Implement WebAuthn passkey authentication

Add complete WebAuthn support for passkey registration and authentication:
- Install @simplewebauthn/server for WebAuthn utilities
- Create passkey-helpers.ts with base64url/Uint8Array conversion utilities
- Create webauthn.ts with registration/authentication option generation and verification
- Create context.ts with API context types
- Implement all WebAuthn router handlers (createRegistrationOptions, verifyRegistration, createAuthenticationOptions, verifyAuthentication)
- Implement passkey management handlers (listPasskeys, createPasskey, renamePasskey, deletePasskey)
- Add WebAuthn configuration constants and environment variables

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
RevIQ
2026-01-09 12:34:26 +08:00
parent a4dff188eb
commit b46146faa5
8 changed files with 709 additions and 24 deletions

View File

@@ -0,0 +1,60 @@
/**
* API context types for oRPC handlers
*/
import type { Database } from "@reviq/db-schema";
import type { Kysely } from "kysely";
/**
* Base API context available to all handlers
*/
export interface APIContext {
/** Database client */
db: Kysely<Database>;
/** Request origin (e.g., "http://localhost:6827") */
origin: string;
/** Allowed WebAuthn origins */
allowedOrigins: string[];
/** Relying party name for WebAuthn */
rpName: string;
}
/**
* User information from the session
*/
export interface SessionUser {
id: number;
email: string;
displayName: string | null;
emailVerifiedAt: Date | null;
isSuperuser: boolean;
}
/**
* Session information
*/
export interface Session {
id: number;
trustedMode: boolean;
createdAt: Date;
}
/**
* Authenticated API context for protected handlers
*/
export interface AuthenticatedContext extends APIContext {
/** Current user from session */
user: SessionUser;
/** Current session */
session: Session;
}
/**
* Login request context (used during login flow)
*/
export interface LoginRequestContext extends APIContext {
/** Login request ID from cookie */
loginRequestId: number;
/** User associated with the login request */
user: SessionUser;
}