3.8 KiB
3.8 KiB
largeBlob extension support
(no submodules)
Purpose
Implements the W3C WebAuthn L3 §10.1.3 largeBlob extension passthrough plus result parsing. The largeBlob extension lets the authenticator store a small per-credential byte string (typically credentials or session-resumption tokens) inside the authenticator's secure element. Registration asks the authenticator to allocate the slot; subsequent authentications read or write the blob.
Features
LargeBlobRegisterInput({ support: "required" | "preferred" }) and discriminatedLargeBlobAuthenticateInput({ read: true }xor{ write: Uint8Array }) — W3C-mandated mutual exclusion.readLargeBlobRegisterResultextracts{ supported }from the registration ceremony'sClientExtensionResults.readLargeBlobReadResultextracts{ blob? }from the assertion ceremony's results —blobis omitted (not zeroed) when the authenticator did not return one.readLargeBlobWriteResultextracts{ written }— boolean discriminator between success and silent drop.buildLargeBlobRegisterExtension/buildLargeBlobAuthenticateExtensionproduce the wire-shape passed tonavigator.credentials.{create,get}.
Usage: Basic Example
import {
buildLargeBlobAuthenticateExtension,
readLargeBlobReadResult,
} from "@suaveplan/webauthn/extensions/large-blob";
const ext = buildLargeBlobAuthenticateExtension({ read: true });
const cred = await navigator.credentials.get({
publicKey: { challenge, allowCredentials, extensions: ext }
});
const result = readLargeBlobReadResult(
(cred as PublicKeyCredential).getClientExtensionResults()
);
console.log(result?.blob?.byteLength ?? 0);
Usage: Advanced Example
import {
buildLargeBlobAuthenticateExtension,
buildLargeBlobRegisterExtension,
readLargeBlobRegisterResult,
readLargeBlobWriteResult,
} from "@suaveplan/webauthn/extensions/large-blob";
const regExt = buildLargeBlobRegisterExtension({ support: "required" });
const reg = await navigator.credentials.create({
publicKey: { ...opts, extensions: regExt }
});
const regResult = readLargeBlobRegisterResult(
(reg as PublicKeyCredential).getClientExtensionResults()
);
if (!regResult?.supported) {
throw new Error("authenticator does not support largeBlob");
}
const writeExt = buildLargeBlobAuthenticateExtension({ write: payload });
const authResult = await navigator.credentials.get({
publicKey: { ...authOpts, extensions: writeExt }
});
const w = readLargeBlobWriteResult(
(authResult as PublicKeyCredential).getClientExtensionResults()
);
if (!w?.written) {
throw new Error("write dropped");
}
API Reference
LargeBlobRegisterInput,LargeBlobAuthenticateInput— input shapes.LargeBlobRegisterResult,LargeBlobReadResult,LargeBlobWriteResult— result shapes.readLargeBlobRegisterResult,readLargeBlobReadResult,readLargeBlobWriteResult— narrowing readers.buildLargeBlobRegisterExtension,buildLargeBlobAuthenticateExtension— wire-shape builders.
Implementation Notes
- The
support: "required"mode causes the registration to fail (withNotSupportedError) when the authenticator cannot allocate a largeBlob slot;support: "preferred"allocates if possible and falls back silently otherwise. The result'ssupportedflag distinguishes the two outcomes. - Read and write are mutually exclusive per W3C §10.1.3. The discriminated input union enforces this at the type level so callers cannot accidentally pass both.
readLargeBlobReadResultreturns{}(empty object, notundefined) when the extension was acknowledged but noblobwas returned. This lets callers distinguish "authenticator does not implement the extension" (undefinedreturn) from "extension implemented, no blob stored" ({ blob: undefined }).