From 4547fb2f795192a85b25e3919b6a8a280ce18eff Mon Sep 17 00:00:00 2001 From: ajnart Date: Wed, 22 Jul 2026 23:08:36 +0200 Subject: [PATCH] test(auth): cover OIDC profile verification wiring --- .../auth/providers/oidc/verified-email.ts | 7 +- .../auth/providers/test/oidc-provider.spec.ts | 84 ++++++++++++++++--- 2 files changed, 79 insertions(+), 12 deletions(-) diff --git a/packages/auth/providers/oidc/verified-email.ts b/packages/auth/providers/oidc/verified-email.ts index 6aad25dec..85f18b64c 100644 --- a/packages/auth/providers/oidc/verified-email.ts +++ b/packages/auth/providers/oidc/verified-email.ts @@ -1,8 +1,11 @@ export const assertVerifiedEmailForCredentialsLinking = ( - profile: { email_verified?: unknown }, + profile: { email?: unknown; email_verified?: unknown }, isCredentialsLinkingEnabled: boolean, ) => { - if (isCredentialsLinkingEnabled && profile.email_verified !== true) { + if ( + isCredentialsLinkingEnabled && + (profile.email_verified !== true || typeof profile.email !== "string" || profile.email.trim().length === 0) + ) { throw new Error("OIDC provider did not return a verified email while credentials linking is enabled"); } }; diff --git a/packages/auth/providers/test/oidc-provider.spec.ts b/packages/auth/providers/test/oidc-provider.spec.ts index 9976218d9..fa253ecba 100644 --- a/packages/auth/providers/test/oidc-provider.spec.ts +++ b/packages/auth/providers/test/oidc-provider.spec.ts @@ -1,22 +1,86 @@ -import { describe, expect, test } from "vitest"; +import { afterEach, describe, expect, test, vi } from "vitest"; +import { OidcProvider } from "../oidc/oidc-provider"; import { assertVerifiedEmailForCredentialsLinking } from "../oidc/verified-email"; +const mockEnv = vi.hoisted(() => ({ + AUTH_OIDC_CLIENT_ID: "client-id", + AUTH_OIDC_CLIENT_NAME: "OIDC", + AUTH_OIDC_CLIENT_SECRET: "client-secret", + AUTH_OIDC_ENABLE_DANGEROUS_ACCOUNT_LINKING: false, + AUTH_OIDC_ENABLE_DANGEROUS_CREDENTIALS_LINKING: false, + AUTH_OIDC_FORCE_USERINFO: false, + AUTH_OIDC_ISSUER: "https://example.com", + AUTH_OIDC_NAME_ATTRIBUTE_OVERWRITE: undefined, + AUTH_OIDC_SCOPE_OVERWRITE: "openid email profile", + AUTH_OIDC_TOKEN_ENDPOINT_AUTH_METHOD: "client_secret_basic" as const, +})); + +vi.mock("../../env", () => ({ env: mockEnv })); +vi.mock("next-auth", () => ({ customFetch: Symbol("customFetch") })); + +afterEach(() => { + mockEnv.AUTH_OIDC_ENABLE_DANGEROUS_CREDENTIALS_LINKING = false; +}); + describe("assertVerifiedEmailForCredentialsLinking", () => { test("allows a strictly verified OIDC email when credentials linking is enabled", () => { - expect(() => assertVerifiedEmailForCredentialsLinking({ email_verified: true }, true)).not.toThrow(); + expect(() => + assertVerifiedEmailForCredentialsLinking({ email: "test@example.com", email_verified: true }, true), + ).not.toThrow(); }); - test.each([{ email_verified: false }, { email_verified: "true" }, {}])( - "rejects an OIDC profile without a strictly verified email when credentials linking is enabled", - (profile) => { - expect(() => assertVerifiedEmailForCredentialsLinking(profile, true)).toThrow( - "OIDC provider did not return a verified email while credentials linking is enabled", - ); - }, - ); + test.each([ + { email: "test@example.com", email_verified: false }, + { email: "test@example.com", email_verified: "true" }, + { email_verified: true }, + { email: null, email_verified: true }, + { email: " ", email_verified: true }, + {}, + ])("rejects an OIDC profile without a strictly verified email when credentials linking is enabled", (profile) => { + expect(() => assertVerifiedEmailForCredentialsLinking(profile, true)).toThrow( + "OIDC provider did not return a verified email while credentials linking is enabled", + ); + }); test("does not require the claim when credentials linking is disabled", () => { expect(() => assertVerifiedEmailForCredentialsLinking({}, false)).not.toThrow(); }); + + test("OIDC provider rejects an unverified profile when credentials linking is enabled", () => { + mockEnv.AUTH_OIDC_ENABLE_DANGEROUS_CREDENTIALS_LINKING = true; + const provider = OidcProvider(null); + const mapProfile = provider.profile; + if (!mapProfile) throw new Error("Expected OIDC profile mapper to be defined"); + + expect(() => + mapProfile( + { + sub: "subject", + preferred_username: "test", + email: "test@example.com", + email_verified: false, + }, + {}, + ), + ).toThrow("OIDC provider did not return a verified email while credentials linking is enabled"); + }); + + test("OIDC provider accepts an unverified profile when credentials linking is disabled", () => { + const provider = OidcProvider(null); + const mapProfile = provider.profile; + if (!mapProfile) throw new Error("Expected OIDC profile mapper to be defined"); + + expect(() => + mapProfile( + { + sub: "subject", + preferred_username: "test", + email: "test@example.com", + email_verified: false, + }, + {}, + ), + ).not.toThrow(); + }); });