From df1281bec024fd37ea13c78fcf8fd14817968f95 Mon Sep 17 00:00:00 2001 From: ouwargui Date: Fri, 10 Oct 2025 03:15:27 -0300 Subject: [PATCH] fix(passkey): add test for verifying passkey authentication and returning user --- packages/passkey/src/passkey.test.ts | 97 +++++++++++++++++++++++++++- 1 file changed, 96 insertions(+), 1 deletion(-) diff --git a/packages/passkey/src/passkey.test.ts b/packages/passkey/src/passkey.test.ts index 94bcf01188..8314c78060 100644 --- a/packages/passkey/src/passkey.test.ts +++ b/packages/passkey/src/passkey.test.ts @@ -1,10 +1,19 @@ import { createAuthClient } from "better-auth/client"; import { getTestInstance } from "better-auth/test"; -import { describe, expect, it } from "vitest"; +import { describe, expect, it, vi } from "vitest"; import type { Passkey } from "."; import { passkey } from "."; import { passkeyClient } from "./client"; +vi.mock("@simplewebauthn/server", async (importOriginal) => { + const actual = + await importOriginal(); + return { + ...actual, + verifyAuthenticationResponse: vi.fn(), + }; +}); + describe("passkey", async () => { const { auth, signInWithTestUser, customFetchImpl } = await getTestInstance({ plugins: [passkey()], @@ -121,4 +130,90 @@ describe("passkey", async () => { }); expect(deleteResult).toBe(null); }); + it("should verify passkey authentication and return user", async () => { + const { headers, user } = await signInWithTestUser(); + const context = await auth.$context; + + await context.adapter.create, Passkey>({ + model: "passkey", + data: { + userId: user.id, + publicKey: "mockPublicKey", + name: "mockName", + counter: 0, + deviceType: "singleDevice", + credentialID: "mockCredentialID", + createdAt: new Date(), + backedUp: false, + transports: "mockTransports", + aaguid: "mockAAGUID", + } satisfies Omit, + }); + + const client = createAuthClient({ + plugins: [passkeyClient()], + baseURL: "http://localhost:3000/api/auth", + fetchOptions: { + headers: headers, + customFetchImpl, + }, + }); + + let passkeyCookie = ""; + await client.passkey.generateAuthenticateOptions({ + fetchOptions: { + onResponse(context) { + const setCookie = context.response.headers.get("Set-Cookie"); + if (setCookie) { + passkeyCookie = setCookie; + } + }, + }, + }); + + // Mock the verification response + const { verifyAuthenticationResponse } = await import( + "@simplewebauthn/server" + ); + const mockedVerify = verifyAuthenticationResponse as unknown as ReturnType< + typeof vi.fn + >; + mockedVerify.mockResolvedValueOnce({ + verified: true, + authenticationInfo: { + newCounter: 1, + }, + }); + + const currentCookie = (headers as any).cookie || ""; + const combinedCookie = currentCookie + ? `${currentCookie}; ${passkeyCookie}` + : passkeyCookie; + + const response = await auth.api.verifyPasskeyAuthentication({ + headers: { + ...headers, + cookie: combinedCookie, + origin: "http://localhost:3000", + }, + body: { + response: { + id: "mockCredentialID", + rawId: "mockRawId", + response: { + clientDataJSON: "mockClientDataJSON", + authenticatorData: "mockAuthenticatorData", + signature: "mockSignature", + userHandle: "mockUserHandle", + }, + type: "public-key", + clientExtensionResults: {}, + }, + }, + }); + + expect(response).toHaveProperty("user"); + expect(response.user).toHaveProperty("id", user.id); + expect(response.user).toHaveProperty("email", user.email); + }); });