Chrome 128 and 129 introduces exciting new features for WebAuthn—the underlying API to build passkey-based authentication systems.
- Hints: Hints give relying parties (RPs) better control over WebAuthn UI in the browser. They are especially helpful for enterprise users who want to use security keys.
- Related origin requests: With related origin requests, RPs can make passkeys valid on multiple domains. If you own multiple sites, you can now enable your users to reuse their passkey across your sites, eliminating login friction.
- JSON serialization: JSON serialization APIs let you simplify an RP's frontend code by encoding and decoding options and credentials passed to and from WebAuthn API.
Hints
With hints
, relying parties (RP) can now specify UI preferences for creating a
passkey or authenticating with a passkey.
Previously, when an RP wanted to restrict the authenticator the user can use to
create a passkey or to authenticate with, they could use
authenticatorSelection.authenticatorAttachment
to specify "platform"
or
"cross-platform"
. They respectively limit the authenticator to a platform
authenticator
or a roaming
authenticator.
With hints
, this specification can be more flexible.
The RP can use optional hints
in the PublicKeyCredentialCreationOptions
or
PublicKeyCredentialRequestOptions
to specify "security-key"
,
"client-device"
and "hybrid"
in a preference order in an array.
The following is an example credential creation request that prefers
"cross-platform"
authenticators with "security-key"
as a hint. This tells
Chrome to show a security key focused UI for enterprise users.
const credential = await navigator.credentials.create({
publicKey: {
challenge: *****,
hints: ['security-key'],
authenticatorSelection: {
authenticatorAttachment: 'cross-platform'
}
}
});
When an RP wants to prioritize a cross-device verification scenario, they can
send an authentication request that prefers "cross-platform"
authenticators
with "hybrid"
as a hint.
const credential = await navigator.credentials.create({
publicKey: {
challenge: *****,
residentKey: true,
hints: ['hybrid']
authenticatorSelection: {
authenticatorAttachment: 'cross-platform'
}
}
});
Related origin requests
With Related Origin Requests, RPs can make passkeys usable from multiple domains. Building a centralized login experience and using federation protocols remains the recommended solution for most sites. But if you own multiple domains and federation isn't possible, related origins may be a solution.
All WebAuthn requests must specify a relying party ID (RP ID), and all passkeys
are associated with a single RP ID. Traditionally, an origin could only specify
an RP ID based on its domain, so in that case www.example.co.uk
could specify
an RP ID of example.co.uk
, but not example.com
. With Related Origin
Requests, a claimed RP ID can be validated by fetching a well-known JSON file
located at /.well-known/webauthn
from the target domain. So example.co.uk
(and example.in
, example.de
, and so on) could all use an RP ID of
example.com
if example.com
specifies them in the following format:
URL: https://example.com/.well-known/webauthn
{
"origins": [
"https://example.co.uk",
"https://example.de",
"https://example.sg",
"https://example.net",
"https://exampledelivery.com",
"https://exampledelivery.co.uk",
"https://exampledelivery.de",
"https://exampledelivery.sg",
"https://myexamplerewards.com",
"https://examplecars.com"
]
}
Learn how to set up Related Origin Requests at Allow passkey reuse across your sites with Related Origin Requests.
JSON serialization
WebAuthn request and response objects have multiple fields that contain raw binary data in an ArrayBuffer, such as the credential ID, user ID, or challenge. If a website wants to use JSON to exchange this data with its server, the binary data must first be encoded, for example with Base64URL. This adds unnecessary complexity for developers that want to start using passkeys on their websites.
WebAuthn now offers APIs to parse
PublicKeyCredentialCreationOptions
and
PublicKeyCredentialRequestOptions
WebAuthn request objects directly from JSON, and serialize the
PublicKeyCredential
response directly into JSON. All ArrayBuffer-valued fields that carry raw binary
data are automatically converted from or to their Base64URL-encoded values.
These APIs are available from Chrome 129.
Before creating a passkey, fetch a JSON encoded
PublicKeyCredentialCreationOptions
object from the server and decode it using
PublicKeyCredential.parseCreationOptionsFromJSON()
.
export async function registerCredential() {
// Fetch encoded `PublicKeyCredentialCreationOptions`
// and JSON decode it.
const options = await fetch('/auth/registerRequest').json();
// Decode `PublicKeyCredentialCreationOptions` JSON object
const decodedOptions = PublicKeyCredential.parseCreationOptionsFromJSON(options);
// Invoke the WebAuthn create() function.
const cred = await navigator.credentials.create({
publicKey: decodedOptions,
});
...
After creating a passkey, encode the resulting credential using toJSON()
so
that it can be sent to the server.
...
const cred = await navigator.credentials.create({
publicKey: options,
});
// Encode the credential to JSON and stringify
const credential = JSON.stringify(cred.toJSON());
// Send the encoded credential to the server
await fetch('/auth/registerResponse', credential);
...
Before authenticating with a passkey, fetch a JSON encoded
PublicKeyRequestCreationOptions
from the server and decode it using
PublicKeyCredential.parseRequestOptionsFromJSON()
.
export async function authenticate() {
// Fetch encoded `PublicKeyCredentialRequestOptions`
// and JSON decode it.
const options = await fetch('/auth/signinRequest').json();
// Decode `PublicKeyCredentialRequestOptions` JSON object
const decodedOptions = PublicKeyCredential.parseRequestOptionsFromJSON(options);
// Invoke the WebAuthn get() function.
const cred = await navigator.credentials.get({
publicKey: options
});
...
After authenticating with a passkey, encode the resulting credential using
toJSON()
method so that it can be sent to the server.
...
const cred = await navigator.credentials.get({
publicKey: options
});
// Encode the credential to JSON and stringify
const credential = JSON.stringify(cred.toJSON());
// Send the encoded credential to the server
await fetch(`/auth/signinResponse`, credential);
...
Learn more
To learn more about WebAuthn and passkeys, check out the following resources: