install
Four focused packages cover the complete Worker and D1 path.
pnpm add @passkeeper/core @passkeeper/client @passkeeper/cloudflare @passkeeper/d1
packages
Protocol rules stay separate from browser, runtime, and storage concerns.
-
01
runtime agnostic
@passkeeper/core
Challenges, verification, registration, authentication, sessions, and invites.
-
02
browser
@passkeeper/client
Browser ceremonies, option conversion, credential serialization, and errors.
-
03
worker
@passkeeper/cloudflare
Worker routes, trusted origins, bounded bodies, cookies, and request hooks.
-
04
storage
@passkeeper/d1
Inspectable SQL, atomic storage operations, migrations, and scheduled cleanup.
secure defaults
Security properties are wired into the ordinary path, not left as integration chores.
- Trusted relying-party and browser-origin validation
- One-time, expiring challenges consumed atomically
- Hashed session tokens and invite codes
- Guarded credential counters and invite usage
- HttpOnly, Secure, SameSite session cookies
- Oslo parsing with runtime WebCrypto verification
live demo
Run a real passkey ceremony against the same packages shown above. Local development
uses the seeded invite launch-code; deployed demos require an issued invite.
Demo credentials belong only to this origin. Do not use a production identity here.
worker setup
Configure the trusted domain, bind D1, and mount auth where the application already runs.
import { createPasskeeperRoutes } from "@passkeeper/cloudflare";
import { d1Adapter } from "@passkeeper/d1";
export default {
async fetch(request: Request, env: Env) {
const auth = createPasskeeperRoutes({
rpName: "My App",
rpId: env.RP_ID,
origin: env.RP_ORIGIN,
storage: d1Adapter(env.DB),
inviteRequired: true,
});
return auth.handle(request);
},
};
keep ownership