Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Example on how to handle recovery codes? #59

Open
binhnguyenduc opened this issue Jan 3, 2021 · 4 comments
Open

Example on how to handle recovery codes? #59

binhnguyenduc opened this issue Jan 3, 2021 · 4 comments

Comments

@binhnguyenduc
Copy link

Forgive me if this is a stupid question, how exactly can I handle recovery codes for users?

In README, you said "These can simply be randomly generated strings that you store in your backend" but I could not find the code that do this.

Does that mean I need to handle recovery codes myself? I was thinking along the lines of

  1. Generate recovery codes in backend
  2. Give users recovery codes
  3. Compare passcode with recovery codes (pulled from backend storage). If not matched, then compare passcode with TOTP / HOTP as usual? If matched, remove recovery codes (one time use like Github)

Let me know if you have plan to support this behavior natively in this package, or if you are interested in a Pull Request that does this (backend storage via an interface, of course)?

@pquerna
Copy link
Owner

pquerna commented Jan 5, 2021

i'd be ok with a sub-module for recovery codes.

i'm a little concerned about scope creep - as you allude to, recovery codes inherently need storage. Additionally, you probally want to either hash or encrypt them - ideally they aren't stored in clear text.

Just sketching out how this could work, to avoid storing recovery codes in clear text:

  1. Generate Function with Options (length, number of codes), returns array of strings
  2. Transform function takes varargs strings input, applies a sha256() and returns an array of strings

To validate:

  1. Get recovery code from user - most UX have this as an explicit option, eg, "Can't find your phone, enter a recovery code here", and not implicitly based on overloading the input box.
  2. Call Transform() with user input, this would return the hashed version.
  3. Lookup in your backend for a given user_id, does the transformed string exist in a set of backup codes, if it does, delete the used one, and continue the login flow.

I'm not sure step 3 having an interface is a big help - its going to be very app specific so I'm wondering if we should instead focus on easy to use composable functions with a few examples, what do you think?

@dkotik
Copy link

dkotik commented Jun 21, 2021

@pquerna Is this issue stale? I was writing a recovery code module for myself the other day using 4-letter English words to encode a binary code. Argon2di for hashing. I could contrib it here. Interested?

@drakkan
Copy link

drakkan commented Aug 22, 2021

Hi,

I don't think storing a hash for recovery codes is a good idea for all use cases. For example GitHub allows you to view the plain recovery codes at any time and this is not possible if you hash the recovery codes.

I'm adding TOTP support to SFTPGo and I'm using a struct like the following one to keep recovery codes

// RecoveryCode defines a 2FA recovery code
type RecoveryCode struct {
	Secret *kms.Secret `json:"secret"`
	Used   bool        `json:"used,omitempty"`
}

kms.Secret is an encrypted secret that can be stored within external KMS such as Vault, GCP KMS, AWS KMS and so on. This way the recovery code is stored encrypted and can be decrypted at any time so I can show the plain text recovery codes to the users at any time as GitHub. I can also show the used recovery codes.

This feature is very application specific and I think it is out of the scope of the library

@pquerna
Copy link
Owner

pquerna commented Dec 14, 2022

@dkotik a sub-module for recovery code generation seems helpful. If it pulls in other deps, might drop it in a new go.mod scope, but would welcome a PR with it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants