passkey auth / cloudflare workers + d1

Auth primitives.
No hosted dependency.

Passkey-only signup, login, sessions, and invite codes for TypeScript applications. Your users, credentials, and authentication data stay in your own database.

model
library-first
hosting
self-hosted
release
pre-1.0

install

Four focused packages cover the complete Worker and D1 path.

pnpm add @passkeeper/core @passkeeper/client @passkeeper/cloudflare @passkeeper/d1

agent setup

Give this prompt to your coding agent. It checks compatibility before changing the project.

prompt
Integrate Passkeeper passkey auth into this repository. First inspect the runtime, framework, package manager, database, routing, and deployment target; report whether Passkeeper is compatible before changing files. If compatible, follow existing conventions and install only the required @passkeeper packages. For Cloudflare Workers with D1, prefer @passkeeper/cloudflare, @passkeeper/d1, and @passkeeper/client. Configure the exact RP_ID and RP_ORIGIN, apply the shipped D1 migration, mount auth routes, and wire registration, login, session, and logout. Do not invent APIs: inspect the installed package READMEs and exports. Run the relevant tests, typecheck, and build, then summarize changes and remaining deployment or manual passkey steps. Stop and explain if the stack is incompatible or security-critical values are unknown.

packages

Protocol rules stay separate from browser, runtime, and storage concerns.

  1. 01

    @passkeeper/core

    Challenges, verification, registration, authentication, sessions, and invites.

    runtime agnostic
  2. 02

    @passkeeper/client

    Browser ceremonies, option conversion, credential serialization, and errors.

    browser
  3. 03

    @passkeeper/cloudflare

    Worker routes, trusted origins, bounded bodies, cookies, and request hooks.

    worker
  4. 04

    @passkeeper/d1

    Inspectable SQL, atomic storage operations, migrations, and scheduled cleanup.

    storage

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. The shared demo invite is prefilled, so each visitor can register immediately.

Demo credentials belong only to this origin. Accounts are cleared daily once 24 hours old. Do not use a production identity here.

worker setup

Configure the trusted domain, bind D1, and mount auth where the application already runs.

typescript worker / module
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

Passkeys without handing auth to another platform.

start with the packages