# TASK METADATA - **Target Files:** `server/main.ts`, `server/db.ts`, `ui/public/auth-client.js`, `ui/components/RegisterPage.tsx`, `ui/components/LoginPage.tsx` - **Core Objective:** Implement WebAuthn PRF extension support for progressive feature detection and Key Encryption Key (KEK) derivation during registration and login, with graceful fallback. - **Dependencies:** WebCrypto API natively in Deno/browser, SimpleWebAuthn v13 for passing PRF extension options. - **Additional Important Notes:** This task establishes the PRF derivation pipeline. SSS multi-share reconstruction will integrate in a future story (3.3). If PRF is unsupported, registration/login must proceed normally without breaking standard WebAuthn flows. --- ## Architectural Considerations & Risks - **Risks:** - **Authenticator Compatibility:** Not all authenticators support the WebAuthn PRF extension. A hard failure when PRF is missing would lock users out. The progressive fallback design is critical to prevent regressions in standard authentication. - **Extension Types & SDK Mapping:** Passing the exact extension payloads for PRF (`eval.first`, `eval.second`) in `generateRegistrationOptions` and `generateAuthenticationOptions` might require careful type mapping if `SimpleWebAuthn` types are strict. - **Database Migrations:** Modifying the `passkeys` table to include `prf_enabled` and `prf_salt` must maintain compatibility with existing passkey rows (which will default to false/null). - **Alternatives:** - Traditional server-side wrapping (HSM/KMS) or user passwords could be used for key derivation. However, the WebAuthn PRF extension natively binds the encryption key material to the hardware authenticator itself, preserving Auth-Yes's passwordless UX and zero-trust properties without transmitting raw secrets. ## Proposed Implementation ### 1. Database Schema Updates (`server/db.ts`) - Modify the `passkeys` table schema to include a `prf_enabled BOOLEAN DEFAULT FALSE` column. - Add a `prf_salt` column (binary or hex string) to store the 32-byte cryptographic salt generated during registration. ### 2. Registration Flow (Server & Client) - **Server (`server/main.ts`)**: In the `/api/register/challenge` endpoint, ensure the `prf: {}` extension is requested via `generateRegistrationOptions`. - **Client (`ui/public/auth-client.js`)**: Execute `navigator.credentials.create()` through the client SDK. Extract `getClientExtensionResults()?.prf`. - **Server (`server/main.ts`)**: In the `/api/register/verify` endpoint, inspect the extension results to check if PRF is enabled (`prf.enabled === true`). If supported, generate a 32-byte secure random salt (`prf_salt`). Store `prf_enabled: true` and the `prf_salt` alongside the new passkey record. ### 3. Login Flow (Server & Client) - **Server (`server/main.ts`)**: In the `/api/login/challenge` endpoint, retrieve the user's `prf_salt` if their passkey has `prf_enabled`. Include the `prf: { eval: { first: } }` extension payload in `generateAuthenticationOptions`. - **Client (`ui/public/auth-client.js`)**: - Execute `navigator.credentials.get()` with the provided PRF evaluation salt. - Check `getClientExtensionResults()?.prf?.results?.first` for the PRF output. - **Client-Side KEK Derivation**: - If PRF output exists, use it as Input Keying Material (IKM) for WebCrypto HKDF to derive a 256-bit AES-GCM Key Encryption Key (KEK). - **HKDF Parameters**: - Hash: `SHA-256` (RFC 5869) - Salt: 32-byte cryptographic salt (stored with passkey record) - Info: `new TextEncoder().encode("auth-yes:prf:device-share:v1")` - **Progressive Fallback**: - If `getClientExtensionResults()?.prf` is missing or fails, gracefully bypass the KEK derivation step and continue standard signature-only WebAuthn login. ### 4. UI Integration (`ui/components/RegisterPage.tsx`, `ui/components/LoginPage.tsx`) - (Optional but recommended) Include minor, non-blocking UI indicators or debug logs to signify when advanced hardware encryption (PRF) is successfully negotiated, aiding in development and progressive feature adoption.