import { Hex, PublicKey } from 'ox' import { Authentication, type Types } from 'ox/webauthn' /** Credential request options. */ export type Options = Types.CredentialRequestOptions /** Authentication response. */ export type Response = Authentication.Response /** * Generates serialized `PublicKeyCredentialRequestOptions` for authentication. * * A random 32-byte challenge is generated by default. The challenge is * returned alongside the options so it can be stored for later verification. * * @example * ```ts * import { Authentication } from 'webauthx/server' * * async function handler(request: Request) { * const { challenge, options } = Authentication.getOptions({ * credentialId: storedCredential.id, * rpId: 'example.com', * }) * await db.storeChallenge(challenge) * return Response.json(options) * } * ``` */ export function getOptions(options: getOptions.Options = {}): getOptions.ReturnType { const challenge = options.challenge ?? Hex.random(32) const serialized = Authentication.serializeOptions( Authentication.getOptions({ ...options, challenge }), ) return { challenge, options: serialized } } export declare namespace getOptions { type Options = Omit & { challenge?: Hex.Hex | undefined } type ReturnType = { challenge: Hex.Hex options: Types.CredentialRequestOptions } type ErrorType = Authentication.getOptions.ErrorType | Authentication.serializeOptions.ErrorType } /** * Verifies a serialized authentication response from the client. * * Deserializes the response, then validates the rpIdHash, origin, * challenge, and P256 signature. * * @example * ```ts * import { Authentication } from 'webauthx/server' * import { db } from './db' * * async function handler(request: Request) { * const response = await request.json() * const challenge = await db.consumeChallenge(request) * const credential = await db.getCredential(response.id) * const valid = Authentication.verify(response, { * challenge, * publicKey: credential.publicKey, * origin: 'https://example.com', * rpId: 'example.com', * }) * } * ``` */ export function verify(response: Response, options: verify.Options): boolean { const deserialized = Authentication.deserializeResponse(response) return Authentication.verify({ ...options, metadata: deserialized.metadata, publicKey: PublicKey.from(options.publicKey), signature: deserialized.signature, }) } export declare namespace verify { type Options = Omit & { publicKey: Hex.Hex } type ErrorType = Authentication.verify.ErrorType | Authentication.deserializeResponse.ErrorType }