Web Authentication API
Secure context: This feature is available only in secure contexts (HTTPS), in some or all supporting browsers.
The Web Authentication API is an extension of the Credential Management API that enables strong authentication with public key cryptography, enabling passwordless authentication and/or secure second-factor authentication without SMS texts.
Web authentication concepts and usage
The Web Authentication API (also referred to as WebAuthn) uses asymmetric (public-key) cryptography instead of passwords or SMS texts for registering, authenticating, and second-factor authentication with websites. This has some benefits:
- Protection against phishing: An attacker who creates a fake login website can't login as the user because the signature changes with the origin of the website.
- Reduced impact of data breaches: Developers don't need to hash the public key, and if an attacker gets access to the public key used to verify the authentication, it can't authenticate because it needs the private key.
- Invulnerable to password attacks: Some users might reuse passwords, and an attacker may obtain the user's password for another website (e.g. via a data breach). Also, text passwords are much easier to brute-force than a digital signature.
Many websites already have pages that allow users to register new accounts or sign in to an existing account, and the Web Authentication API acts as a replacement or supplement to those on those existing webpages. Similar to the other forms of the Credential Management API, the Web Authentication API has two basic methods that correspond to register and login:
-
navigator.credentials.create()
- when used with the publicKey option, creates new credentials, either for registering a new account or for associating a new asymmetric key pair credentials with an existing account. -
navigator.credentials.get()
- when used with the publicKey option, uses an existing set of credentials to authenticate to a service, either logging a user in or as a form of second-factor authentication.
Note: Both create()
and get()
require a secure context (i.e. the server is connected by HTTPS or is the localhost), and will not be available for use if the browser is not operating in a secure context.
In their most basic forms, both create()
and get()
receive a very large random number called the "challenge" from the server and they return the challenge signed by the private key back to the server. This proves to the server that a user is in possession of the private key required for authentication without revealing any secrets over the network.
In order to understand how the create() and get() methods fit into the bigger picture, it is important to understand that they sit between two components that are outside the browser:
- Server - the Web Authentication API is intended to register new credentials on a server (also referred to as a service or a relying party) and later use those same credentials on that same server to authenticate a user.
- Authenticator - the credentials are created and stored in a device called an authenticator. This is a new concept in authentication: when authenticating using passwords, the password is stored in a user's brain and no other device is needed; when authenticating using web authentication, the password is replaced with a key pair that is stored in an authenticator. The authenticator may be embedded into the user agent, into an operating system, such as Windows Hello, or it may be a physical token, such as a USB or Bluetooth Security Key.
Registration
A typical registration process has six steps, as illustrated in Figure 1 and described further below. This is a simplification of the data required for the registration process that is only intended to provide an overview. The full set of required fields, optional fields, and their meanings for creating a registration request can be found in the PublicKeyCredentialCreationOptions
dictionary. Likewise, the full set of response fields can be found in the PublicKeyCredential
interface (where PublicKeyCredential.response
is the AuthenticatorAttestationResponse
interface). Note most JavaScript programmers that are creating an application will only really care about steps 1 and 5 where the create() function is called and subsequently returns; however, steps 2, 3, and 4 are essential to understanding the processing that takes place in the browser and authenticator and what the resulting data means.
Figure 1 - a diagram showing the sequence of actions for a web authentication registration and the essential data associated with each action.
First (labeled step 0 in the diagram), the application makes the initial registration request. The protocol and format of this request are outside the scope of the Web Authentication API.
After this, the registration steps are:
-
Server Sends Challenge, User Info, and Relying Party Info - The server sends a challenge, user information, and relying party information to the JavaScript program. The protocol for communicating with the server is not specified and is outside of the scope of the Web Authentication API. Typically, server communications would be REST over https (probably using XMLHttpRequest or Fetch), but they could also be SOAP, RFC 2549 or nearly any other protocol provided that the protocol is secure. The parameters received from the server will be passed to the create() call, typically with little or no modification and returns a Promise that will resolve to a
PublicKeyCredential
containing anAuthenticatorAttestationResponse
. Note that it is absolutely critical that the challenge be a buffer of random information (at least 16 bytes) and it MUST be generated on the server in order to ensure the security of the registration process. -
Browser Calls authenticatorMakeCredential() on Authenticator - Internally, the browser will validate the parameters and fill in any defaults, which become the
AuthenticatorResponse.clientDataJSON
. One of the most important parameters is the origin, which is recorded as part of the clientData so that the origin can be verified by the server later. The parameters to the create() call are passed to the authenticator, along with a SHA-256 hash of the clientDataJSON (only a hash is sent because the link to the authenticator may be a low-bandwidth NFC or Bluetooth link and the authenticator is just going to sign over the hash to ensure that it isn't tampered with). - Authenticator Creates New Key Pair and Attestation - Before doing anything, the authenticator will typically ask for some form of user verification. This could be entering a PIN, using a fingerprint, doing an iris scan, etc. to prove that the user is present and consenting to the registration. After the user verification, the authenticator will create a new asymmetric key pair and safely store the private key for future reference. The public key will become part of the attestation, which the authenticator will sign over with a private key that was burned into the authenticator during its manufacturing process and that has a certificate chain that can be validated back to a root of trust.
- Authenticator Returns Data to Browser - The new public key, a globally unique credential id, and other attestation data are returned to the browser where they become the attestationObject.
-
Browser Creates Final Data, Application sends response to Server - The create() Promise resolves to an
PublicKeyCredential
, which has aPublicKeyCredential.rawId
that is the globally unique credential id along with a response that is theAuthenticatorAttestationResponse
containing theAuthenticatorResponse.clientDataJSON
andAuthenticatorAttestationResponse.attestationObject
. ThePublicKeyCredential
is sent back to the server using any desired formatting and protocol (note that the ArrayBuffer properties need to be base64 encoded or similar). -
Server Validates and Finalizes Registration - Finally, the server is required to perform a series of checks to ensure that the registration was complete and not tampered with. These include:
- Verifying that the challenge is the same as the challenge that was sent
- Ensuring that the origin was the origin expected
- Validating that the signature over the clientDataHash and the attestation using the certificate chain for that specific model of the authenticator
Authentication
After a user has registered with web authentication, they can subsequently authenticate (a.k.a. - login or sign-in) with the service. The authentication flow looks similar to the registration flow, and the illustration of actions in Figure 2 may be recognizable as being similar to the illustration of registration actions in Figure 1. The primary differences between registration and authentication are that: 1) authentication doesn't require user or relying party information; and 2) authentication creates an assertion using the previously generated key pair for the service rather than creating an attestation with the key pair that was burned into the authenticator during manufacturing. Again, the description of authentication below is a broad overview rather than getting into all the options and features of the Web Authentication API. The specific options for authenticating can be found in the PublicKeyCredentialRequestOptions
dictionary, and the resulting data can be found in the PublicKeyCredential
interface (where PublicKeyCredential.response
is the AuthenticatorAssertionResponse
interface) .
Figure 2 - similar to Figure 1, a diagram showing the sequence of actions for a web authentication and the essential data associated with each action.
First (labeled step 0 in the diagram), the application makes the initial registration request. The protocol and format of this request are outside the scope of the Web Authentication API.
After this, the registration steps are:
- Server Sends Challenge - The server sends a challenge to the JavaScript program. The protocol for communicating with the server is not specified and is outside of the scope of the Web Authentication API. Typically, server communications would be REST over https (probably using XMLHttpRequest or Fetch), but they could also be SOAP, RFC 2549 or nearly any other protocol provided that the protocol is secure. The parameters received from the server will be passed to the get() call, typically with little or no modification. Note that it is absolutely critical that the challenge be a buffer of random information (at least 16 bytes) and it MUST be generated on the server in order to ensure the security of the authentication process.
-
Browser Calls authenticatorGetCredential() on Authenticator - Internally, the browser will validate the parameters and fill in any defaults, which become the
AuthenticatorResponse.clientDataJSON
. One of the most important parameters is the origin, which recorded as part of the clientData so that the origin can be verified by the server later. The parameters to the get() call are passed to the authenticator, along with a SHA-256 hash of the clientDataJSON (only a hash is sent because the link to the authenticator may be a low-bandwidth NFC or Bluetooth link and the authenticator is just going to sign over the hash to ensure that it isn't tampered with). - Authenticator Creates an Assertion - The authenticator finds a credential for this service that matches the Relying Party ID and prompts a user to consent to the authentication. Assuming both of those steps are successful, the authenticator will create a new assertion by signing over the clientDataHash and authenticatorData with the private key generated for this account during the registration call.
- Authenticator Returns Data to Browser - The authenticator returns the authenticatorData and assertion signature back to the browser.
-
Browser Creates Final Data, Application sends response to Server - The browser resolves the Promise to a
PublicKeyCredential
with aPublicKeyCredential.response
that contains theAuthenticatorAssertionResponse
. It is up to the JavaScript application to transmit this data back to the server using any protocol and format of its choice. -
Server Validates and Finalizes Authentication - Upon receiving the result of the authentication request, the server performs validation of the response such as:
- Using the public key that was stored during the registration request to validate the signature by the authenticator.
- Ensuring that the challenge that was signed by the authenticator matches the challenge that was generated by the server.
- Checking that the Relying Party ID is the one expected for this service.
Interfaces
-
Credential
-
Provides information about an entity as a prerequisite to a trust decision.
CredentialsContainer
-
Exposes methods to request credentials and notify the user agent when events such as successful sign in or sign out happen. This interface is accessible from
Navigator.credentials
. The Web Authentication specification adds apublicKey
member to thecreate()
andget()
methods to either create a new public key pair or get an authentication for a key pair, repsectively. PublicKeyCredential
-
Provides information about a public key / private key pair, which is a credential for logging in to a service using an un-phishable and data-breach resistant asymmetric key pair instead of a password.
AuthenticatorResponse
-
The base interface for
AuthenticatorAttestationResponse
andAuthenticatorAssertionResponse
, which provide a cryptographic root of trust for a key pair. Returned byCredentialsContainer.create()
andCredentialsContainer.get()
, respectively, the child interfaces include information from the browser such as the challenge origin. Either may be returned fromPublicKeyCredential.response
. AuthenticatorAttestationResponse
-
Returned by
CredentialsContainer.create()
when aPublicKeyCredential
is passed, and provides a cryptographic root of trust for the new key pair that has been generated. AuthenticatorAssertionResponse
-
Returned by
CredentialsContainer.get()
when aPublicKeyCredential
is passed, and provides proof to a service that it has a key pair and that the authentication request is valid and approved.
Options
PublicKeyCredentialCreationOptions
-
The options passed to
CredentialsContainer.create()
. PublicKeyCredentialRequestOptions
-
The options passed to
CredentialsContainer.get()
.
Examples
Warning: For security reasons, web authentication calls (create()
and get()
) are cancelled if the browser window loses focus while the call is pending.
// sample arguments for registration var createCredentialDefaultArgs = { publicKey: { // Relying Party (a.k.a. - Service): rp: { name: "Acme" }, // User: user: { id: new Uint8Array(16), name: "[email protected]", displayName: "John P. Smith" }, pubKeyCredParams: [{ type: "public-key", alg: -7 }], attestation: "direct", timeout: 60000, challenge: new Uint8Array([ // must be a cryptographically random number sent from a server 0x8C, 0x0A, 0x26, 0xFF, 0x22, 0x91, 0xC1, 0xE9, 0xB9, 0x4E, 0x2E, 0x17, 0x1A, 0x98, 0x6A, 0x73, 0x71, 0x9D, 0x43, 0x48, 0xD5, 0xA7, 0x6A, 0x15, 0x7E, 0x38, 0x94, 0x52, 0x77, 0x97, 0x0F, 0xEF ]).buffer } }; // sample arguments for login var getCredentialDefaultArgs = { publicKey: { timeout: 60000, // allowCredentials: [newCredential] // see below challenge: new Uint8Array([ // must be a cryptographically random number sent from a server 0x79, 0x50, 0x68, 0x71, 0xDA, 0xEE, 0xEE, 0xB9, 0x94, 0xC3, 0xC2, 0x15, 0x67, 0x65, 0x26, 0x22, 0xE3, 0xF3, 0xAB, 0x3B, 0x78, 0x2E, 0xD5, 0x6F, 0x81, 0x26, 0xE2, 0xA6, 0x01, 0x7D, 0x74, 0x50 ]).buffer }, }; // register / create a new credential navigator.credentials.create(createCredentialDefaultArgs) .then((cred) => { console.log("NEW CREDENTIAL", cred); // normally the credential IDs available for an account would come from a server // but we can just copy them from above... var idList = [{ id: cred.rawId, transports: ["usb", "nfc", "ble"], type: "public-key" }]; getCredentialDefaultArgs.publicKey.allowCredentials = idList; return navigator.credentials.get(getCredentialDefaultArgs); }) .then((assertion) => { console.log("ASSERTION", assertion); }) .catch((err) => { console.log("ERROR", err); });
- Mozilla Demo website and its source code.
- Google Demo website and its source code.
- webauthn.org and its client source code and server source code
Specifications
Browser compatibility
Desktop | Mobile | |||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
Chrome | Edge | Firefox | Internet Explorer | Opera | Safari | WebView Android | Chrome Android | Firefox for Android | Opera Android | Safari on IOS | Samsung Internet | |
Web_Authentication_API |
67 |
≤79 |
60 |
No |
54 |
13 |
67 |
67 |
? |
48 |
13 |
No |
allowCredentials |
67 |
≤79 |
60 |
No |
54 |
13 |
67 |
67 |
? |
48 |
13 |
No |
challenge |
67 |
≤79 |
60 |
No |
54 |
13 |
67 |
67 |
? |
48 |
13 |
No |
extensions |
67 |
≤79 |
60 |
No |
54 |
13 |
67 |
67 |
? |
48 |
13 |
No |
rpId |
67 |
≤79 |
60 |
No |
54 |
13 |
67 |
67 |
? |
48 |
13 |
No |
timeout |
67 |
≤79 |
60 |
No |
54 |
13 |
67 |
67 |
? |
48 |
13 |
No |
userVerification |
67 |
≤79 |
60 |
No |
54 |
13 |
67 |
67 |
? |
48 |
13 |
No |
Desktop | Mobile | |||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
Chrome | Edge | Firefox | Internet Explorer | Opera | Safari | WebView Android | Chrome Android | Firefox for Android | Opera Android | Safari on IOS | Samsung Internet | |
Web_Authentication_API |
67 |
≤79 |
60 |
No |
54 |
13 |
No |
67 |
? |
48 |
13 |
No |
attestation |
67 |
≤79 |
60 |
No |
54 |
13 |
No |
67 |
? |
48 |
13 |
No |
authenticatorSelection |
67 |
≤79 |
60 |
No |
54 |
13 |
No |
67 |
? |
48 |
13 |
No |
challenge |
67 |
≤79 |
60 |
No |
54 |
13 |
No |
67 |
? |
48 |
13 |
No |
excludeCredentials |
67 |
≤79 |
60 |
No |
54 |
13 |
No |
67 |
? |
48 |
13 |
No |
extensions |
67 |
≤79 |
60 |
No |
54 |
13 |
No |
67 |
? |
48 |
13 |
No |
pubKeyCredParams |
67 |
≤79 |
60 |
No |
54 |
13 |
No |
67 |
? |
48 |
13 |
No |
rp |
67 |
≤79 |
60 |
No |
54 |
13 |
No |
67 |
? |
48 |
13 |
No |
timeout |
67 |
≤79 |
60 |
No |
54 |
13 |
No |
67 |
? |
48 |
13 |
No |
user |
67 |
≤79 |
60 |
No |
54 |
13 |
No |
67 |
? |
48 |
13 |
No |
Desktop | Mobile | |||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
Chrome | Edge | Firefox | Internet Explorer | Opera | Safari | WebView Android | Chrome Android | Firefox for Android | Opera Android | Safari on IOS | Samsung Internet | |
Web_Authentication_API |
67 |
18 |
60
Only supports USB U2F tokens.
|
No |
No |
13 |
No |
70 |
60
Only supports USB U2F tokens.
|
No |
13 |
No |
authenticatorData |
67 |
18 |
60
Only supports USB U2F tokens.
|
No |
No |
13 |
No |
70 |
60
Only supports USB U2F tokens.
|
No |
13 |
No |
signature |
67 |
18 |
60
Only supports USB U2F tokens.
|
No |
No |
13 |
No |
70 |
60
Only supports USB U2F tokens.
|
No |
13 |
No |
userHandle |
67 |
18 |
60
Only supports USB U2F tokens.
|
No |
No |
13 |
No |
70 |
60
Only supports USB U2F tokens.
|
No |
13 |
No |
Desktop | Mobile | |||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
Chrome | Edge | Firefox | Internet Explorer | Opera | Safari | WebView Android | Chrome Android | Firefox for Android | Opera Android | Safari on IOS | Samsung Internet | |
Web_Authentication_API |
67 |
18 |
60
Only supports USB U2F tokens.
|
No |
No |
13 |
No |
70 |
60
Only supports USB U2F tokens.
|
No |
13 |
10.0 |
attestationObject |
67 |
18 |
60
Only supports USB U2F tokens.
|
No |
No |
13 |
No |
70 |
60
Only supports USB U2F tokens.
|
No |
13 |
10.0 |
getAuthenticatorData |
85 |
85 |
No |
No |
No |
No |
No |
85 |
No |
No |
No |
No |
getPublicKey |
85 |
85 |
No |
No |
No |
No |
No |
85 |
No |
No |
No |
No |
getPublicKeyAlgorithm |
85 |
85 |
No |
No |
No |
No |
No |
85 |
No |
No |
No |
No |
getTransports |
74 |
79 |
No |
No |
No |
No |
No |
74 |
No |
No |
No |
11.0 |
Desktop | Mobile | |||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
Chrome | Edge | Firefox | Internet Explorer | Opera | Safari | WebView Android | Chrome Android | Firefox for Android | Opera Android | Safari on IOS | Samsung Internet | |
Web_Authentication_API |
67 |
18 |
60
Only supports USB U2F tokens.
|
No |
No |
13 |
No |
70 |
60
Only supports USB U2F tokens.
|
No |
13 |
No |
clientDataJSON |
67 |
18 |
60
Only supports USB U2F tokens.
|
No |
No |
13 |
No |
70 |
60
Only supports USB U2F tokens.
|
No |
13 |
No |
Desktop | Mobile | |||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
Chrome | Edge | Firefox | Internet Explorer | Opera | Safari | WebView Android | Chrome Android | Firefox for Android | Opera Android | Safari on IOS | Samsung Internet | |
Web_Authentication_API |
67 |
18 |
60
Only supports USB U2F tokens.
|
No |
No |
13 |
No |
70 |
60
Only supports USB U2F tokens.
|
No |
13 |
No |
getClientExtensionResults |
67 |
18 |
60
Only supports USB U2F tokens.
|
No |
No |
13 |
No |
70 |
60
Only supports USB U2F tokens.
|
No |
13 |
No |
isUserVerifyingPlatformAuthenticatorAvailable |
67 |
18 |
60
Only supports USB U2F tokens.
|
No |
No |
13 |
No |
70 |
60
Only supports USB U2F tokens.
|
No |
13 |
No |
rawId |
67 |
18 |
60
Only supports USB U2F tokens.
|
No |
No |
13 |
No |
70 |
60
Only supports USB U2F tokens.
|
No |
13 |
No |
response |
67 |
18 |
60
Only supports USB U2F tokens.
|
No |
No |
13 |
No |
70 |
60
Only supports USB U2F tokens.
|
No |
13 |
No |
Desktop | Mobile | |||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
Chrome | Edge | Firefox | Internet Explorer | Opera | Safari | WebView Android | Chrome Android | Firefox for Android | Opera Android | Safari on IOS | Samsung Internet | |
Web_Authentication_API |
51 |
18 |
61 |
No |
38 |
13 |
51 |
51 |
61 |
41 |
13 |
5.0 |
create |
60 |
18 |
61 |
No |
47 |
13 |
60 |
60 |
61 |
44 |
13 |
8.0 |
get |
51 |
18 |
61 |
No |
38 |
13 |
51 |
51 |
61 |
41 |
13 |
5.0 |
preventSilentAccess |
60
51-60
|
18 |
61 |
No |
47
38-47
|
13 |
60
51-60
|
60
51-60
|
61 |
44
41-44
|
13 |
8.0
5.0-8.0
|
store |
51 |
79 |
61 |
No |
38 |
13 |
51 |
51 |
61 |
41 |
13 |
5.0 |
Desktop | Mobile | |||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
Chrome | Edge | Firefox | Internet Explorer | Opera | Safari | WebView Android | Chrome Android | Firefox for Android | Opera Android | Safari on IOS | Samsung Internet | |
Web_Authentication_API |
51 |
18 |
60 |
No |
38 |
13 |
51 |
51 |
60 |
41 |
13 |
5.0 |
id |
51 |
18 |
60 |
No |
38 |
13 |
51 |
51 |
60 |
41 |
13 |
5.0 |
type |
51 |
18 |
60 |
No |
38 |
13 |
51 |
51 |
60 |
41 |
13 |
5.0 |
BCD tables only load in the browser
CredentialsContainer
BCD tables only load in the browser
PublicKeyCredential
BCD tables only load in the browser
AuthenticatorResponse
BCD tables only load in the browser
AuthenticatorAttestationResponse
BCD tables only load in the browser
AuthenticatorAssertionResponse
BCD tables only load in the browser
PublicKeyCredentialCreationOptions
BCD tables only load in the browser
PublicKeyCredentialRequestOptions
BCD tables only load in the browser
© 2005–2021 MDN contributors.
Licensed under the Creative Commons Attribution-ShareAlike License v2.5 or later.
https://developer.mozilla.org/en-US/docs/Web/API/Web_Authentication_API