This extension allows for recovery credentials to be registered with an RP,
which can be used for account recovery in the case of a lost/destroyed main
authenticator. This is done by associating one or more backup authenticators
with the main authenticator, the latter of which is then able to provide
additional credentials for account recovery to the RP without involving the
backup authenticators. The mechanism of setting this up is outside of the scope
of this extension, however a state
counter is defined as follows:
Let state
be initialized to 0. Performing a device reset re-initializes
state
to 0. When the set of registered backup authenticators for the device
changes (eg. on adding/removing a backup authenticator, including adding the
first backup authenticator) state
is incremented by one.
The state
counter is stored by the main authenticator, and allows the RP to
automatically detect when the set of registered recovery credentials needs to be
updated.
NOTE: The choice to make registration of recovery credentials explicit is deliberate, in an attempt to ensure that the user deliberately intends to do so and understands the implications.
recovery
Registration and Authentication
partial dictionary AuthenticationExtensionsClientInputs {
RecoveryExtensionInput recovery;
}
dictionary RecoveryExtensionInput {
required RecoveryExtensionAction action;
sequence<PublicKeyCredentialDescriptor> allowCredentials;
}
enum RecoveryExtensionAction {
"state",
"generate",
"recover"
}
The values of action
have the following meanings. X
indicates that the value
is applicable for the given WebAuthn operation:
Value | create() | get() | Description |
---|---|---|---|
state | X | X | Get the state counter value from the main authenticator. |
generate | X | Regenerate recovery credentials from the main authenticator. | |
recover | X | Get a recovery signature from a backup authenticator, to replace the main credential with a new one. |
None required, except creating the authenticator extension input from the client extension input.
If the client implements support for this extension, then when action
is
"generate"
, the client SHOULD notify the user of the number of recovery
credentials in the response.
None.
The client extension input encoded as a CBOR map.
If action
is
-
"state"
,set the extension output to the CBOR encoding of
{"action": "state", "state": <state counter>}
. -
"generate"
,generate one recovery credential for each associated backup authenticator, formatting these as a CBOR array of attested credential data byte arrays. Set the extension output to the CBOR encoding of
{"action": "generate", "state": <state counter>, "creds": <list of recovery credentials>}
. -
"recover"
,locate a usable recovery credential from the credential IDs in
allowCredentials
in the extension input.-
If no usable credential is found, do not include the extension in the output.
-
If a usable credential is found,
-
Let
cred
be the found credential. -
Let
authenticatorDataWithoutExtensions
be the authenticator data that will be returned from this registration operation, but without theextensions
part. TheED
flag inauthenticatorDataWithoutExtensions
MUST be set even thoughauthenticatorDataWithoutExtensions
does not include extension data. -
Let
sig
be a signature overauthenticatorDataWithoutExtensions || clientDataHash
usingcred
. -
Set the extension output to the CBOR encoding of
{"action": "recover", "credId": <credential ID of cred>, "sig": <sig>, "state": <state counter>}
.
-
-
A CBOR map with contents as defined above.
dictionary RecoveryExtensionOutput {
required RecoveryExtensionAction action;
required int state;
sequence<ArrayBuffer> creds;
ArrayBuffer credId;
ArrayBuffer sig;
}
-
The RP MUST be very explicit in notifying the user when recovery credentials are registered, and how many, to avoid any credentials being registed without the user's knowledge. If possible, the client SHOULD also display the number of backup authenticators associated with the main authenticator.
-
The RP SHOULD clearly display information about registered recovery credentials, just as it does with standard credentials.
-
The same security considerations apply to recovery credentials as to standard credentials.
-
Although recovery credentials are issued by the main authenticator, they can only ever be used by the backup authenticator.
-
Recovery credentials are scoped to a specific RP ID, and the RP SHOULD also associate them with a specific main credential.
-
Recovery credentials can only be used in registration ceremonies where the recovery extension is present, with
action == "recover"
. -
A main authenticator should ensure that the recovery credentials it issues on behalf of a backup authenticator are authentic.
An RP supporting this extension SHOULD include the extension the action = "state"
value whenever performing standard registration or authentication
ceremony. There are two cases where the response indicates that the RP should
initiate recovery credential registration (action "generate"
), which are:
- Upon successful
create()
, ifstate
> 0. - Upon successful
get()
, ifstate
>old_state
, whereold_state
is the previous value forstate
that the RP has seen for the used credential.
To initiate recovery credential registration, the RP performs a get()
operation with action = "generate"
. Upon a successful response, the returned
list of recovery credentials is stored, associated with the main credential.
Any prior recovery credentials for that main credential are replaced.
If the user initiates device recovery, the RP performs the following procedure:
-
Ask the user which credential to recover. Let
mainCred
be the chosen credential. -
Let
allowCredentials
be a list of the credential descriptors of the recovery credentials associated withmainCred
. IfallowCredentials
is empty, abort this procedure with an error. -
Initiate a
create()
operation with the extension input:"recovery": { "action": "recover", "allowCredentials": <allowCredentials as computed above> }
-
Wait for the response from the client. If the operation fails, abort this procedure with an error.
-
Let
publicKey
be the public key for the recovery credential identified by the credential IDcredId
in the extension output. -
Let
authenticatorDataWithoutExtensions
be the authenticator data in the PublicKeyCredential response, but without the extensions part. TheED
flag inauthenticatorDataWithoutExtensions
MUST be set even thoughauthenticatorDataWithoutExtensions
does not include the extension outputs. -
Using
publicKey
, verify thatsig
in the extension output is a valid signature overauthenticatorDataWithoutExtensions || clientDataHash
. -
Finish the registration ceremony as usual. This means a new credential has now been registered using the backup authenticator.
-
Revoke
mainCred
and all recovery credentials associated with it. -
If
state
in the extension output is greater than 0, the RP SHOULD initiate recovery credential registration (action = "generate"
) for the newly registered credential.
As an alternative to proceeding to register a new credential for the backup authenticato, the RP MAY choose to not replace the lost credential with the new one, and instead disable 2FA or provide some other means for the user to access their account. In either case, the associated main credential SHOULD be revoked and no longer usable.