Register a passkey
You’ll use the Passlock browser library in your frontend to register a passkey on the user’s device. The library will return an id_token and code. You will use the Passlock server library to exchange the code or id_token for details about the new passkey. You will then link the Passkey ID to a local user account in your backend.
sequenceDiagram participant Frontend participant Browser as @passlock/browser participant Backend participant Server as @passlock/server Frontend->>Browser: registerPasskey() Browser-->>Frontend: id_token, code Frontend->>Backend: code Backend->>Server: exchangeCode(code) Server-->>Backend: authenticatorId Backend->>Backend: linkPasskey(authenticatorId)
Frontend / Browser
Section titled “Frontend / Browser”You’ll need a username to register a passkey. How you obtain this is up to you. If the user is already signed into your system you could use their account name, otherwise you’d capture a username during your registration flow. For now we’ll hardcode it:
import { Passlock } from "@passlock/browser";
// get this from your dev tenancy settings in the Passlock consoleconst tenancyId = "myTenancyId";const passlock = new Passlock({ tenancyId });
// capture in a form or prefill if the user is already logged inconst username = "jdoe@example.com";
// call this in a button click handler or similar actionconst result = await passlock.registerPasskey({ username });
if (result.success) { // send this to your backend console.log({ code: result.value.code });} else { console.error(result.error.message);}import { Passlock } from "@passlock/browser/unsafe";
// get this from your dev tenancy settings in the Passlock consoleconst tenancyId = "myTenancyId";const passlock = new Passlock({ tenancyId });
// capture in a form or prefill if the user is already logged inconst username = "jdoe@example.com";
// call this in a button click handler or similar actionconst result = await passlock.registerPasskey({ username });
// send this to your backend for verificationconsole.log({ code: result.code });import { registerPasskey } from "@passlock/browser";
// get this from your dev tenancy settings in the Passlock consoleconst tenancyId = "myTenancyId";
// capture in a form or prefill if the user is already logged inconst username = "jdoe@example.com";
// call this in a button click handler or similar actionconst result = await registerPasskey({ username }, { tenancyId });
if (result.success) { // send this to your backend console.log({ code: result.value.code });} else { console.error(result.error.message);}import { registerPasskey } from "@passlock/browser/unsafe";
// get this from your dev tenancy settings in the Passlock consoleconst tenancyId = "myTenancyId";
// capture in a form or prefill if the user is already logged inconst username = "jdoe@example.com";
// call this in a button click handler or similar actionconst result = await registerPasskey({ username }, { tenancyId });
// send this to your backend for verificationconsole.log({ code: result.code });Assuming everything went well, you’ll obtain an id_token (JWT) and code. For now we’ll use the code. Submit it to your backend by whichever means you prefer (form submission, fetch, URL redirect etc.)
Backend
Section titled “Backend”Your backend should exchange the code for details about the new passkey.
Get the passkey details
Section titled “Get the passkey details”We’ll use the @passlock/server library to do this, but you can also make a vanilla REST call
import { Passlock } from "@passlock/server";
// get these from your development tenancy settingsconst tenancyId = "myTenancyId";const apiKey = "myApiKey";const passlock = new Passlock({ tenancyId, apiKey });
const result = await passlock.exchangeCode({ code });
if (result.success) { // implement this linkPasskey(user.id, result.value.authenticatorId);} else { console.error(result.error.message);}import { Passlock } from "@passlock/server/unsafe";
// get these from your development tenancy settingsconst tenancyId = "myTenancyId";const apiKey = "myApiKey";const passlock = new Passlock({ tenancyId, apiKey });
const result = await passlock.exchangeCode({ code });
// result includes details about the passkey. implement// linkPasskey to associate the passkey with a local user idlinkPasskey(user.id, result.authenticatorId);import { exchangeCode } from "@passlock/server";
// get these from your development tenancy settingsconst tenancyId = "myTenancyId";const apiKey = "myApiKey";
const result = await exchangeCode({ code }, { tenancyId, apiKey });
if (result.success) { // implement this linkPasskey(user.id, result.value.authenticatorId);} else { console.error(result.error.message);}import { exchangeCode } from "@passlock/server/unsafe";
// get these from your development tenancy settingsconst tenancyId = "myTenancyId";const apiKey = "myApiKey";
const result = await exchangeCode({ code }, { tenancyId, apiKey });
// result includes details about the passkey. implement// linkPasskey to associate the passkey with a local user idlinkPasskey(user.id, result.authenticatorId);exchangeCode returns an ExtendedPrincipal, representing a successful registration or authentication operation. Extended principal includes an authenticatorId property (passkey ID).
Associate the passkey with a user
Section titled “Associate the passkey with a user”You’ll need to link the ExtendedPrincipal.authenticatorId to a user account in your backend system. When the user signs in with the passkey you’ll identify their account using the same authenticatorId
---
title: Example table structure
---
erDiagram
user[user] {
int id PK
}
authenticator[authenticator] {
string authenticatorId PK "returned by exchangeCode"
int userId FK "points to user.id"
}
user ||--|{ authenticator : "User has one or more authenticators"
Using the REST API
Section titled “Using the REST API”If you’re unable to use the @passlock/server library, you can make a simple REST call:
GET /{tenancyId}/principal/{code} HTTP/1.1Host: https://api.passlock.devAccept: application/jsonAuthorization: Bearer {apiKey}