KEYCLOAK-6270 Support for Backup Codes for 2FA Recovery

787 views
Skip to first unread message

Thomas Darimont

unread,
May 20, 2021, 7:34:44 AM5/20/21
to Keycloak Dev
Dear Keycloak Developers,

In a customer project, I need support to recover lost 2nd-factors. Recovery of 2nd-factors 
is usually made via backup codes that one can register after a 2nd-factor creation.

The "multi-factor-admin-and-step-up" design document [2] mentions backup codes but does not 
describe how they should work in detail. I could also find KEYCLOAK-6270 "Two factor authentication 
with backup codes" [3] and related issues, but they were stale or closed due to lack of time/priority.

# PoC
Since I need something now, I created a small PoC [1] that allows users to register backup codes from 
the account-console on the Account-Security page. The example contains a few gifs and images that demonstrate the flow.

The example consists of the following main components:

- CredentialProvider: Adds support for storing and validating Backup Codes
- RequiredAction: User Initiated Action (UIA) that allows to generate and download Backup Codes
- Authenticator: Validates a given backup code as an alternative 2nd factor

# How it works
Backup codes are currently handled like passwords and stored in the credentials table. In the PoC, 
I generate some codes and encode them like passwords (PBKDF2, but with fewer iterations to spare CPU). 
Note that previous backup codes are removed when generating new backup codes.

A user can generate and download backup codes with a user initiated action. 
A user can then use a backup code to log in via the "try another way" link and click on "Authenticate with Backup Code", 
which shows the "Enter Backup Code" form provided by the Authenticator.

If the user enters a correct backup code, then the code is removed from the credentials table. 
An incorrect code yields the message "username or password not found" for now.

The remaining backup codes are visible in the account-console on the Account-Security page. Instead of showing a 
list of backup codes in the UI, it would be better just to show that backup codes are present.

I wonder whether the PoC can be turned into a built-in Keycloak feature, as the building blocks are mostly there.

Cheers,
Thomas

Thomas Darimont

unread,
Jun 14, 2021, 6:43:54 AM6/14/21
to Keycloak Dev
Quick update:

I refactored the backup-codes extension [1] quite a bit to ease extensibility and I think it is now in a state that might be considered for a PR.
I assume that we need a small specification for this, which at least brings together the essential requirements to be able to check the present implementation against it.
Have you already thought about backup support or maybe already implemented it?

I would be glad to hear your thoughts :)

Some additional questions:

Q1 Backup Code Encoding
I currently encode backup codes similar to passwords with pbkdf2-sha256 with 1000 iterations to save some CPU since we generate ten codes at once and store the backup codes in the credentials table. Is my approach for storing backup codes sound?

Q1.1 Handle "Used" Backup Codes
I currently "burn" a used backup code by deleting it from the credentials table. Is this okay, or should I rather keep it and mark it as "used"?

Q1.2 Backup Codes are only Displayed once
The user can only see the generated backup codes when they are generated. After that, there is no way for Keycloak to present the raw backup codes again.
Does this make sense to you?

Q2 Backup Codes as a Recovery Mechanism vs. independent 2nd Factor?
Should backup codes work as a general second-factor on their own, or should they only be considered if at least one alternative 2FA is configured?

Q3 How to configure Backup Codes details?
How should an admin be able to configure (backup-code length, number of codes, hash mechanism, hash iterations)? The backup code configuration should probably be realms-specific. Should I use realm attributes or password policies (which makes sense as a config container) for this?

Q3.1 Backup Codes Config via (more flexible) Password Policies?
If I use password policies, I need to ensure that they are only applied to backup codes and not regular passwords. 
Perhaps we need to add a `default boolean supports(String credentialType) { return PasswordCredentialModel.TYPE; }` to 
the PasswordPolicyProvider interface, which allows extensions to control the credential type to apply the policy.

Q4 Backup Codes and User Events
On backup code generation, I want to send an event. Currently, I use the UPDATE_PASSWORD event with some additional detail metadata. 
Does it make sense to have a new event type like EventType.UPDATE_BACKUP_CODE or something generic like EventType.UPDATE_SECOND_FACTOR?

Q5 Backup Code Display in Account-Console
I currently generate ten backup codes at once, which are then displayed in the account console as a rather clunky long list.
Would it make sense to have support to use a collapsible list here that by default only shows that the user has backup codes registered?
E.g., something like the HTML details element would work here: [2]

Cheers,
Thomas

Reply all
Reply to author
Forward
0 new messages