From 109aaa5260a2dc70b249cd1454f86bf31d1c7629 Mon Sep 17 00:00:00 2001 From: Johny Date: Fri, 10 Apr 2026 21:04:54 +0100 Subject: [PATCH 1/3] fix: configure github oauth issuer --- apps/web/src/server/auth.ts | 4 ++ apps/web/src/server/auth.unit.test.ts | 58 +++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) create mode 100644 apps/web/src/server/auth.unit.test.ts diff --git a/apps/web/src/server/auth.ts b/apps/web/src/server/auth.ts index 1f53f4c5..ccd9d388 100644 --- a/apps/web/src/server/auth.ts +++ b/apps/web/src/server/auth.ts @@ -14,6 +14,8 @@ import { sendSignUpEmail } from "~/server/mailer"; import { env } from "~/env"; import { db } from "~/server/db"; +const GITHUB_OAUTH_ISSUER = "https://github.com/login/oauth"; + /** * Module augmentation for `next-auth` types. Allows us to add custom properties to the `session` * object and keep type safety. @@ -54,6 +56,8 @@ function getProviders() { GitHubProvider({ clientId: env.GITHUB_ID, clientSecret: env.GITHUB_SECRET, + // GitHub now includes `iss` on OAuth callbacks, so NextAuth needs the expected issuer. + issuer: GITHUB_OAUTH_ISSUER, allowDangerousEmailAccountLinking: true, authorization: { params: { diff --git a/apps/web/src/server/auth.unit.test.ts b/apps/web/src/server/auth.unit.test.ts new file mode 100644 index 00000000..8268bd62 --- /dev/null +++ b/apps/web/src/server/auth.unit.test.ts @@ -0,0 +1,58 @@ +import { describe, expect, it, vi } from "vitest"; + +const { githubProviderMock } = vi.hoisted(() => ({ + githubProviderMock: vi.fn((options: Record) => ({ + id: "github", + type: "oauth", + options, + })), +})); + +vi.mock("next-auth", () => ({ + getServerSession: vi.fn(), +})); + +vi.mock("@auth/prisma-adapter", () => ({ + PrismaAdapter: vi.fn(() => ({})), +})); + +vi.mock("next-auth/providers/github", () => ({ + default: githubProviderMock, +})); + +vi.mock("next-auth/providers/google", () => ({ + default: vi.fn(), +})); + +vi.mock("next-auth/providers/email", () => ({ + default: vi.fn(), +})); + +vi.mock("~/server/db", () => ({ + db: {}, +})); + +vi.mock("~/server/mailer", () => ({ + sendSignUpEmail: vi.fn(), +})); + +vi.mock("~/env", () => ({ + env: { + GITHUB_ID: "github-client-id", + GITHUB_SECRET: "github-client-secret", + }, +})); + +import "~/server/auth"; + +describe("authOptions", () => { + it("configures the GitHub provider with an explicit issuer", () => { + expect(githubProviderMock).toHaveBeenCalledWith( + expect.objectContaining({ + clientId: "github-client-id", + clientSecret: "github-client-secret", + issuer: "https://github.com/login/oauth", + }), + ); + }); +}); From bb91cf9bbd57ca5fc23e9ba57891543394ed4015 Mon Sep 17 00:00:00 2001 From: Johny Date: Fri, 10 Apr 2026 21:19:18 +0100 Subject: [PATCH 2/3] fix: set cloud-mode flag in test env mock --- apps/web/src/server/auth.unit.test.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/web/src/server/auth.unit.test.ts b/apps/web/src/server/auth.unit.test.ts index 8268bd62..ef7ea0bb 100644 --- a/apps/web/src/server/auth.unit.test.ts +++ b/apps/web/src/server/auth.unit.test.ts @@ -40,6 +40,7 @@ vi.mock("~/env", () => ({ env: { GITHUB_ID: "github-client-id", GITHUB_SECRET: "github-client-secret", + NEXT_PUBLIC_IS_CLOUD: true, }, })); From c014f7fbeab33640334786bb1a2a11aec15408e4 Mon Sep 17 00:00:00 2001 From: Johny Date: Fri, 10 Apr 2026 21:39:56 +0100 Subject: [PATCH 3/3] test: stabilize auth issuer unit test --- apps/web/src/server/auth.unit.test.ts | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/apps/web/src/server/auth.unit.test.ts b/apps/web/src/server/auth.unit.test.ts index ef7ea0bb..50682cb1 100644 --- a/apps/web/src/server/auth.unit.test.ts +++ b/apps/web/src/server/auth.unit.test.ts @@ -1,13 +1,5 @@ import { describe, expect, it, vi } from "vitest"; -const { githubProviderMock } = vi.hoisted(() => ({ - githubProviderMock: vi.fn((options: Record) => ({ - id: "github", - type: "oauth", - options, - })), -})); - vi.mock("next-auth", () => ({ getServerSession: vi.fn(), })); @@ -16,10 +8,6 @@ vi.mock("@auth/prisma-adapter", () => ({ PrismaAdapter: vi.fn(() => ({})), })); -vi.mock("next-auth/providers/github", () => ({ - default: githubProviderMock, -})); - vi.mock("next-auth/providers/google", () => ({ default: vi.fn(), })); @@ -44,16 +32,21 @@ vi.mock("~/env", () => ({ }, })); -import "~/server/auth"; +import { authOptions } from "~/server/auth"; describe("authOptions", () => { it("configures the GitHub provider with an explicit issuer", () => { - expect(githubProviderMock).toHaveBeenCalledWith( - expect.objectContaining({ + const githubProvider = authOptions.providers.find( + (provider) => provider.id === "github", + ); + + expect(githubProvider).toMatchObject({ + id: "github", + options: { clientId: "github-client-id", clientSecret: "github-client-secret", issuer: "https://github.com/login/oauth", - }), - ); + }, + }); }); });