{"vibecode":{"doc":"passkeys","role":"implementation sketch for WebAuthn / FIDO2 passkeys in Caspian; assumes the reader knows the protocol and is asking what the class shape, engine primitives, and integration points look like","status":"speculative — not a current implementation target; documented so the design is ready when it becomes one","related":["index.md (parent security model — vault, protected mode, libsodium memory protection)"],"audience":"Caspian implementers"}}
Server side (relying party): holds credential metadata in regular bucket fields; verifies assertions via libsodium signature primitives. No vault needed — nothing in the bucket is crypto-secret.
Authenticator side: holds the private key in the vault; signs through vault.sign gateway operations. Uses the existing vault + protected-mode model (see index.md).
Both are user-space Caspian classes. The only genuinely new engine dependency is a CBOR decoder for COSE_Key parsing and attestation/assertion objects. Everything else (CSPRNG, signature primitives, vault) is already on the roadmap for unrelated reasons.
Validates clientData (challenge, origin, type), authenticatorData (rpIdHash, user-present flag), sign_count progression, signature against the stored public key. Mutates @sign_count and @last_used_at on success. Raises specific exception classes per failure mode.
.id
string
The credential ID.
.algorithm_name
string
Human-readable alg name.
.transports, .aaguid, .user_handle
various
Accessors for the corresponding fields.
.label / .label=(value)
string
Read/set the user-supplied nickname.
.is_backed_up? / .is_backup_eligible?
boolean
Sync-state predicates.
.created_at, .last_used_at
timestamp
Timestamps.
.to_storage_hash
hash
Serialize for DB storage.
.matches_aaguid?(known_aaguid_list)
boolean
Convenience for authenticator-model policy checks.
Returns {credential_id, authenticator_data, client_data_json, signature, user_handle} so the caller can look up the matching Passkey by credential_id and call .verify on it.
Every bucket field is non-secret. Public keys, credential IDs, sign counts, and metadata can live in regular DB columns without protection. The vault and protected-mode machinery aren't engaged on the server side.
Calls vault.sign(@vault_id, message). The vault gateway opens a protected-mode window, mprotects the buffer readable, runs the signing primitive, mprotects back.
Generates a keypair via libsodium, extracts the public key (cached in the bucket), pipes the private key into vault.store, returns the instance. The plaintext private key never reaches a regular Caspian value.
Passkey.from_storage(hash, vault_id)
Passkey instance
Reconstruct at startup. Caller is responsible for populating the vault entry separately (usually via a startup loader that reads encrypted key material from disk through vault.store).
The CBOR decoder is the only genuinely new dependency. Options:
C-binding to an existing library (cn-cbor, tinycbor).
Pure-Caspian implementation. WebAuthn touches a small subset of CBOR; a focused implementation is feasible.
The lean is a C-binding for performance and correctness (CBOR has subtle edge cases — duplicate keys, integer canonicalization, indefinite-length encodings — and existing libraries have already worked them out).
Whether Passkey ships in core, in a standard-library package, or as third-party Caspian code is a packaging call, not a security one. Reasonable to defer until passkey support is a live implementation priority. The class is straightforward Caspian code once the primitives above are in place.