import { describe, expect, it } from "vitest"; import { betterAuth } from "better-auth"; import { memoryAdapter } from "better-auth/adapters/memory"; import { genericOAuth } from "better-auth/plugins"; const origin = "https://guide.test"; function createReplica(database: Record[]>) { return betterAuth({ baseURL: origin, secret: "a-shared-test-secret-with-enough-entropy-123", database: memoryAdapter(database), rateLimit: { enabled: false }, plugins: [genericOAuth({ config: [{ providerId: "sudloh", clientId: "test-client", clientSecret: "test-secret", authorizationUrl: "https://account.test/authorize", tokenUrl: "https://account.test/token", getToken: async () => ({ accessToken: "test-access-token", accessTokenExpiresAt: new Date(Date.now() + 3600_000) }), getUserInfo: async () => ({ id: "test-subject", email: "user@test.invalid", emailVerified: true, name: "Test User" }), }] })], }); } describe("Sudloh OAuth callback", () => { it("completes across replicas, creates the Guide session, and consumes state once", async () => { const database = { user: [], session: [], account: [], verification: [] }; const first = createReplica(database); const second = createReplica(database); const start = await first.handler(new Request(`${origin}/api/auth/sign-in/social`, { method: "POST", headers: { Origin: origin, "Content-Type": "application/json" }, body: JSON.stringify({ provider: "sudloh", callbackURL: "/profile" }), })); expect(start.status).toBe(200); const authorization = new URL((await start.json()).url); expect(authorization.searchParams.get("code_challenge_method")).toBe("S256"); expect(authorization.searchParams.get("code_challenge")).toBeTruthy(); const stateCookie = start.headers.get("set-cookie")?.split(";", 1)[0]; expect(stateCookie).toBeTruthy(); const callbackURL = new URL(`${origin}/api/auth/callback/sudloh`); callbackURL.searchParams.set("code", "test-code"); callbackURL.searchParams.set("state", authorization.searchParams.get("state")!); const callback = await second.handler(new Request(callbackURL, { headers: { Cookie: stateCookie! }, })); expect(callback.status).toBe(302); expect(callback.headers.get("location")).toBe("/profile"); const sessionCookie = callback.headers.getSetCookie() .find((cookie) => cookie.includes("session_token="))?.split(";", 1)[0]; const session = await second.api.getSession({ headers: new Headers({ Cookie: sessionCookie! }) }); expect(session?.user.email).toBe("user@test.invalid"); const replay = await first.handler(new Request(callbackURL, { headers: { Cookie: stateCookie! }, })); expect(replay.headers.get("location")).toContain("state_mismatch"); }); it("rejects a callback without state before exchanging a code", async () => { const auth = createReplica({ user: [], session: [], account: [], verification: [] }); const response = await auth.handler(new Request(`${origin}/api/auth/callback/sudloh?code=test-code`)); expect(response.status).toBe(302); expect(response.headers.get("location")).toContain("state_not_found"); }); });