UNPKG

payload-auth-plugin

Version:
83 lines (82 loc) 2.69 kB
// src/core/protocols/passkey/authentication.ts import { parseCookies } from "payload"; import { generateAuthenticationOptions, verifyAuthenticationResponse } from "@simplewebauthn/server"; import { PasskeyVerificationAPIError } from "../../errors/apiErrors.js"; import { MissingOrInvalidSession } from "../../errors/consoleErrors.js"; import { hashCode } from "../../utils/hash.js"; async function GeneratePasskeyAuthentication(request, rpID) { const { data } = await request.json(); const registrationOptions = { rpID, timeout: 60000, allowCredentials: [ { id: data.passkey.credentialId, transports: data.passkey.transports } ], userVerification: "required" }; const options = await generateAuthenticationOptions(registrationOptions); const cookieMaxage = new Date(Date.now() + 300 * 1000); const cookies = []; cookies.push(`__session-webpk-challenge=${options.challenge};Path=/;HttpOnly;SameSite=lax;Expires=${cookieMaxage.toUTCString()}`); const res = new Response(JSON.stringify({ options }), { status: 201 }); cookies.forEach((cookie) => { res.headers.append("Set-Cookie", cookie); }); return res; } async function VerifyPasskeyAuthentication(request, rpID, session_callback) { try { const parsedCookies = parseCookies(request.headers); const challenge = parsedCookies.get("__session-webpk-challenge"); if (!challenge) { throw new MissingOrInvalidSession; } const { data } = await request.json(); const verification = await verifyAuthenticationResponse({ response: data.authentication, expectedChallenge: challenge, expectedOrigin: request.payload.config.serverURL, expectedRPID: rpID, credential: { id: data.passkey.credentialId, publicKey: new Uint8Array(Object.values(data.passkey.publicKey)), counter: data.passkey.counter, transports: data.passkey.transports } }); if (!verification.verified) { throw new PasskeyVerificationAPIError; } const { credentialID, credentialDeviceType, credentialBackedUp, newCounter } = verification.authenticationInfo; return await session_callback({ sub: hashCode(data.email + request.payload.secret).toString(), name: "", picture: "", email: data.email, passKey: { credentialId: credentialID, counter: newCounter, deviceType: credentialDeviceType, backedUp: credentialBackedUp } }); } catch (error) { console.error(error); return Response.json({}); } } export { VerifyPasskeyAuthentication, GeneratePasskeyAuthentication };