Ship production-ready passkey authentication without becoming a WebAuthn expert
Project website »
Documentation
·
Quick start
·
Demo
No SDK lock-in. No backend coupling.
: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
Programmatically manage passkeys on 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 an isolated "tenancy" (environment):
npx @passlock/cli init
Take a note of your Tenancy ID and API Key
Passlock uses short-lived, single-use codes to safely bridge the browser and backend. Register a passkey in your frontend JS and send the result to your backend for verification:
// frontend/register.ts
import { registerPasskey } from "@passlock/client/passkey";
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 this code to your backend for verification
console.log('code: %s', result.code);
In your backend verify the code to obtain details about the newly registered passkey. We'll use the @passlock/server library for this, but you can also make vanilla REST calls.
// 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 new passkey
// 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 the code to your backend for verification.
// frontend/authenticate.ts
import { authenticatePasskey } from "@passlock/client/passkey";
const tenancyId = "myTenancyId";
// call this in a button click handler or similar action
const result = await authenticatePasskey({ tenancyId });
// send this code to your backend for verification
console.log('code: %s', result.code);
In your backend, verify the code and lookup 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.