Ship production-ready passkey authentication without becoming a WebAuthn expert
Project website »
Documentation
·
Quick start
·
Demo
- Passlock handles WebAuthn complexity (browser quirks, ceremonies, encoding)
- Your frontend registers/authenticates passkeys using a simple JS API, resulting in a code and id_token (JWT)
- Your backend exchanges the code or verifies the JWT using our server library or REST API.
- You stay in control of users, sessions, and authorization
No SDK lock-in. No backend coupling.
This monorepo contains the public browser SDK, server SDK, CLI, and a reference SvelteKit example.
- Developers looking for flexible integration options
- Teams needing to launch quickly, then adopt advanced features as the need arises
- Organizations who don't want to be locked into a product, framework or ecosystem
🔓 No lock-in
Framework agnostic. Standards compliant.
🔑 Related origins (domain migration)
Accept passkeys from other domains on your site (subject to security constraints).
🚀 Zero config passkeys
Works out of the box with sensible defaults.
📱 Credential management
Update, prune and remove passkeys on supported end user devices.
💪 Powerful
User verification, autofill, roaming authenticators and more.
You can be up and running with a working passkey flow in minutes 🚀
Create a new Passlock tenancy:
npx @passlock/cli initTake 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 = "jdoe@gmail.com";
// 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 an id_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.