What's the problem this feature will solve?
The new 2FA feature adds a TOTP second factor to the authentication proces. This can be problematic when you lose access to the device you use for the 2FA authentication (e.g. the phone running the TOTP app).
Describe the solution you'd like
Most TOTP using sites I've used have an option of recovery codes that can be used to log in with a recovery code when you've lost access to the TOTP device.
Additional context
https://github.com/pypa/warehouse/issues/5758 ("Define manual account recovery process") is related.
Per conversation in IRC today -- recovery codes, while a useful feature, are not in-scope for the deliverables we promised in our grant-funded work from the Open Technology Fund (more details). So right now we'll continue with the current workflow, where it falls on PyPI site admins to perform the recovery process on behalf of users, and if we have time in this grant, we'll prioritize doing this, but otherwise we will work on it on a volunteer basis afterward.
To follow up on @nurupo's question in #996:
All 2FA implementations I have seen have a backup method you can use if you lose your TOTP/U2F device. Often times they provide backup codes. Sometimes it's TOTP with SMS as backup, or U2F with TOTP as backup. But I think I have yet to see a 2FA without a backup method.
If a user has both TOTP and WebAuthn enabled but has lost access to one or the other, they'll still be able to use the one they still have access to. That's not a backup scheme per se since we impose no ordering between TOTP and WebAuthn, but it's something we'll support.
Re: SMS and recovery codes: like @brainwane said these are not in scope for the OTF work, but it's my professional opinion that SMS should not be either a second-factor or recovery option in any greenfield 2FA implementation. Recovery codes are a great idea and IIRC are on the PyPI roadmap, but (again IMO) should not be mandatory, as they circumvent the two factor scheme entirely. Users who don't enable recovery codes will then be at the mercy of the recovery process determined by the site admins.
An issue with using both TOTP and WebAuthn is that if you use a single device for both, e.g. a Yubikey can do both TOTP and WebAuthn, and lose it, then you won't have access to both of those. Of course the obvious solution would be "don't store them on the same device". Or you could treat TOTP secret as a backup code and write it somewhere down as you would with backup codes. So I guess either way it somehow works out in the end, so I'm fine with just TOTP and WebAuthn. Having recovery codes would be a huge improvement though.
it's my professional opinion that SMS should not be either a second-factor or recovery option in any greenfield 2FA implementation.
Of course, please do not use SMS, it's considered insecure as it's subject to being intercepted and you can social engineer phone companies to assign you target's phone number, not to mention it would cost money to send messages to users. I mentioned SMS purely as an example of what I have seen in the wild, not necessarily as a model that should be followed.
as they circumvent the two factor scheme entirely.
Not sure how a website giving a user recovery codes "circumvents the two factor scheme entirely" any more than a website giving a user a TOTP secret. Both are shared secrets known to the website. Both can be written down. Both can be used for 2FA.
Users who don't enable recovery codes will then be at the mercy of the recovery process determined by the site admins.
I'm not following, what does this have to do with recovery codes? You could apply this to any 2FA method. For example, users who enable just WebAuthn but lose their key "will then be at the mercy of the recovery process determined by the site admins."
Anyway, thanks for letting know, I'm glad that recovery codes are on the PyPI road-map, even if not as part of the OTF work.
Not sure how a website giving a user recovery codes "circumvents the two factor scheme entirely" any more than a website giving a user a TOTP secret. Both are shared secrets known to the website. Both can be written down. Both can be used for 2FA.
Yeah, this is admittedly a hazy distinction. TOTP preserves the second factor property by requiring a transform on the secret + windowed timestamp that the user (probably) can't do in their head and thus turn into something they know, but a user could always save their TOTP secret somewhere that isn't sequestered and violate the scheme in that way.
OTOH, recovery codes are (usually) trivial for users to memorize. They probably won't memorize them so maybe that's a moot distinction, but it's common enough to see people save their codes on disk instead of printing them out, stash them in their password managers, &c. Combined with the absence of a transform that humans can't easily perform, I'd say this compromises their ability to be a "real" second factor. Admittedly nitpicky.
I'm not following, what does this have to do with recovery codes? You could apply this to any 2FA method. For example, users who enable just WebAuthn but lose their key "will then be at the mercy of the recovery process determined by the site admins."
Ah, sorry. Implicit in that is the assumption that account recovery requests won't be honored if the account in question has 2FA enabled and the user can't prove that they possess the second factor. But I don't know if that's actually been settled on yet.
Note: we already have draft help text for this feature. I've copied this from https://github.com/pypa/warehouse/issues/5586
When setting up two factor authentication on your account, you were provided with the option to add a set of 8 recovery codes, and instructed to keep these in a safe place.
These codes are usually a string of numbers, letters or words that act as a one time password. If you are unable to login to PyPI using your normal second factor, you can use one of these codes to bypass the 2FA process. Once you have used a recovery code, you cannot use it again.
It is important that you store these codes securely by either printing or writing down the codes - we strongly recommend that you do not store them in a password manager, or on any device.
If you lose your recovery codes, and cannot authenticate with one of your 2FA methods, you will be locked out of your PyPI account. The PyPI team can manually grant you access to your account under limited circumstances.
TODO:
These codes are usually a string of numbers, letters or words to reflect the actual structure of the recovery codes we implementThe PyPI team can manually grant you access to your account under limited circumstances. Mockups for this feature can be found here: https://github.com/pypa/warehouse/issues/5587
TLDR:
Guys, I currently can't log in to my PyPI account because for some reason, my TOTP codes aren't being accepted. If I had recovery codes, I'd be good, but I'm currently locked out of my account. I maintain a popular open-source project so this is kind of a problem. Besides implementing recovery codes, can anyone help me regain control of my account?
@cool-RR do you have an update on this?
Ernest fixed the problem with my account.
@ewdurbin @cool-RR do I have to contact someone regarding this??
@pidugusundeep please open an issue to track your recovery request.
I've noticed the 2FA reset requests starting to pile up, showcasing first that users are happy with our current TOTP which is amazing, but also that our manual recovery approach is not sustainable as it increases the burden on admins and creates quite a bit of frustration for users.
I think we need to start defining the work necessary for this issue to be completed.
The conversation in https://github.com/pypa/warehouse/issues/5586 is a good starting point, maybe we could refine the specifics of:
cc @ewdurbin @di @brainwane @woodruffw @nlhkabu
To copy some of the details from a conversation with @ewdurbin + some old notes:
It should be hard and/or impossible for users to confuse their recovery codes with their TOTP tokens (this is less of a problem with a technical base like PyPI, but still happens). This can be accomplished by making the latter longer than the former, and/or using a different alphabet (alphanum instead of just numeric), and/or having an explicit separator (e.g. XXXX-XXXX).
IMO, it makes sense to make recovery code provisioning an explicit part of all 2FA (i.e., both TOTP and WebAuthn) flows: after provisioning their first 2FA method, users are unconditionally redirected to a page where recovery codes have been generated.
Standard practices apply: the codes should be selectable, should have print and save actions, and should come with a strong warning not to treat them as a 2FA bypass and protect them appropriately. Industry practice currently (mostly) splits between suggesting that the codes be printed out and stored somewhere or saved in a password manager; recommending either or both is fine IMO.
Depending on how mandatory you'd like recovery codes to be, you can ask users to use one to complete the 2FA + recovery provisioning process.
The flow when using a recovery code should be identical to the 2FA flow, since recovery codes behave as just a 2FA bypass: users should still be required to enter their password. It'd be appropriate to record additional UserEvents for the consumption of recovery tokens.
(I imagine the support headache will increase further now that we've publicized 2FA more widely (announcement email, blog post).)
Implementation in progress in #7260
Thank you @ewdurbin!
Most helpful comment
Implementation in progress in #7260