refactor: remove OIDC authentication

This commit is contained in:
2026-06-16 11:09:11 +08:00
parent 4b788befb0
commit 9ddbec5643
10 changed files with 2 additions and 456 deletions

View File

@@ -1,88 +0,0 @@
import { describe, expect, test } from "bun:test";
import {
getAuthMode,
mapOidcProfile,
isAuthRoute,
isProtectedPath,
type AuthEnv,
} from "./auth-config";
describe("optional OIDC auth config", () => {
test("disables auth when no OIDC settings are present", () => {
const env: AuthEnv = {};
expect(getAuthMode(env)).toEqual({ enabled: false, error: null });
});
test("does not enable auth when only non-OIDC auth settings are present", () => {
const env: AuthEnv = {
AUTH_SECRET: "session-secret",
OIDC_PROVIDER_NAME: "Casdoor",
};
expect(getAuthMode(env)).toEqual({ enabled: false, error: null });
});
test("enables auth when all required OIDC settings are present", () => {
const env: AuthEnv = {
OIDC_ISSUER: "https://door.example.com",
OIDC_CLIENT_ID: "analytics",
OIDC_CLIENT_SECRET: "secret",
AUTH_SECRET: "session-secret",
};
expect(getAuthMode(env)).toEqual({ enabled: true, error: null });
});
test("reports missing settings when OIDC config is partial", () => {
const env: AuthEnv = {
OIDC_ISSUER: "https://door.example.com",
OIDC_CLIENT_ID: "analytics",
};
expect(getAuthMode(env)).toEqual({
enabled: false,
error: "Missing required auth environment variables: OIDC_CLIENT_SECRET, AUTH_SECRET",
});
});
});
describe("auth route matching", () => {
test("protects analytics pages and API data routes", () => {
expect(isProtectedPath("/")).toBe(true);
expect(isProtectedPath("/logs")).toBe(true);
expect(isProtectedPath("/detail/user/alice")).toBe(true);
expect(isProtectedPath("/api/overview")).toBe(true);
expect(isProtectedPath("/api/detail/user/alice")).toBe(true);
});
test("does not protect auth or static asset routes", () => {
expect(isProtectedPath("/api/auth/signin")).toBe(false);
expect(isProtectedPath("/_next/static/chunk.js")).toBe(false);
expect(isProtectedPath("/favicon.ico")).toBe(false);
expect(isProtectedPath("/icon.svg")).toBe(false);
});
test("detects auth routes", () => {
expect(isAuthRoute("/api/auth/signin")).toBe(true);
expect(isAuthRoute("/api/overview")).toBe(false);
});
});
describe("OIDC profile mapping", () => {
test("uses standard OIDC profile claims for the NextAuth user", () => {
expect(
mapOidcProfile({
sub: "user-123",
preferred_username: "alice",
email: "alice@example.com",
picture: "https://example.com/alice.png",
})
).toEqual({
id: "user-123",
name: "alice",
email: "alice@example.com",
image: "https://example.com/alice.png",
});
});
});

View File

@@ -1,102 +0,0 @@
export interface AuthEnv {
OIDC_ISSUER?: string;
OIDC_CLIENT_ID?: string;
OIDC_CLIENT_SECRET?: string;
OIDC_PROVIDER_NAME?: string;
AUTH_SECRET?: string;
NEXTAUTH_URL?: string;
}
export interface AuthMode {
enabled: boolean;
error: string | null;
}
export interface OidcProfile {
sub: unknown;
name?: unknown;
preferred_username?: unknown;
email?: unknown;
picture?: unknown;
}
const REQUIRED_AUTH_KEYS = [
"OIDC_ISSUER",
"OIDC_CLIENT_ID",
"OIDC_CLIENT_SECRET",
"AUTH_SECRET",
] as const;
const OIDC_KEYS = [
"OIDC_ISSUER",
"OIDC_CLIENT_ID",
"OIDC_CLIENT_SECRET",
] as const;
const STATIC_FILE_PATTERN = /\.(?:ico|svg|png|jpg|jpeg|gif|webp|css|js|map|txt|xml|json)$/i;
export function getAuthMode(env: AuthEnv = process.env): AuthMode {
const hasAnyOidcConfig = OIDC_KEYS.some((key) => Boolean(trimEnv(env[key])));
if (!hasAnyOidcConfig) return { enabled: false, error: null };
const missing = REQUIRED_AUTH_KEYS.filter((key) => !trimEnv(env[key]));
if (missing.length > 0) {
return {
enabled: false,
error: `Missing required auth environment variables: ${missing.join(", ")}`,
};
}
return { enabled: true, error: null };
}
export function isAuthEnabled(env: AuthEnv = process.env): boolean {
return getAuthMode(env).enabled;
}
export function isAuthRoute(pathname: string): boolean {
return pathname === "/api/auth" || pathname.startsWith("/api/auth/");
}
export function isProtectedPath(pathname: string): boolean {
if (isAuthRoute(pathname)) return false;
if (pathname.startsWith("/_next/")) return false;
if (pathname === "/favicon.ico" || pathname === "/robots.txt" || pathname === "/sitemap.xml") return false;
if (STATIC_FILE_PATTERN.test(pathname)) return false;
return pathname === "/" || pathname.startsWith("/api/") || pathname.startsWith("/");
}
export function getOidcProviderName(env: AuthEnv = process.env): string {
return trimEnv(env.OIDC_PROVIDER_NAME) || "OIDC";
}
export function getRequiredAuthSecret(env: AuthEnv = process.env): string {
const secret = trimEnv(env.AUTH_SECRET);
if (!secret) throw new Error("Missing required auth environment variable: AUTH_SECRET");
return secret;
}
export function mapOidcProfile(profile: OidcProfile) {
const subject = String(profile.sub);
const name = firstString(profile.name, profile.preferred_username, profile.email, subject);
return {
id: subject,
name,
email: typeof profile.email === "string" ? profile.email : null,
image: typeof profile.picture === "string" ? profile.picture : null,
};
}
function trimEnv(value: string | undefined): string {
return value?.trim() ?? "";
}
function firstString(...values: unknown[]): string {
for (const value of values) {
if (typeof value === "string" && value.trim()) return value;
}
return "";
}