Files
skills/docs/identity/auth/webauthn/src/schemas/schemas.md
2026-05-29 08:20:56 +01:00

3.6 KiB

WebAuthn — boundary schemas

(no submodules)

Purpose

Defines the Zod schemas wired at every public surface of @suaveplan/webauthn. They serve as the structural contract for caller-supplied options (register, authenticate) and for the parsed shapes the package returns (ParsedAuthData, ParsedAttestationStmt, ClientDataJSON, CoseKey). The schemas are the single typed boundary between untrusted byte input and the production validation pipeline.

Features

  • Strict caller-option shapes for register and authenticate.
  • Forward-compatible passthrough() on every authenticator-produced structure so an authenticator that emits extra metadata does not break parsing.
  • Constrained literal unions for attestation, userVerification, mediation, residentKey, and the per-format dispatchers so a mistyped enum surfaces at the boundary.
  • Discriminated largeBlob authenticate input (read: true xor write: Uint8Array) so the verifier can branch on the shape without re-validating.

Usage: Basic Example

import { WebAuthnRegisterOptionsSchema } from "@suaveplan/webauthn";

const parsed = WebAuthnRegisterOptionsSchema.parse({
    rp: { name: "example.com" },
    user: { id: new Uint8Array(16), name: "u", displayName: "U" },
    challenge: new Uint8Array(32),
    pubKeyCredParams: [{ type: "public-key", alg: -7 }],
    expectedOrigin: "https://example.com",
    expectedRpIdHash: new Uint8Array(32),
});

Usage: Advanced Example

import {
    ParsedAuthDataSchema,
    WebAuthnAuthenticateOptionsSchema,
} from "@suaveplan/webauthn";

function validate(unsafe: unknown) {
    const opts = WebAuthnAuthenticateOptionsSchema.parse(unsafe);
    return opts;
}
const auth = ParsedAuthDataSchema.parse({
    rpIdHash: new Uint8Array(32),
    flags: {
        userPresent: true,
        userVerified: false,
        backupEligible: false,
        backupState: false,
        attestedCredentialData: false,
        extensionsPresent: false,
    },
    flagsByte: 0x01,
    signCount: 0,
});

API Reference

  • ClientDataJSONSchema — pinned type, challenge, origin; passthrough.
  • CoseKeySchema — pinned kty (int); optional alg, crv, x, y, n, e, k; passthrough.
  • ParsedAuthDataFlagsSchema — six booleans per W3C L3 §6.1.
  • ParsedAuthDataSchema — fixed prefix + optional attested-credential-data + optional extensions.
  • ParsedAttestationStmtSchema — fmt: string, attStmt: Record<string, unknown>.
  • WebAuthnRegisterOptionsSchema, WebAuthnAuthenticateOptionsSchema — caller options.
  • PrfRegisterInputSchema, PrfAuthenticateInputSchema, LargeBlobRegisterInputSchema, LargeBlobAuthenticateInputSchema — extension inputs.

Implementation Notes

  • COSE_Key fields outside the RFC 9052 §7 minimum set are kept on the parsed object via passthrough() so a verifier can reach into vendor extensions when needed. The structural type narrowing happens in parser/cose-key.ts where the discriminated kty arms (EC2, OKP, RSA, Symmetric) are produced.
  • WebAuthnRegisterOptionsSchema deliberately marks attestation as optional; the W3C default is "none" and the production code applies that default before forwarding to the adapter.
  • LargeBlobAuthenticateInputSchema is a z.union of { read: true } xor { write: Uint8Array } so callers cannot request both simultaneously — the same constraint W3C §10.1.3 imposes.
  • Every options schema accepts a caller-side Uint8Array instance check rather than Buffer. This is universal — Buffer would not load in browsers.