Authsignal’s Web SDKs let you rapidly implement passkeys in your browser-based apps.
Passkeys on Chrome

Signing in with a passkey on Chrome

Configure passkeys in the Authsignal Portal

  1. Navigate to the Authenticators section and click Set up Passkey.
  2. Set your Relying Party ID. The value should match the domain where your app is hosted (e.g. example.com).
    Add relying party ID
  3. If your app includes any subdomains then you can whitelist these by adding expected origins.

    Defining the valid origins for your app

Setup SDKs

Passkeys require integration from your backend server and your web frontend.
  1. Get your tenant’s credentials from the API keys page.
  2. Follow the setup instructions for one of our Server SDKs - or integrate via REST with our Server API.
  3. Follow the setup instructions for our Web SDK.

Creating passkeys

In Authsignal, you define an action to let users create passkeys. This does two things:
  1. It provides observability for all passkey creation events in the Authsignal Portal.
  2. It ensures that the passkey is securely bound to an existing user.

1. Backend - Generate token

In your backend, track an action using a Server SDK to generate a short-lived enrollment token.
const request = {
  userId: "dc58c6dc-a1fd-4a4f-8e2f-846636dd4833",
  action: "createPasskey",
  attributes: {
    scope: "add:authenticators",
  },
};

const response = await authsignal.track(request);

const token = response.token;
This token includes the add:authenticators scope to authorize binding a passkey to an existing user so you should only generate it when the user is strongly authenticated.

2. Frontend - Create passkey

In your app, call the signUp method using the Web SDK, passing the token generated in step 1.
const response = await authsignal.passkey.signUp({
  token: "eyJhbGciOiJIUzI....",
  username: "jane@authsignal.com",
  displayName: "Jane Smith",
});

Authenticating with passkeys

You can define another action to let users authenticate with their passkeys. This action will be used for observability and to authenticate the user on the server.

1. Frontend - Sign in with passkey

In your app, call the signIn method using the Web SDK.
const response = await authsignal.passkey.signIn({
  action: "signInWithPasskey",
});

if (response.data?.token) {
  // Send token to your backend for validation
}

2. Backend - Validate action

Pass the token returned in the previous step to your backend, validating the result of the authentication server-side.
const response = await authsignal.validateChallenge({
  action: "signInWithPasskey",
  token: "eyJhbGciOiJIUzI....",
});

if (response.state === "CHALLENGE_SUCCEEDED") {
  // User successfully authenticated with passkey
  const userId = response.userId;
} else {
  // Authentication failed
}
This server-side validation step can be used within one of our popular IdP integrations or with our session APIs to issue access tokens and refresh tokens.

Using autofill

Passkey autofill in Chrome

Passkey autofill requires you to have an input field on your web page for a username (e.g. email address) which can be used to sign in. When the user focuses the input field, they will be able to select an existing passkey if one is available on their device.
<input placeholder="Email address" autocomplete="username webauthn" />

1. Frontend - Enable passkey autofill

In your app’s frontend, call the signIn method after the page loads using the Web SDK and set the autofill parameter to true.
authsignal.passkey.signIn({ 
  action: "signInWithPasskey",
  autofill: true 
}).then((response) => {
  if (response.data?.token) {
    // User selected a passkey via autofill
    // Send token to your backend for validation
  }
});
If the user focuses the input field and successfully activates their passkey, the method will resolve with a token.

2. Backend - Validate action

Pass the token returned in the previous step to your backend, validating the result of the authentication server-side.
const response = await authsignal.validateChallenge({
  action: "signInWithPasskey",
  token: "eyJhbGciOiJIUzI....",
});

if (response.state === "CHALLENGE_SUCCEEDED") {
  // User successfully authenticated with passkey
  const userId = response.userId;
} else {
  // Authentication failed
}

Local development

For local development we recommend creating a separate tenant. Set your Relying Party ID to localhost for this tenant and add an expected origins entry which includes the port where your development server is running.
Add relying party ID for localhost
This will let you test passkeys locally while keeping your production configuration separate.

Next steps