Ship production-ready passkey authentication without becoming a WebAuthn expert
Project website »
Documentation
·
Quick start
·
Demo
No SDK lock-in. No backend coupling.
This monorepo contains the public browser SDK, server SDK, CLI, and a reference SvelteKit example.
:unlock: No lock-in
Framework agnostic. Standards compliant.
:key: Related origins (domain migration)
Accept passkeys from other domains on your site (subject to security constraints).
:rocket: Zero config passkeys
Works out of the box with sensible defaults.
:iphone: Credential management
Update, prune and remove passkeys on supported end user devices.
:muscle: Powerful
User verification, autofill, roaming authenticators and more.
You can be up and running with a working passkey flow in minutes :rocket:
Create a new Passlock tenancy:
npx @passlock/cli init
Take a note of your Tenancy ID and API Key.
Passlock uses short-lived, single-use codes and signed id_tokens to safely bridge the browser and backend. Register a passkey in your frontend JS and send either value to your backend for verification:
// frontend/register.ts
import { registerPasskey } from "@passlock/browser";
const tenancyId = "myTenancyId";
// supply or capture a username
const username = "[email protected]";
// call this in a click handler or similar action
const result = await registerPasskey({ tenancyId, username });
// send result.code or result.id_token to your backend for verification
console.log('code: %s', result.code);
In your backend exchange the code to obtain details about the completed registration. We'll use the @passlock/server library for this, but you can also make vanilla REST calls or verify the id_token instead.
// backend/register.ts
import { exchangeCode } from "@passlock/server";
const tenancyId = "myTenancyId";
const apiKey = "myApiKey";
const result = await exchangeCode({ code, tenancyId, apiKey });
// includes details about the completed registration
// associate the authenticatorId (passkey ID) with a local user account
console.log('passkey id: %s', result.authenticatorId);
Very similar to the registration process, authenticate in your frontend and send either the returned code or id_token to your backend for verification.
// frontend/authenticate.ts
import { authenticatePasskey } from "@passlock/browser";
const tenancyId = "myTenancyId";
// call this in a button click handler or similar action
const result = await authenticatePasskey({ tenancyId });
// send result.code or result.id_token to your backend for verification
console.log('code: %s', result.code);
In your backend, exchange the code and look up the user by authenticatorId ...
// backend/authenticate.ts
import { exchangeCode } from "@passlock/server";
const tenancyId = "myTenancyId";
const apiKey = "myApiKey";
const result = await exchangeCode({ code, tenancyId, apiKey });
// lookup the user based on their authenticatorId
console.log('passkey id: %s', result.authenticatorId);
[!TIP]
Not using a JS backend? The examples in this README use our @passlock/server server library, but this is not required. Passlock works similarly to OAuth2/OpenID Connect, so you can make vanilla HTTP calls or use any suitable JWT library to verify anid_token(JWT).
Please see the tutorial and documentation
If Passlock saved you time or helped you ship passkeys faster, a ⭐ on GitHub helps more than you think.