Passkeys
Configure WebAuthn registration, discoverable sign-in, and credential removal.
Passkeys use WebAuthn to authenticate with a device credential instead of a password. Authlier creates the WebAuthn options, stores one-time ceremony state, verifies the browser response, stores the public credential, and creates the session. The browser or device keeps the private key.
Configure the Go server
Passkeys: authlier.PasskeyConfig{
Enabled: true,
},The relying party is the site for which a passkey is valid. By default,
RelyingPartyID is the hostname from BaseURL, RelyingPartyName is
AppName, and allowed Origins contain BaseURL and TrustedOrigins. Set
these fields explicitly when the browser-facing WebAuthn domain differs from
the Go server URL.
WebAuthn requires HTTPS outside localhost.
Register a passkey
Registration adds a passkey to an existing Authlier user, so it requires a recent session. The browser client first requests options from the Go server, asks WebAuthn to create the credential, and returns the response with Authlier's ceremony token:
const started = await fetch('/api/auth/passkey/register/options', {
method: 'POST',
}).then((response) => response.json());
const publicKey = PublicKeyCredential.parseCreationOptionsFromJSON(
started.options.publicKey,
);
const credential = await navigator.credentials.create({ publicKey });
await fetch('/api/auth/passkey/register/verify', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
ceremonyToken: started.ceremonyToken,
response: credential,
}),
});The WebAuthn JSON convenience methods are available in current browsers but may be missing on older devices. Use a tested WebAuthn JSON compatibility helper when supporting those browsers.
Sign in with a passkey
const started = await fetch('/api/auth/passkey/sign-in/options', {
method: 'POST',
}).then((response) => response.json());
const publicKey = PublicKeyCredential.parseRequestOptionsFromJSON(
started.options.publicKey,
);
const credential = await navigator.credentials.get({ publicKey });
await fetch('/api/auth/passkey/sign-in/verify', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
ceremonyToken: started.ceremonyToken,
response: credential,
}),
});Unlike registration, discoverable passkey sign-in starts without a session. Successful verification identifies the Authlier user and creates the configured session.
List credentials with GET /api/auth/passkey/list. Remove one by sending its
returned credentialId to POST /api/auth/passkey/remove. Removal requires a
recent session and cannot delete the account's last sign-in method.