Web Authentication API

The W3C Web Authentication API specification is the authority for implementing WebAuthn. This guide will rely on the content of that specification for building WebAuthn user authentication experiences.

WebAuthn specifies an API for creating and using public key credentials. Credentials belong to a user and are managed by an authenticator, with which the RP interacts through the client.

WebAuthn Client Registration

With the user’s consent, the RP can request the client to create a new credential. In the browser, this is achieved by calling the navigator.credentials.create() method. It takes in PublicKeyCredentialCreationOptions as the argument and returns a PublicKeyCredential. The RP validates the PublicKeyCredential before adding the credential to the user’s account.

webauthn-registration-flow-01.svg?sanitize=true

Registration Flow

Step 0: The client initiates a request to register an authenticator on behalf of the user. It is a best practice to collect the authenticator nickname. When multiple authenticators are registered, nicknames make them more recognizable to users.

Step 1: The RP builds an instance of the PublicKeyCredentialCreationOptions and returns it to the client. The instance contains information about the user, the RP and the type of credential desired.

Example

Parsed PublicKeyCredentialCreationOptions

Note: In the WebAuthn API, all binary parameters (user.id, challenge etc.) are actually Uint8Arrays and not Base64 strings. This example displays them as Base64 strings for readability

{
  "publicKey": {
    "attestation": "direct",
    "authenticatorSelection": {
      "authenticatorAttachment": "cross-platform",
      "requireResidentKey": false,
      "userVerification": "discouraged"
    },
    "challenge": "qNqrdXUrk5S7dCM1MAYH3qSVDXznb-6prQoGqiACR10=",
    "excludeCredentials": [],
    "pubKeyCredParams": [
      {
        "alg": -7,
        "type": "public-key"
      }
    ],
    "rp": {
      "id": "demo.yubico.com",
      "name": "Yubico Demo"
    },
    "timeout": 30000,
    "user": {
      "displayName": "Yubico demo user",
      "id": "bz9ZDfHzOBLycqISTAdWwWIZt8VO-6mT3hBNXS5jwmY="
    }
  }
}

attestation: The default value is “none” which means the RP is not interested in authenticator attestation. “indirect” indicates the RP prefers a verifiable attestation statement but allows the client to decide how to obtain it. “direct” indicates the RP wants to receive the attestation statement. It is recommended that RPs use the “direct” value and store the attestation statement with the credential so they can inspect authenticator models retroactively if policy changes.

authenticatorSelection: specify authenticator requirements. The optional authenticatorAttachment attribute filters eligible authenticator by type. The value “platform” indicates a platform authenticator, such as Windows Hello. The value "cross-platform" value indicates a roaming authenticator, such as a security key. When the requireResidentKey attribute is true, the authenticator must create a client side resident private key (a.k.a. resident credential). The userVerification attribute can be set to a value of “preferred”, “required”, or “discouraged”.

challenge: In order to prevent replay attacks, the value should be randomly generated by the RP.

excludeCredentials: limits 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.

pubKeyCredParams: Specifies which cryptographic algorithms the RP supports. type: only one type: “public-key”. alg: cryptographic signature algorithm preference specified by COSE Algorithms registry. If you use a library to validate authenticator responses, pubKeyCredParams is probably determined by what the library suppports.

rp: relying party information. name is required. The 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.

timeout: the time, in milliseconds, that the caller is willing to wait for the call to complete.

user: contains data about the user account. The displayName provides a user-friendly name which may be displayed to the user. The name attribute takes a traditional username or the like, to disambiguate accounts with similar displayNames. The 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.

Step 2: The JavaScript client calls navigator.credentials.create(). The browser validates the rp.id against the origin, hashes the clientData, and calls authenticatorMakeCredential method.

Note: Even with the same parameter object, navigator.credentials.create() will create a new credential every time it is called. Use the exclude list to prevent registering the same authenticator twice. See excludeCredentials above.

Step 3: Before proceeding, the authenticator will ask for some form of user consent. After verifying consent, the authenticator will create a new asymmetric key pair and safely store the private key. The public key becomes part of the attestation, which the authenticator signs over with the attestation private key. The manufacturer’s attestation certificate chain may also be returned so that the relying party can validate the device back to a root of trust.

Step 4: The new public key, a credential id, and other attestation data are returned to the browser where they become the attestationObject.

Step 5: The navigator.credentials.create() promise resolves to a PublicKeyCredential which is returned to the RP to finalize the registration.

Example

Parsed PublicKeyCredential

Note: In the WebAuthn API, all binary parameters (attestationObject and clientDataJSON) are actually an ArrayBuffer and not Base64 strings. This example displays them as Base64 strings for readability.

{
  "id": "X9FrwMfmzj...",
  "response": {
    "attestationObject": "o2NmbXRoZmlk...",
    "clientDataJSON": "eyJjaGFsbGVuZ..."
  },
  "clientExtensionResults": {}
}

id: The credential identifier.

response: contains the credential public key, and metadata which can be used by the RP to assess the characteristics of the credential. The attestationObject contains the authenticator data and attestation statement. The clientDataJSON contains the JSON-serialized data passed to the authenticator by the client in order to generate the credential.

clientExtensionResults(): method returns values for zero or more WebAuthn extensions.

Example

Parsed attestationObject

Note: In the WebAuthn API, the attestationObject is actually an ArrayBuffer. This example displays it in Base64 for readability

{
    "attStmt": {
      "alg": -7,
      "sig": "MEUCIQD1...",
      "x5c": [
        "MIICvDCCA..."
      ]
    },
    "authData": {
      "credentialData": {
        "aaguid": "-iuZ3J45QlePkkow0jxBGA==",
        "credentialId": "X9FrwMfmzj...",
        "publicKey": {
          "1": 2,
          "3": -7,
          "-1": 1,
          "-2": "ZsGUIeG53MifPb72qqnmC-X-0PLO-bZiNNow3LUHUYo=",
          "-3": "kuBFf3ZcUc-LAFTPIB8e5DaDt2ofJQ3wAB16zHqNUX0="
        }
      },
      "flags": {
        "AT": true,
        "ED": false,
        "UP": true,
        "UV": false
      },
      "rpIdHash": "xGzvgq0bVGR3WR0Aiwh1nsPm0uy085R0v-ppaZJdA7c=",
      "signatureCounter": 7
    },
    "fmt": "packed"
}

attStmt: The attestation statement is a signed data object containing statements about the public key credential itself and the authenticator that created it. This example uses the “packed” attestation statement format. The alg field contains the COSE Algorithm identifier. The sig field contains the attestation signature. The x5c field contains the attestation certificate and its certificate chain. Use the certificate chain to verify the device is genuine.

authData: The authenticator data is a byte array containing data about the make credential operation, including the credential ID and public key.

credentialData: the credential data attested by the authenticator.

aaguid: An identifier chosen by the authenticator manufacturer, indicating the make and model of the authenticator.

_Note: Not all authenticators support this, and no U2F authenticators do. Those that do not set the aaguid to 16 zero bytes.

credentialId: The credential identifier generated by the authenticator

publicKey: The credential public key encoded in COSE_Key format. The example is a COSE_Key Elliptic Curve public key in EC2 format.
1: is the key type. A value of 2 is the EC2 type
3: is the signature algorithm. A value of -7 is the ES256 signature algorithm
-1: is the curve type. A value of 1 is the P-256 curve
-2: is the x-coordinate as byte string
-3: is the y-coordinate as byte string




flags: The AT indicates whether the authenticator added attested credential data, and is always 1 for registrations. The ED flag indicates if the authenticator data has extensions. The UP flag indicates if the user is present. The UV flag indicates if the user is verified (PIN or biometric).

rpIdHash: a SHA-256 hash of the RP ID to which the credential is scoped.

signatureCounter: is incremented for each successful authenticatorGetAssertion operation. It is used by RPs to aid in detecting cloned authenticators.

fmt: The attestation statement format identifier. The format could be one of the defined attestation formats detailed in the W3C WebAuthn specification, e.g., packed, fido-u2f format, etc…

Example

Parsed clientDataJSON

Note: In the WebAuthn API, the clientDataJSON is actually an ArrayBuffer. This example displays it in Base64 for readability

{
  "challenge": "qNqrdXUrk5S7dCM1MAYH3qSVDXznb-6prQoGqiACR10",
  "origin": "https://demo.yubico.com",
  "type": "webauthn.create"
}

The clientDataJSON object contains the challenge sent by the RP, the origin of the domain observed by the client, and the type of operation performed.

Step 6: The RP performs a series of checks to ensure the registration ceremony was not tampered with, including:

  • Verifying the signature over the clientDataHash and the attestation using the certificate chain in the attestation statement

  • Optionally: verifying that the certificate chain is signed by a trusted certificate authority of the RP’s choice.

The full list of validation steps can be found in the WebAuthn specification.