Skip to content

Register a passkey

You’ll use the Passlock client library in your frontend to register a passkey on the user’s device. You’ll receive an id_token and code, which you will exchange for details about the newly created passkey. You will then link the Passkey ID to a local user account in your backend.

sequenceDiagram
  participant Frontend
  participant Client as Passlock Client
  participant Backend
  participant Server as Passlock Server

  Frontend->>Client: registerPasskey()
  Client-->>Frontend: id_token, code

  Frontend->>Backend: code

  Backend->>Server: exchangeCode(code)
  Server-->>Backend: authenticatorId
  
  Backend->>Backend: linkPasskey(authenticatorId)

You’ll need a user name 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 user name during your registration flow. For now we’ll hardcode it:

frontend/registerPasskey.ts
import {
registerPasskey,
isRegistrationSuccess
} from "@passlock/client/passkey";
// get this from your dev tenancy settings in the Passlock console
const tenancyId = "myTenancyId";
// capture in a form or prefill if the user is already logged in
const username = "jdoe@gmail.com";
// call this in a button click handler or similar action
const result = await registerPasskey({ tenancyId, username });
if (isRegistrationSuccess(result)) {
// send this to your backend
console.log({ code: result.code });
} else {
// something went wrong
console.error(result.message);
}

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.)

Your backend needs to exchange the code for details about the newly created passkey. We’ll use the Passlock server library to do this, but you can also make a vanilla REST call.

import { exchangeCode, isPrincipal } from "@passlock/node/principal";
// get these from your development tenancy settings
const tenancyId = "myTenancyId";
const apiKey = "myApiKey";
const result = await exchangeCode(code, { tenancyId, apiKey });
if (isPrincipal(result)) {
// includes details about the passkey
console.log(result);
} else {
console.error(result.message);
}

exchangeCode returns a Principal, representing a successful registration or authentication operation. Principal includes these properties:

{
"authenticatorId": "68syr-amcxo-4kkjp",
"passkey": {
"userVerified": true
},
}

You’ll need to link the 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"

If you’re unable to use the Passlock server library, you can make a simple REST call:

GET /{tenancyId}/principal/{code} HTTP/1.1
Host: https://api.passlock.dev
Accept: application/json
Authorization: Bearer {apiKey}