Passkey

This addon provides passkey (WebAuthn) authentication for a RedwoodSDK project.

Passkey

RedwoodSDK Passkey Addon

This addon provides passkey (WebAuthn) authentication for a RedwoodSDK project.

How to add to your project

These instructions assume you are starting with a new RedwoodSDK project, for example from npx create-rwsdk -t minimal my-project-name.

0. Decide whether to add this manually or via AI

To use your editor's AI agent support to add this addon for you (e.g. Cursor, VSCode Copilot):

  1. Make sure your project dir is open in your editor. You can create a new project with: npx create-rwsdk -t minimal my-project-name
  2. Open a new AI chat window for your project
  3. Make sure you are in Agent mode
  4. Send the following chat prompt in the chat window - it will do the rest for you!
Please apply this addon to my RedwoodSDK project using these instructions: https://raw.githubusercontent.com/redwoodjs/passkey-addon/refs/heads/main/README.md

Alternatively, to apply this addon manually, simply follow the steps below.

1. Download this addon

npx degit redwoodjs/sdk-experiments/passkey-addon _tmp_passkey_addon

2. Copy files

Copy the src directory from this addon into your project's root directory. This will add the following directories:

  • src/passkey: Core logic for passkey authentication.
  • src/session: Session management using a Durable Object.

3. Update package.json

Add the following dependencies to your package.json file:

"dependencies": {
  "@simplewebauthn/browser": "^13.1.0",
  "@simplewebauthn/server": "^13.1.1",
  "rwsdk": "0.1.6"
}

Then run pnpm install.

4. Update wrangler.jsonc

Update your wrangler.jsonc to add Durable Object bindings, environment variables, and database migrations.

{
  // ... existing configuration ...

  // Durable Objects configuration
  "durable_objects": {
    "bindings": [
      {
        "name": "SESSION_DURABLE_OBJECT",
        "class_name": "SessionDurableObject"
      },
      {
        "name": "PASSKEY_DURABLE_OBJECT",
        "class_name": "PasskeyDurableObject"
      }
    ]
  },

  // Environment variables
  "vars": {
    "WEBAUTHN_APP_NAME": "My Awesome App"
  },

  // Migrations
  "migrations": [
    {
      "tag": "v1",
      "new_sqlite_classes": ["PasskeyDurableObject"]
    }
  ]
}

Remember to change WEBAUTHN_APP_NAME to your app's name.

5. Update src/worker.tsx

Modify your src/worker.tsx to integrate the passkey authentication and routes.

// ...

import { authRoutes } from "@/passkey/routes";
import { setupPasskeyAuth } from "@/passkey/setup";
import { Session } from "@/session/durableObject";

export { SessionDurableObject } from "@/session/durableObject";
export { PasskeyDurableObject } from "@/passkey/durableObject";

export type AppContext = {
  // ...
  session: Session | null;
};

export default defineApp([
  // ...
  setCommonHeaders(),
  setupPasskeyAuth(),
  render(Document, [
    // ...
    index([
      ({ ctx }) => {
        if (!ctx.session?.userId) {
          return new Response(null, {
            status: 302,
            headers: { Location: "/auth/login" },
          });
        }
      },
      Home,
    ]),
    prefix("/auth", authRoutes()),
  ]),
]);

6. Update src/app/pages/Home.tsx

Add a login link to your Home.tsx page.

// ...

export function Home({ ctx }: RequestInfo) {
  return (
    <div>
      {/* ... */}
      <p>
        <a href="/auth/login">Login</a>
      </p>
    </div>
  );
}

7. Run the dev server

Now you can run the dev server:

pnpm dev

You should now have a working passkey authentication flow in your RedwoodSDK application!