Skip to content

Passkey Authentication

Overview

Passkeys provide passwordless authentication using biometrics (fingerprint, face recognition) or security keys. The SDK’s auth.passkey namespace wraps the WebAuthn API, handling credential creation, assertion, and server-side verification.

What Are Passkeys?

Passkeys are FIDO2/WebAuthn credentials stored on the user’s device or in a platform authenticator (iCloud Keychain, Google Password Manager, Windows Hello). They are:

  • Phishing-resistant — Credentials are bound to the origin (domain)
  • No passwords — Users authenticate with biometrics or a PIN
  • Synced across devices — Platform authenticators sync passkeys via cloud

Checking Support

Before showing Passkey UI, check if the browser supports WebAuthn:

// Synchronous check
if (auth.passkey.isSupported()) {
// Show Passkey login button
}
// Check if Conditional UI (autofill) is available
const hasConditionalUI = await auth.passkey.isConditionalUIAvailable();

Sign Up

Create a new account with a Passkey. This creates the user and registers a WebAuthn credential in a single step:

const { data, error } = await auth.passkey.signUp({
});
if (error) {
console.error('Sign up failed:', error.message);
return;
}
console.log('Account created:', data.user);
console.log('Session:', data.session);

Sign Up Options

interface PasskeySignUpOptions {
/** User's email address (required) */
email: string;
/** Display name (optional) */
displayName?: string;
}

What Happens Internally

  1. SDK sends a registration request to the Authrim server
  2. Server returns WebAuthn creation options (challenge, relying party info)
  3. Browser prompts the user for biometric verification
  4. Browser creates a public key credential
  5. SDK sends the credential back to the server
  6. Server creates the user account, stores the credential, and returns a session

Sign In

Authenticate an existing user with their Passkey:

const { data, error } = await auth.passkey.login();
if (error) {
console.error('Login failed:', error.message);
return;
}
console.log('Welcome back:', data.user);

No email or username is needed — the browser presents available passkeys for the current origin.

Login Options

interface PasskeyLoginOptions {
/** Preferred authenticator attachment */
authenticatorAttachment?: 'platform' | 'cross-platform';
/** Whether to use conditional UI (autofill) */
conditionalUI?: boolean;
}

Conditional UI (Autofill)

Conditional UI integrates Passkey selection into the browser’s autofill menu. Instead of a dedicated “Sign in with Passkey” button, users see their passkeys in the same autofill dropdown as saved passwords:

// Check availability
if (await auth.passkey.isConditionalUIAvailable()) {
// Start conditional UI (non-blocking)
auth.passkey.login({ conditionalUI: true })
.then(({ data, error }) => {
if (data) {
console.log('Signed in via autofill:', data.user);
}
});
}

To cancel a pending conditional UI request (e.g., when navigating away):

auth.passkey.cancelConditionalUI();

Register Additional Passkey

Add a new passkey to an existing account. The user must already be authenticated:

const { data, error } = await auth.passkey.register();
if (error) {
console.error('Registration failed:', error.message);
return;
}
console.log('New passkey registered:', data);
// data: PasskeyCredential { id, publicKey, ... }

This is useful for:

  • Adding a security key as a backup
  • Registering a passkey on a new device
  • Settings/profile page “Add Passkey” feature

Register Options

interface PasskeyRegisterOptions {
/** Preferred authenticator attachment */
authenticatorAttachment?: 'platform' | 'cross-platform';
}

Error Handling

Common passkey errors:

Error CodeMeaningUser Action
AR003001WebAuthn not supportedShow alternative login methods
AR003002User cancelled the ceremonyAllow retry or offer alternatives
AR003003Credential not foundPrompt user to sign up or use another method
AR003004Authenticator errorRetry or contact support
AR003005Server validation failedRetry the operation
const { data, error } = await auth.passkey.login();
if (error) {
switch (error.code) {
case 'AR003002':
// User cancelled — do nothing or show subtle message
break;
case 'AR003003':
// No credential — suggest sign up
showMessage('No passkey found. Would you like to sign up?');
break;
default:
showMessage(error.message);
}
}

Complete Example

import { createAuthrim } from '@authrim/web';
const auth = await createAuthrim({
issuer: 'https://auth.example.com',
clientId: 'my-app',
});
// Check support
if (!auth.passkey.isSupported()) {
document.getElementById('passkey-section').style.display = 'none';
}
// Sign in button
document.getElementById('passkey-login').addEventListener('click', async () => {
const { data, error } = await auth.passkey.login();
if (error) {
alert(error.message);
return;
}
window.location.href = '/dashboard';
});
// Sign up button
document.getElementById('passkey-signup').addEventListener('click', async () => {
const email = document.getElementById('email-input').value;
const { data, error } = await auth.passkey.signUp({ email });
if (error) {
alert(error.message);
return;
}
window.location.href = '/dashboard';
});
// Add passkey button (profile page, user already authenticated)
document.getElementById('add-passkey').addEventListener('click', async () => {
const { data, error } = await auth.passkey.register();
if (error) {
alert(error.message);
return;
}
alert('Passkey added successfully');
});

Next Steps