import type { InternalOptions, RequestInternal, ResponseInternal, User, } from "../../types.js" import type { Cookie, SessionStore } from "../utils/cookie.js" import { getLoggedInUser } from "../utils/session.js" import { assertInternalOptionsWebAuthn, inferWebAuthnOptions, getAuthenticationResponse, getRegistrationResponse, } from "../utils/webauthn-utils.js" /** * Returns authentication or registration options for a WebAuthn flow * depending on the parameters provided. */ export async function webAuthnOptions( request: RequestInternal, options: InternalOptions, sessionStore: SessionStore, cookies: Cookie[] ): Promise { // Return an error if the adapter is missing or if the provider // is not a webauthn provider. const narrowOptions = assertInternalOptionsWebAuthn(options) const { provider } = narrowOptions // Extract the action from the query parameters const { action } = (request.query ?? {}) as Record // Action must be either "register", "authenticate", or undefined if ( action !== "register" && action !== "authenticate" && typeof action !== "undefined" ) { return { status: 400, body: { error: "Invalid action" }, cookies, headers: { "Content-Type": "application/json", }, } } // Get the user info from the session const sessionUser = await getLoggedInUser(options, sessionStore) // Extract user info from request // If session user exists, we don't need to call getUserInfo const getUserInfoResponse = sessionUser ? { user: sessionUser, exists: true, } : await provider.getUserInfo(options, request) const userInfo = getUserInfoResponse?.user // Make a decision on what kind of webauthn options to return const decision = inferWebAuthnOptions( action, !!sessionUser, getUserInfoResponse ) switch (decision) { case "authenticate": return getAuthenticationResponse( narrowOptions, request, userInfo, cookies ) case "register": if (typeof userInfo?.email === "string") { return getRegistrationResponse( narrowOptions, request, userInfo as User & { email: string }, cookies ) } default: return { status: 400, body: { error: "Invalid request" }, cookies, headers: { "Content-Type": "application/json", }, } } }