From 126d4ac3413f91da8a200b824910632d4b2cf5f8 Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Mon, 13 Jul 2026 09:49:45 -0700 Subject: [PATCH] Fix: remove debug logging from nextauth --- .../pages/api/auth/[...nextauth].test.js | 56 ++++++++++++++++++- src/pages/api/auth/[...nextauth].js | 15 ++--- 2 files changed, 63 insertions(+), 8 deletions(-) diff --git a/src/__tests__/pages/api/auth/[...nextauth].test.js b/src/__tests__/pages/api/auth/[...nextauth].test.js index 2a510d514..b6a6416af 100644 --- a/src/__tests__/pages/api/auth/[...nextauth].test.js +++ b/src/__tests__/pages/api/auth/[...nextauth].test.js @@ -1,19 +1,29 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; -const { nextAuthMock } = vi.hoisted(() => ({ +const { debugMock, errorMock, nextAuthMock, warnMock } = vi.hoisted(() => ({ + debugMock: vi.fn(), + errorMock: vi.fn(), nextAuthMock: vi.fn((options) => ({ options })), + warnMock: vi.fn(), })); vi.mock("next-auth", () => ({ default: nextAuthMock, })); +vi.mock("utils/logger", () => ({ + default: vi.fn(() => ({ debug: debugMock, error: errorMock, warn: warnMock })), +})); + describe("pages/api/auth/[...nextauth]", () => { const originalEnv = process.env; beforeEach(() => { vi.resetModules(); + debugMock.mockClear(); + errorMock.mockClear(); nextAuthMock.mockClear(); + warnMock.mockClear(); process.env = { ...originalEnv }; delete process.env.NEXTAUTH_SECRET; delete process.env.NEXTAUTH_URL; @@ -27,6 +37,50 @@ describe("pages/api/auth/[...nextauth]", () => { expect(mod.default.options.pages?.signIn).toBe("/auth/signin"); }); + it("does not enable NextAuth's raw debug logger", async () => { + const mod = await import("pages/api/auth/[...nextauth]"); + + expect(mod.default.options).not.toHaveProperty("debug"); + }); + + it("routes sanitized NextAuth logs through the Homepage logger", async () => { + const mod = await import("pages/api/auth/[...nextauth]"); + const sensitiveMetadata = { + clientSecret: "sensitive-client-secret", + access_token: "sensitive-access-token", + id_token: "sensitive-id-token", + }; + + mod.default.options.logger.error("OAUTH_CALLBACK_ERROR", sensitiveMetadata); + mod.default.options.logger.warn("NEXTAUTH_URL", sensitiveMetadata); + mod.default.options.logger.debug("OAUTH_CALLBACK_RESPONSE", sensitiveMetadata); + + expect(errorMock).toHaveBeenCalledWith("%s", "OAUTH_CALLBACK_ERROR"); + expect(warnMock).toHaveBeenCalledWith("%s", "NEXTAUTH_URL"); + expect(debugMock).toHaveBeenCalledWith("%s", "OAUTH_CALLBACK_RESPONSE"); + expect(JSON.stringify([...errorMock.mock.calls, ...warnMock.mock.calls, ...debugMock.mock.calls])).not.toContain( + "sensitive", + ); + }); + + it("logs only sanitized authentication lifecycle events", async () => { + const mod = await import("pages/api/auth/[...nextauth]"); + + await mod.default.options.events.signIn({ + account: { + provider: "homepage-oidc", + access_token: "sensitive-access-token", + id_token: "sensitive-id-token", + }, + user: { email: "sensitive@example.com" }, + }); + await mod.default.options.events.signOut({ token: { sub: "sensitive-user-id" } }); + + expect(debugMock).toHaveBeenNthCalledWith(1, "Sign in via provider '%s'", "homepage-oidc"); + expect(debugMock).toHaveBeenNthCalledWith(2, "Sign out"); + expect(JSON.stringify(debugMock.mock.calls)).not.toContain("sensitive"); + }); + it("maps HOMEPAGE_AUTH_SECRET and HOMEPAGE_EXTERNAL_URL to NextAuth envs", async () => { process.env.HOMEPAGE_AUTH_SECRET = "secret"; process.env.HOMEPAGE_EXTERNAL_URL = "https://homepage.example"; diff --git a/src/pages/api/auth/[...nextauth].js b/src/pages/api/auth/[...nextauth].js index 1b29f81a4..42d687620 100644 --- a/src/pages/api/auth/[...nextauth].js +++ b/src/pages/api/auth/[...nextauth].js @@ -3,6 +3,8 @@ import { timingSafeEqual } from "node:crypto"; import NextAuth from "next-auth"; import CredentialsProvider from "next-auth/providers/credentials"; +import createLogger from "utils/logger"; + const authEnabled = Boolean(process.env.HOMEPAGE_AUTH_ENABLED); const issuer = process.env.HOMEPAGE_OIDC_ISSUER; const clientId = process.env.HOMEPAGE_OIDC_CLIENT_ID; @@ -100,16 +102,15 @@ export const authOptions = { pages: { signIn: "/auth/signin", }, - debug: true, logger: { - error: (...args) => console.error("[nextauth][error]", ...args), - warn: (...args) => console.warn("[nextauth][warn]", ...args), - debug: (...args) => console.debug("[nextauth][debug]", ...args), + error: (code) => createLogger("nextauth").error("%s", code), + warn: (code) => createLogger("nextauth").warn("%s", code), + debug: (code) => createLogger("nextauth").debug("%s", code), }, events: { - signIn: async (message) => console.debug("[nextauth][event][signIn]", message), - signOut: async (message) => console.debug("[nextauth][event][signOut]", message), - error: async (message) => console.error("[nextauth][event][error]", message), + signIn: async ({ account }) => + createLogger("nextauth").debug("Sign in via provider '%s'", account?.provider ?? "unknown"), + signOut: async () => createLogger("nextauth").debug("Sign out"), }, };