WebAuthn specifies an API for creating and using public key credentials. Credentials belong to a user and are managed by an authenticator. The process of creating credentials is called attestation. Through Attestation the device can be verified as authentic using trust chains. A successful attestation proves that the device the user has authenticated with is authentic and hasn't been tampered with. From a high level end users perspective, you can think of attestation as a kin to registration.
Registration
On user action, such as a button click (browsers may block automatic attestation), the Relying Party can request the client to create a new credential, this is done via interaction with the WebAuthn API by calling the navigator.credentials.create() method. There are a few different credential options objects we can pass into the function.
- PublicKeyCredential
- PasswordCredential
- FederatedCredential
- IdentityCredential
- OTPCredential
For FIDO however the only credential type required is PublicKeyCredential.
With the FIDO component the FidoAuthentication service can be injected into the controller and the InitiateRegistration called before the page load to supply some of the fields required in the options.
Public Key Credential Options
-
Attestation :
stringOptionalIntended for use by Relying Parties that wish to express their preference for attestation conveyance. Attestation value can either bedirect,indirectornone. If no value is provided it will default tonone.directattestation means the RelyingParty wants to receive the attestation statement as generated by the authenticator.directis the recommended value.indirectattestation indicates that the RelyingParty prefers a verifiable attestation statement but allows the client to device how to obtain it.noneThis means that the relying party is not interested in authenticator attestation.
-
AuthenticatorSelection :
objectOptionalAuthenticator requirements object.- AuthenticatorAttachment :
stringplatformindicates a platform authenticator such as WindowsHello or Apple TouchId/FaceId.cross-platformindicates a roaming authenticator such as a security key.
- RequireResidentKey :
boolWhentruethe authenticator must create a discoverable credential (residence key) for username-less authentication. Not all keys support residence keys. - UserVerification :
stringThe user verification value can be set aspreferred,requiredordiscouraged. If no value is supplied it will default topreferred.discouragedmeans the RelyingParty does not want user verification during the operation, this could be to minimize disruption to the user flow.preferredmeans that the RelyingParty prefers user verification if possible but will not fail the if the response does have the AuthenticatorDataFlags.UV set.requiredmeans the operation will fail if the response does have the AuthenticatorDataFlags.UV set. The operation will fail if the key does not support user verification and may fail depending on the browser if no PIN or biometric has been configured
- AuthenticatorAttachment :
-
Challenge :
Uint8ArrayA randomly generated value generated by the RelyingParty. In the FIDO2 component the challenge value is generated when callingFidoAuthenticationInitiateRegistrationmethod. -
ExcludeCredentials :
ArrayLimits creation of multiple credentials for the same account on a single authenticator. If the authenticator finds an existing credential type and id for the RP, then a new credential will not be created. TheFidoAuthenticationInitiateRegistrationwill supply this a list of all credential ids for the user you can use for this option. -
PubKeyCredParams Specifies which cryptographic algorithms the RelyingParty supports. The FIDO2 component supports the following algorithms
EdDSA(Ed25519)ES256ES256KES384ES512PS256PS384PS512RS1RS256RS384RS512
-
rp :
objectRelying party information.idThe id attribute must equal the domain of the origin seen by the client, or the origin must be a subdomain of the id. If id is omitted, then origins effective domain is used.nameDisplay name, required.
-
timeout :
intThe time, in milliseconds, that the caller is willing to wait for the call to complete. -
user :
objectInformation about the user account.idThe id attribute is the user handle that is generated by the RP and used to uniquely identify a user. Unlike name, id is not meant to be human-readable and should not contain personally identifying information such as an e-mail address
TheFidoAuthenticationInitiateAuthenticationmethod will generate a user handle to be used here.name:stringUsernamedisplayName:stringUser-friendly Display name.
Complete Registration
Once WebAuthn has completed its authentication, the authentication data needs to be passed to the FIDO component to perform attestation and validation. The encoded credentials can be turned into JSON and posted to RegisterCallback endpoint via a javascript promise.
navigator.credentials.create({ publicKey }).then((credentials) => {
var encodedCredentials = {
id: credentials.id,
rawId: btoa(String.fromCharCode.apply(null, new Uint8Array(credentials.rawId))),
type: credentials.type,
response: {
attestationObject:
btoa(String.fromCharCode.apply(null, new Uint8Array(credentials.response.attestationObject))),
clientDataJSON:
btoa(String.fromCharCode.apply(null, new Uint8Array(credentials.response.clientDataJSON)))
}
};
$.ajax({
url: '/Home/RegisterCallback',
type: 'POST',
contentType: 'application/json',
data: JSON.stringify(encodedCredentials),
success:function() {
window.location.href = "/";
}
});
});
The FIDO component contains types to model FIDO payloads. To receive the encoded credential object from the browser use Base64FidoRegistrationResponse. (See code fragment below)
[HttpPost]
public async Task<IActionResult> RegisterCallback([FromBody] Base64FidoRegistrationResponse registrationResponse)
{
IFidoRegistrationResult result = await fido.CompleteRegistration(registrationResponse.ToFidoResponse());
if (result.IsError) return BadRequest(result.ErrorDescription);
return Ok();
}
The FidoAuthentication.CompleteRegistration method requires a IFidoRegistrationResponse, the ToFidoResponse extension method generates a IFidoRegistrationResponse from the Base64FidoRegistrationResponse.