{"version":3,"file":"passkey.cjs","names":[],"sources":["../../src/auth/passkey.ts"],"sourcesContent":["/**\n * @tempest-limits file-lines, function-lines — the WebAuthn client half: the JSON\n * shapes both ceremonies exchange with a backend, base64url ↔ ArrayBuffer, the\n * capability probes and the error classifier. The two ceremonies are near-mirrors\n * that must not drift — register and authenticate encode the same credential fields\n * in the same order — and the file's docstring is also the specification of the four\n * backend routes it expects.\n */\n\nimport { base64ToBytes, bytesToBase64 } from \"@/utils/base64\";\n\n/**\n * Classified reason a passkey ceremony did not produce a credential.\n *\n * The kinds group the raw `DOMException.name` values the way a UI has to branch\n * on them, which is *not* how the spec groups them:\n *\n * - `\"cancelled\"` covers `NotAllowedError`, which the browser raises both when\n *   the user dismissed the sheet and when the ceremony timed out. They are\n *   indistinguishable **by design** — telling a site \"the user has no credential\n *   for you\" would leak account existence — so a UI must treat them as one thing.\n * - `\"already-registered\"` (`InvalidStateError`) is not really a failure: this\n *   device already holds a credential for this user. The correct reaction is\n *   \"you are already set up on this device\", never a red error.\n * - `\"rp-mismatch\"` (`SecurityError`) is the single most common integration bug:\n *   `rp.id` must equal the page's domain or a registrable parent of it.\n */\nexport type PasskeyErrorKind =\n    | \"unsupported\"\n    | \"insecure\"\n    | \"cancelled\"\n    | \"already-registered\"\n    | \"not-supported\"\n    | \"rp-mismatch\"\n    | \"invalid-options\"\n    | \"aborted\"\n    | \"unknown\";\n\n/** Which ceremony was running, so the message can name it. */\nexport type PasskeyCeremony = \"register\" | \"authenticate\";\n\n/**\n * A passkey failure carrying a stable {@link PasskeyErrorKind} plus an English\n * message safe to show a user.\n *\n * A class rather than the plain `{ kind, message }` object the media classifier\n * returns, because these surface by rejecting a promise: an `Error` subclass keeps\n * stack traces, `instanceof` checks and logging intact, and `kind` is what code\n * branches on.\n */\nexport class PasskeyError extends Error {\n    /** Stable, branchable classification. */\n    readonly kind: PasskeyErrorKind;\n\n    /**\n     * Build a classified passkey error.\n     *\n     * @param kind - The classification a UI branches on.\n     * @param message - English, user-safe explanation.\n     * @param cause - The original thrown value, when there was one.\n     */\n    constructor(kind: PasskeyErrorKind, message: string, cause?: unknown) {\n        super(message);\n        this.name = \"PasskeyError\";\n        this.kind = kind;\n        this.cause = cause;\n    }\n}\n\n/**\n * Minimal subset of `navigator.credentials` the passkey client touches.\n *\n * Declared here — the `<X>Like` pattern the SDK's adapters use — for two reasons:\n * jsdom has no `navigator.credentials` at all, so tests must inject a double; and\n * `mediation: \"conditional\"` is newer than some TypeScript DOM libs, which would\n * otherwise reject the call that makes autofill work.\n */\nexport interface CredentialsContainerLike {\n    /** Runs the registration ceremony. */\n    create(options: {\n        publicKey: PublicKeyCredentialCreationOptions;\n        signal?: AbortSignal;\n    }): Promise<Credential | null>;\n    /** Runs the authentication ceremony. */\n    get(options: {\n        publicKey: PublicKeyCredentialRequestOptions;\n        signal?: AbortSignal;\n        mediation?: string;\n    }): Promise<Credential | null>;\n}\n\n/** How the browser should surface the authentication ceremony. */\nexport type PasskeyMediation = \"optional\" | \"conditional\" | \"required\" | \"silent\";\n\n/**\n * Server-issued registration options, in the base64url JSON shape every WebAuthn\n * backend speaks (`PublicKeyCredentialCreationOptionsJSON` in the spec).\n *\n * `challenge`, `user.id` and every `excludeCredentials[].id` are **base64url**\n * strings here and `ArrayBuffer`s in the DOM API. Converting them is the plumbing\n * this client owns.\n */\nexport interface PasskeyCreationOptionsJSON {\n    /** Base64url server challenge. Single-use; the server must remember it. */\n    challenge: string;\n    /** Relying party. `id` defaults to the client's `rpId`, then to the origin. */\n    rp: { name: string; id?: string };\n    /** The account. `id` is base64url of an opaque, stable user handle. */\n    user: { id: string; name: string; displayName: string };\n    /** Allowed COSE algorithms. Defaults to {@link DEFAULT_PUB_KEY_CRED_PARAMS}. */\n    pubKeyCredParams?: { type: \"public-key\"; alg: number }[];\n    /** Ceremony timeout in ms. Defaults to the client's `timeoutMs`. */\n    timeout?: number;\n    /** Credentials this user already has, so the authenticator refuses a duplicate. */\n    excludeCredentials?: { id: string; type: \"public-key\"; transports?: string[] }[];\n    /** Resident-key / user-verification / attachment requirements. */\n    authenticatorSelection?: AuthenticatorSelectionCriteria;\n    /** Attestation conveyance. Leave unset (`\"none\"`) unless you verify it. */\n    attestation?: AttestationConveyancePreference;\n    /** Client extension inputs (`credProps`, `largeBlob`, …). */\n    extensions?: AuthenticationExtensionsClientInputs;\n}\n\n/** Server-issued authentication options, base64url JSON. */\nexport interface PasskeyRequestOptionsJSON {\n    /** Base64url server challenge. */\n    challenge: string;\n    /** Relying party id. Defaults to the client's `rpId`, then to the origin. */\n    rpId?: string;\n    /** Ceremony timeout in ms. Defaults to the client's `timeoutMs`. */\n    timeout?: number;\n    /** Restrict to these credentials. **Omit it** for usernameless / autofill flows. */\n    allowCredentials?: { id: string; type: \"public-key\"; transports?: string[] }[];\n    /** Whether the authenticator must verify the user (biometric / PIN). */\n    userVerification?: UserVerificationRequirement;\n    /** Client extension inputs. */\n    extensions?: AuthenticationExtensionsClientInputs;\n}\n\n/** What the client sends to the backend to finish registration. */\nexport interface PasskeyRegistrationJSON {\n    /** Base64url credential id. */\n    id: string;\n    /** Same bytes as `id`; both are sent because servers differ on which they read. */\n    rawId: string;\n    type: \"public-key\";\n    /** `\"platform\"` (this device) or `\"cross-platform\"` (a phone or key). */\n    authenticatorAttachment: string | null;\n    response: {\n        /** Base64url client data — the server re-checks challenge, origin and type. */\n        clientDataJSON: string;\n        /** Base64url attestation object, holding the new public key. */\n        attestationObject: string;\n        /** Transports the authenticator advertises, when the browser exposes them. */\n        transports?: string[];\n        /** COSE algorithm of the new key, when the browser exposes it. */\n        publicKeyAlgorithm?: number;\n        /** Base64url SPKI public key, when the browser exposes it. */\n        publicKey?: string;\n        /** Base64url authenticator data, when the browser exposes it. */\n        authenticatorData?: string;\n    };\n    /** Extension outputs — `credProps.rk` tells you whether it is discoverable. */\n    clientExtensionResults: AuthenticationExtensionsClientOutputs;\n}\n\n/** What the client sends to the backend to finish authentication. */\nexport interface PasskeyAuthenticationJSON {\n    /** Base64url credential id — the server looks up the stored public key by it. */\n    id: string;\n    /** Same bytes as `id`. */\n    rawId: string;\n    type: \"public-key\";\n    /** `\"platform\"` or `\"cross-platform\"`. */\n    authenticatorAttachment: string | null;\n    response: {\n        /** Base64url client data. */\n        clientDataJSON: string;\n        /** Base64url authenticator data, carrying the signature counter. */\n        authenticatorData: string;\n        /** Base64url signature over `authenticatorData || sha256(clientDataJSON)`. */\n        signature: string;\n        /** Base64url user handle — present on discoverable credentials, else null. */\n        userHandle: string | null;\n    };\n    /** Extension outputs. */\n    clientExtensionResults: AuthenticationExtensionsClientOutputs;\n}\n\n/** Per-call knobs for {@link PasskeyClient.register}. */\nexport interface PasskeyRegisterInit {\n    /** Cancel the ceremony (closes the browser sheet). */\n    signal?: AbortSignal;\n}\n\n/** Per-call knobs for {@link PasskeyClient.authenticate}. */\nexport interface PasskeyAuthenticateInit extends PasskeyRegisterInit {\n    /**\n     * `\"conditional\"` is the autofill flow: no modal, the browser offers passkeys\n     * inside a field marked `autocomplete=\"webauthn\"`. Requires a `signal`, and\n     * only one conditional request may be live per page.\n     */\n    mediation?: PasskeyMediation;\n}\n\n/** Framework-free WebAuthn client. Build one with {@link createPasskeyClient}. */\nexport interface PasskeyClient {\n    /** Run the registration ceremony and return the JSON your backend verifies. */\n    register(\n        options: PasskeyCreationOptionsJSON,\n        init?: PasskeyRegisterInit,\n    ): Promise<PasskeyRegistrationJSON>;\n    /** Run the authentication ceremony and return the JSON your backend verifies. */\n    authenticate(\n        options: PasskeyRequestOptionsJSON,\n        init?: PasskeyAuthenticateInit,\n    ): Promise<PasskeyAuthenticationJSON>;\n    /**\n     * Whether this client can run a ceremony at all — the WebAuthn API exists, or a\n     * `credentials` container was injected.\n     */\n    isSupported(): boolean;\n    /** Whether this device has a built-in authenticator (Face ID, Hello, …). */\n    isPlatformAuthenticatorAvailable(): Promise<boolean>;\n    /** Whether autofill-driven (`\"conditional\"`) requests are available. */\n    isConditionalMediationAvailable(): Promise<boolean>;\n}\n\n/** Options for {@link createPasskeyClient}. */\nexport interface CreatePasskeyClientOptions {\n    /**\n     * Default relying-party id, applied when the server options omit one. Must be\n     * the page's domain or a registrable parent of it (`app.acme.com` may use\n     * `acme.com`, never the other way round).\n     */\n    rpId?: string;\n    /** Default ceremony timeout in ms. Default `60_000`. */\n    timeoutMs?: number;\n    /** `navigator.credentials` replacement, for tests. */\n    credentials?: CredentialsContainerLike;\n}\n\n/**\n * COSE algorithms offered when the server sends no `pubKeyCredParams`, in\n * preference order.\n *\n * `-8` is Ed25519, which modern authenticators prefer and which produces the\n * smallest signatures. `-7` is ES256, the one algorithm every WebAuthn\n * authenticator supports. `-257` is RS256, needed for TPM-backed Windows Hello.\n * Offering all three is what avoids a `NotSupportedError` on some device you do\n * not own; a server that cannot verify one of them should send its own list.\n */\nexport const DEFAULT_PUB_KEY_CRED_PARAMS: { type: \"public-key\"; alg: number }[] = [\n    { type: \"public-key\", alg: -8 },\n    { type: \"public-key\", alg: -7 },\n    { type: \"public-key\", alg: -257 },\n];\n\n/** Static members of `PublicKeyCredential` that are not in every DOM lib yet. */\ninterface PublicKeyCredentialStatics {\n    isUserVerifyingPlatformAuthenticatorAvailable?: () => Promise<boolean>;\n    isConditionalMediationAvailable?: () => Promise<boolean>;\n}\n\n/** The browser-supplied extras on an attestation response, all optional. */\ninterface AttestationExtras {\n    getTransports?: () => string[];\n    getPublicKey?: () => ArrayBuffer | null;\n    getPublicKeyAlgorithm?: () => number;\n    getAuthenticatorData?: () => ArrayBuffer;\n}\n\nfunction publicKeyCredentialStatics(): PublicKeyCredentialStatics | undefined {\n    return (globalThis as { PublicKeyCredential?: PublicKeyCredentialStatics }).PublicKeyCredential;\n}\n\n/**\n * Decode a base64url string into bytes.\n *\n * WebAuthn transports every binary field as base64url (`-`/`_`, no padding)\n * because that is what survives JSON, while the DOM API insists on\n * `ArrayBuffer`. Getting this pair wrong — usually by feeding plain base64 to\n * `atob` and losing the last byte — is the classic broken-WebAuthn bug, which is\n * why the SDK owns it instead of leaving it to each app.\n *\n * This is the WebAuthn-facing name for {@link base64ToBytes}; the codec itself is\n * shared, so the padding rule has one implementation rather than three.\n *\n * @param value - Base64url text, with or without `=` padding.\n * @returns The decoded bytes.\n */\nexport function base64UrlToBytes(value: string): Uint8Array<ArrayBuffer> {\n    return base64ToBytes(value);\n}\n\n/**\n * Encode bytes as an unpadded base64url string.\n *\n * Normalises `ArrayBuffer` to a view — which is what the WebAuthn response\n * fields hand over — and delegates the encoding to {@link bytesToBase64}.\n *\n * @param value - Bytes to encode, as a view or a raw buffer.\n * @returns Base64url text, safe to put in JSON and in a URL.\n */\nexport function bytesToBase64Url(value: ArrayBuffer | Uint8Array): string {\n    const bytes = value instanceof Uint8Array ? value : new Uint8Array(value);\n    return bytesToBase64(bytes, { urlSafe: true });\n}\n\n/**\n * Whether this browser exposes WebAuthn at all.\n *\n * Note that \"supported\" is not \"usable\": WebAuthn also requires a secure context,\n * and a device may have no authenticator. Use\n * {@link isPlatformAuthenticatorAvailable} before offering a passkey button.\n */\nexport function isPasskeySupported(): boolean {\n    return (\n        typeof window !== \"undefined\" &&\n        typeof navigator !== \"undefined\" &&\n        navigator.credentials !== undefined &&\n        typeof navigator.credentials.create === \"function\" &&\n        publicKeyCredentialStatics() !== undefined\n    );\n}\n\n/**\n * Whether the device has a **built-in** authenticator — Face ID, Touch ID,\n * Windows Hello, an Android screen lock.\n *\n * This is the check that decides whether \"Entrar com passkey\" may be shown at\n * all. `isPasskeySupported()` is true on a desktop with no biometrics and no\n * security key, and offering a passkey there sends the user into a sheet that can\n * only be cancelled. A `false` here does not forbid passkeys — a phone can still\n * be used over hybrid/QR — it means the flow needs a second step, so present it\n * as \"usar meu celular\", not as one tap.\n *\n * @returns `false` when the API is missing, so a caller never has to null-check.\n */\nexport async function isPlatformAuthenticatorAvailable(): Promise<boolean> {\n    const statics = publicKeyCredentialStatics();\n    if (!statics?.isUserVerifyingPlatformAuthenticatorAvailable) return false;\n    try {\n        return await statics.isUserVerifyingPlatformAuthenticatorAvailable();\n    } catch {\n        return false;\n    }\n}\n\n/**\n * Whether autofill-driven passkeys (`mediation: \"conditional\"`) are available.\n *\n * @returns `false` when the API is missing or throws.\n */\nexport async function isConditionalMediationAvailable(): Promise<boolean> {\n    const statics = publicKeyCredentialStatics();\n    if (!statics?.isConditionalMediationAvailable) return false;\n    try {\n        return await statics.isConditionalMediationAvailable();\n    } catch {\n        return false;\n    }\n}\n\n/**\n * Map a thrown WebAuthn failure onto a {@link PasskeyError}.\n *\n * The secure-context check runs first for the same reason it does in the media\n * classifier: over plain HTTP the whole API is absent or refuses, and reporting\n * \"not supported\" sends a developer hunting for a polyfill for something an\n * `https://` URL fixes.\n *\n * @param error - Whatever `navigator.credentials` rejected with.\n * @param ceremony - Which ceremony was running, for the message.\n * @returns The classified error, ready to throw or to show.\n */\nexport function classifyPasskeyError(error: unknown, ceremony: PasskeyCeremony): PasskeyError {\n    if (error instanceof PasskeyError) return error;\n\n    if (typeof window !== \"undefined\" && !window.isSecureContext) {\n        return new PasskeyError(\"insecure\", \"Passkeys require a secure (HTTPS) connection.\", error);\n    }\n\n    if (error instanceof DOMException) {\n        switch (error.name) {\n            case \"NotAllowedError\":\n                return new PasskeyError(\n                    \"cancelled\",\n                    \"The passkey prompt was dismissed or timed out. The browser does not say which — it must not reveal whether a credential exists.\",\n                    error,\n                );\n            case \"InvalidStateError\":\n                return new PasskeyError(\n                    \"already-registered\",\n                    \"This device already has a passkey for this account. Sign in with it instead of creating another.\",\n                    error,\n                );\n            case \"NotSupportedError\":\n                return new PasskeyError(\n                    \"not-supported\",\n                    \"No authenticator here supports the requested algorithms. Check the server's pubKeyCredParams.\",\n                    error,\n                );\n            case \"SecurityError\":\n                return new PasskeyError(\n                    \"rp-mismatch\",\n                    \"The relying-party id does not match this origin. rp.id must be the page's domain or a registrable parent of it.\",\n                    error,\n                );\n            case \"AbortError\":\n                return new PasskeyError(\"aborted\", \"The passkey request was aborted.\", error);\n        }\n    }\n\n    if (error instanceof TypeError) {\n        return new PasskeyError(\n            \"invalid-options\",\n            `The ${ceremony} options the server sent are malformed. Check that challenge, user.id and credential ids are base64url.`,\n            error,\n        );\n    }\n\n    return new PasskeyError(\n        \"unknown\",\n        error instanceof Error\n            ? error.message\n            : `Unexpected error during the passkey ${ceremony} ceremony.`,\n        error,\n    );\n}\n\nfunction toDescriptors(\n    list: { id: string; type: \"public-key\"; transports?: string[] }[] | undefined,\n): PublicKeyCredentialDescriptor[] | undefined {\n    if (!list) return undefined;\n    return list.map((item) => ({\n        id: base64UrlToBytes(item.id),\n        type: item.type,\n        transports: item.transports as AuthenticatorTransport[] | undefined,\n    }));\n}\n\n/**\n * Build a WebAuthn client: the base64url ↔ `ArrayBuffer` plumbing, the two\n * ceremonies, and one classified error type.\n *\n * ## What your backend must do\n *\n * This is the **client half only**, and a WebAuthn client that documents only its\n * own half is unusable. Four routes are yours to implement:\n *\n * 1. `POST /webauthn/register/begin` → a {@link PasskeyCreationOptionsJSON}. Mint a\n *    random `challenge` (≥16 bytes), store it against the session, and list the\n *    user's existing credentials in `excludeCredentials`.\n * 2. `POST /webauthn/register/finish` ← a {@link PasskeyRegistrationJSON}. Verify\n *    the challenge, `origin` and `type` inside `clientDataJSON`, parse the\n *    attestation object, then store the credential id, public key and signature\n *    counter.\n * 3. `POST /webauthn/signin/begin` → a {@link PasskeyRequestOptionsJSON}. New\n *    challenge. Omit `allowCredentials` for a usernameless or autofill flow.\n * 4. `POST /webauthn/signin/finish` ← a {@link PasskeyAuthenticationJSON}. Look the\n *    credential up by `id`, verify the signature over\n *    `authenticatorData || sha256(clientDataJSON)`, and reject a signature counter\n *    that did not grow (a clone). Only then issue your session token.\n *\n * @param options - Defaults applied when the server options omit them.\n * @returns A client usable from anywhere — React, a plain form, a worker.\n *\n * @example\n * const passkeys = createPasskeyClient({ rpId: \"acme.com\" });\n *\n * const options = await api.post(\"/webauthn/register/begin\");\n * const credential = await passkeys.register(options);\n * await api.post(\"/webauthn/register/finish\", { body: credential });\n */\nexport function createPasskeyClient(options: CreatePasskeyClientOptions = {}): PasskeyClient {\n    const { rpId, timeoutMs = 60_000, credentials } = options;\n\n    function container(): CredentialsContainerLike {\n        if (credentials) return credentials;\n        if (!isPasskeySupported()) {\n            throw new PasskeyError(\n                \"unsupported\",\n                typeof window !== \"undefined\" && !window.isSecureContext\n                    ? \"Passkeys require a secure (HTTPS) connection.\"\n                    : \"This browser does not support passkeys (WebAuthn).\",\n            );\n        }\n        return navigator.credentials as unknown as CredentialsContainerLike;\n    }\n\n    async function register(\n        json: PasskeyCreationOptionsJSON,\n        init: PasskeyRegisterInit = {},\n    ): Promise<PasskeyRegistrationJSON> {\n        const api = container();\n        const publicKey: PublicKeyCredentialCreationOptions = {\n            challenge: base64UrlToBytes(json.challenge),\n            rp: { name: json.rp.name, id: json.rp.id ?? rpId },\n            user: {\n                id: base64UrlToBytes(json.user.id),\n                name: json.user.name,\n                displayName: json.user.displayName,\n            },\n            pubKeyCredParams: json.pubKeyCredParams ?? DEFAULT_PUB_KEY_CRED_PARAMS,\n            timeout: json.timeout ?? timeoutMs,\n            excludeCredentials: toDescriptors(json.excludeCredentials),\n            authenticatorSelection: json.authenticatorSelection,\n            attestation: json.attestation,\n            extensions: json.extensions,\n        };\n\n        let credential: Credential | null;\n        try {\n            credential = await api.create({ publicKey, signal: init.signal });\n        } catch (error) {\n            throw classifyPasskeyError(error, \"register\");\n        }\n        if (!credential) {\n            throw new PasskeyError(\"unknown\", \"The authenticator returned no credential.\");\n        }\n\n        const typed = credential as PublicKeyCredential;\n        const response = typed.response as AuthenticatorAttestationResponse & AttestationExtras;\n        const publicKeyBytes = response.getPublicKey?.();\n\n        return {\n            id: typed.id,\n            rawId: bytesToBase64Url(typed.rawId),\n            type: \"public-key\",\n            authenticatorAttachment: typed.authenticatorAttachment ?? null,\n            response: {\n                clientDataJSON: bytesToBase64Url(response.clientDataJSON),\n                attestationObject: bytesToBase64Url(response.attestationObject),\n                transports: response.getTransports?.(),\n                publicKeyAlgorithm: response.getPublicKeyAlgorithm?.(),\n                publicKey: publicKeyBytes ? bytesToBase64Url(publicKeyBytes) : undefined,\n                authenticatorData: response.getAuthenticatorData\n                    ? bytesToBase64Url(response.getAuthenticatorData())\n                    : undefined,\n            },\n            clientExtensionResults: typed.getClientExtensionResults(),\n        };\n    }\n\n    async function authenticate(\n        json: PasskeyRequestOptionsJSON,\n        init: PasskeyAuthenticateInit = {},\n    ): Promise<PasskeyAuthenticationJSON> {\n        const api = container();\n        const publicKey: PublicKeyCredentialRequestOptions = {\n            challenge: base64UrlToBytes(json.challenge),\n            rpId: json.rpId ?? rpId,\n            timeout: json.timeout ?? timeoutMs,\n            allowCredentials: toDescriptors(json.allowCredentials),\n            userVerification: json.userVerification,\n            extensions: json.extensions,\n        };\n\n        let credential: Credential | null;\n        try {\n            credential = await api.get({\n                publicKey,\n                signal: init.signal,\n                mediation: init.mediation,\n            });\n        } catch (error) {\n            throw classifyPasskeyError(error, \"authenticate\");\n        }\n        if (!credential) {\n            throw new PasskeyError(\"unknown\", \"The authenticator returned no credential.\");\n        }\n\n        const typed = credential as PublicKeyCredential;\n        const response = typed.response as AuthenticatorAssertionResponse;\n\n        return {\n            id: typed.id,\n            rawId: bytesToBase64Url(typed.rawId),\n            type: \"public-key\",\n            authenticatorAttachment: typed.authenticatorAttachment ?? null,\n            response: {\n                clientDataJSON: bytesToBase64Url(response.clientDataJSON),\n                authenticatorData: bytesToBase64Url(response.authenticatorData),\n                signature: bytesToBase64Url(response.signature),\n                userHandle: response.userHandle ? bytesToBase64Url(response.userHandle) : null,\n            },\n            clientExtensionResults: typed.getClientExtensionResults(),\n        };\n    }\n\n    return {\n        register,\n        authenticate,\n        isSupported: () => credentials !== undefined || isPasskeySupported(),\n        isPlatformAuthenticatorAvailable,\n        isConditionalMediationAvailable,\n    };\n}\n"],"mappings":"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"}