HomeJournalThis post

WebAuthn PRF Browser Vault: Key Derivation

Derive a browser-vault key from WebAuthn PRF output with HKDF context binding, authenticated encryption, capability checks, recovery policy, and test vectors.

JP
JP Casabianca
UI/UX designer and full-stack engineer · Bogotá

A WebAuthn PRF browser vault can derive encryption material after a passkey assertion without exposing the credential's private key to JavaScript. This guide separates PRF capability, HKDF context binding, authenticated local encryption, recovery, sync, and server policy so a clever demo does not become an unrecoverable product.

WebAuthn PRF browser vault draws three boundaries

Authentication proves control of a credential to a relying party. The PRF extension asks a compatible authenticator to evaluate secret material for a supplied salt. Vault encryption turns the resulting output into a key for local records. These are connected operations, but their threat models and failure modes remain distinct.

Draw browser, authenticator, relying-party server, local storage, sync service, and recovery channel. Mark which party sees credential ID, PRF salt, PRF output, derived key, plaintext, ciphertext, metadata, and backup material. A WebAuthn PRF browser vault should keep PRF output and decrypted records inside the trusted client context unless the product explicitly chooses another boundary.

Define the asset and adversary. Local notes protected from casual disk inspection differ from enterprise secrets protected against a compromised origin, malicious extension, stolen unlocked device, or server operator. WebAuthn does not rescue an application running hostile JavaScript under its own origin. Content security, dependency control, session locking, and minimal plaintext lifetime remain essential.

PRF output enters a context-bound key ladderAn authenticator evaluates a salt, HKDF binds vault and credential context, and distinct keys encrypt local records without exposing the private credential key.PRFHKDFrecord keywrap keyvault context
  • Passkey: credential stays in authenticator
  • PRF: secret output for a salt
  • HKDF: bind vault context
  • AES-GCM: encrypt authenticated records
Figure 1: Authentication, PRF evaluation, and vault encryption keep separate responsibilities.

Detect PRF support before promising the vault

Capability is credential- and authenticator-specific, not a generic “passkeys supported” boolean. During registration, persist prf.enabled for the credential; during authentication, require prf.results for the requested eval or evalByCredential input before treating that assertion as an unlock capability. Platform, roaming, and synced credential behavior can differ, so the product still needs a tested browser-authenticator matrix and a clear alternative when the requested output is absent.

The Web Authentication Level 3 specification defines extension processing, the PRF explainer describes intended usage and constraints, and Web Crypto supplies HKDF and authenticated encryption. Treat current browser support as a tested matrix, not a permanent fact inferred from a specification.

Product copy must not offer encrypted-vault creation until the exact credential returns usable PRF results. If capability disappears on a new device, show that the vault is locked and explain available recovery paths. A browser local vault that silently falls back to a server-known key violates the original trust promise. A capability result belongs in product state, not a hidden console message, because unsupported authenticators require a deliberate alternative before data is written.

Derive keys with domain-separated context

Never use raw PRF output directly as a general encryption key. Feed it into HKDF with a versioned salt and an info value that binds relying-party context, credential or vault identity, purpose, algorithm, and key version. Domain separation prevents the same secret material from becoming interchangeable across encryption, wrapping, or authentication uses.

For example, jp-vault|example.com|vault-17|record-key|v1 can describe one derivation purpose. Store nonsecret salt, context version, credential reference, and algorithm beside ciphertext. Do not store PRF output or exportable derived keys. The WebAuthn PRF extension remains the root input while HKDF creates an explicit local key schedule.

The visual key ladder shows authenticator output entering HKDF, then splitting into a record-encryption key and optional wrapping key under different context labels. A WebAuthn PRF browser vault should keep those branches cryptographically distinct even when one unlock gesture produces both. The versioned labels make future rotation possible without asking old ciphertext to guess which derivation created it.

Encrypt records with authenticated metadata

Use an authenticated encryption mode such as AES-GCM with a fresh unpredictable nonce for every encryption under a key. Bind stable metadata—vault ID, record ID, schema version, and content type—as additional authenticated data when it must not be altered. Store nonce, ciphertext, tag, version, and nonsecret lookup fields together.

Avoid one giant encrypted JSON blob for a growing vault. Per-record encryption limits rewrite scope and supports independent deletion, but it can leak record count, update timing, and sizes. Decide which metadata is acceptable to reveal and consider padding or batching only when the threat model justifies the complexity.

Passkey-derived encryption does not imply that IndexedDB or OPFS is transactional with authenticator access. Write new ciphertext before replacing pointers, keep schema migrations restartable, and never discard the last decryptable version until the new version is verified. A failed tab, quota error, or device sleep should leave a recoverable record set.

Treat locking as plaintext lifecycle control

An unlocked page can read decrypted data, regardless of how strong the at-rest encryption is. Keep derived CryptoKey objects and plaintext in the narrowest scope, clear rendered secrets when the session locks, close workers, revoke object URLs, and avoid placing sensitive values in logs, analytics, crash reports, or global state.

Define lock triggers: explicit user action, inactivity, tab lifecycle, device change, permission loss, or high-risk operation. Requiring a fresh WebAuthn assertion for every keystroke is unusable, while leaving a key resident all day weakens the vault. Choose a session window and make it visible.

The table separates locked storage, unlocked memory, synced ciphertext, and recovery material. WebAuthn PRF browser vault security depends on this lifecycle as much as on key derivation. The encryption boundary only protects data while plaintext and keys are absent from an attacker-controlled execution context. Test session locking while a record editor, export operation, and background sync are active; each path must discard or finish plaintext under an explicit rule.

StateKey presentPlaintextServer sees
LockedNoNoCiphertext
UnlockedClientClientCiphertext
SyncedNoNoVersions
RecoveryDependsAfter unlockPolicy
Figure 2: The vault promise changes across locked, unlocked, synced, and recovery states.

Plan credential loss before storing irreplaceable data

If the credential disappears and no independent recovery path exists, the data may be permanently unreadable. Decide whether that is an acceptable privacy property or an unacceptable product failure. State the answer before the first record is created and let users export or enroll recovery according to the declared model.

Possible designs include a second PRF-capable credential that wraps the same vault key, a printed recovery secret, an organization escrow key, or no recovery at all. Each changes who can decrypt. Never claim “only you” while retaining a server escrow key, and never imply recoverability when it depends on a single synced credential whose PRF behavior has not been tested.

The runnable artifact demonstrates context binding, not authenticator recovery. It proves that the same fixture output under a different credential context cannot decrypt the record. In a real WebAuthn PRF browser vault, recovery fixtures must cover credential addition, credential removal, key rotation, device replacement, failed partial enrollment, and audit evidence.

The Node Web Crypto fixture stands in for authenticator PRF output, derives an AES-GCM key with HKDF context, decrypts the expected record, and rejects the same ciphertext under another credential context.

Runnable artifact — webauthn-prf-vault.test.mjs

import assert from "node:assert/strict";import {webcrypto} from "node:crypto";const subtle=webcrypto.subtle,enc=new TextEncoder();
const derive=async(context)=>{const base=await subtle.importKey("raw",enc.encode("fixture-prf-output"),"HKDF",false,["deriveKey"]);return subtle.deriveKey({name:"HKDF",hash:"SHA-256",salt:enc.encode("vault-v1"),info:enc.encode(context)},base,{name:"AES-GCM",length:256},false,["encrypt","decrypt"])};
const iv=new Uint8Array(12);iv[11]=7;const key=await derive("credential-a|example.com"),cipher=await subtle.encrypt({name:"AES-GCM",iv},key,enc.encode("draft note"));assert.equal(new TextDecoder().decode(await subtle.decrypt({name:"AES-GCM",iv},key,cipher)),"draft note");const wrong=await derive("credential-b|example.com");await assert.rejects(()=>subtle.decrypt({name:"AES-GCM",iv},wrong,cipher));
console.log("PASS: PRF-derived vault key is context bound");

Run node webauthn-prf-vault.test.mjs. Expected receipt: PASS: PRF-derived vault key is context bound.

Keep sync ciphertext-only and conflict-aware

Sync can replicate ciphertext, nonce, authenticated metadata, versions, and tombstones without receiving decryption keys. Authenticate the account and authorize vault membership separately from the encryption key. The server still learns traffic patterns and metadata unless the design deliberately hides them, so describe privacy boundaries precisely.

Use immutable record revisions and explicit conflict handling. Two unlocked devices can edit the same note with keys derived from their enrolled credentials. Preserve both ciphertext versions until the client decrypts and resolves them; a server-side last-write-wins rule can destroy content it cannot inspect. The WebAuthn PRF browser vault should surface conflict identity before merging decrypted content. Preserve both revision digests in the merge receipt.

Adjacent Journal articles cover related boundaries: passkey recovery is authentication architecture handles enrollment and recovery UX, AI agent workload identity separates service principals, temporary access expiry designs time-bound authority, and multimodal inputs as evidence constrains sensitive attachments. WebAuthn PRF browser vault recovery must work on a clean device with only the documented materials; an untested recovery sentence is not a recoverable design.

Release with capability and recovery drills

Test registration and assertion on every supported browser-authenticator class, including no PRF result, canceled ceremony, changed credential, device restore, offline use, quota exhaustion, corrupt ciphertext, wrong additional data, duplicate nonce detection, schema migration, and lock timeout. Retain only synthetic secrets in automated fixtures.

The release gate stops when unsupported users can create an unrecoverable vault unknowingly, a context mismatch decrypts, nonce reuse occurs, plaintext reaches telemetry, synced conflicts overwrite unseen data, or recovery claims exceed actual evidence. A secure primitive cannot compensate for misleading product language or an absent export path.

Archive the capability matrix, derivation context schema, encryption format, browser versions, recovery policy, lock rules, test vectors, and threat model. Revisit the WebAuthn PRF browser vault when passkey portability, browser extension behavior, or storage architecture changes. The elegant key ladder is only one component of a product whose real promise is knowing exactly who can recover which data.

Record credential deletion and device loss as separate drills because their remaining recovery materials and user explanations are not equivalent.

  1. 1Enroll

    Confirm PRF capability

  2. 2Derive

    Bind credential and vault

  3. 3Encrypt

    Use fresh nonce and AAD

  4. 4Recover

    Exercise declared policy

Figure 3: Capability and recovery frame the cryptographic happy path.

Ship the vault with an honest recovery story

The PRF extension can be a clean root for local encryption, but the trustworthy product is the entire lifecycle around it: capability, context, plaintext residence, sync, credential loss, and honest recovery. Design those boundaries with the same care as the key derivation. Keep a synthetic vault that exercises every supported credential class and restore path after browser upgrades. It is easier to discover a portability change in a fixture than when a person's only copy of a note refuses to open. Store the synthetic export outside normal user data so a drill never becomes a privacy incident.