From 8a0f06bbdbb10ac70d3a04816529ca848b256590 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fatih=20Kadir=20Ak=C4=B1n?= Date: Fri, 12 Dec 2025 22:30:41 +0300 Subject: [PATCH] chore(auth): update authentication providers configuration --- prompts.config.ts | 7 ++-- src/app/(auth)/login/page.tsx | 21 +++++++++--- src/app/(auth)/register/page.tsx | 20 +++++++++--- src/components/auth/auth-content.tsx | 48 ++++++++++++++++++++-------- src/lib/auth/index.ts | 33 ++++++++++++++++--- src/lib/config/index.ts | 9 ++++-- src/lib/plugins/auth/index.ts | 15 ++++----- src/lib/plugins/index.ts | 36 +++++++++++++++++---- 8 files changed, 145 insertions(+), 44 deletions(-) diff --git a/prompts.config.ts b/prompts.config.ts index 961e93b8..60db8956 100644 --- a/prompts.config.ts +++ b/prompts.config.ts @@ -27,11 +27,12 @@ export default defineConfig({ }, }, - // Authentication plugin + // Authentication plugins auth: { // Available: "credentials" | "google" | "azure" | "github" | custom - provider: "github", - // Allow public registration + // Use `providers` array to enable multiple auth providers + providers: ["github", "google"], + // Allow public registration (only applies to credentials provider) allowRegistration: false, }, diff --git a/src/app/(auth)/login/page.tsx b/src/app/(auth)/login/page.tsx index a4ef1622..f0c5a67f 100644 --- a/src/app/(auth)/login/page.tsx +++ b/src/app/(auth)/login/page.tsx @@ -9,10 +9,23 @@ export const metadata: Metadata = { description: "Login to your account", }; +// Helper to get providers from config (supports both old `provider` and new `providers` array) +function getProviders(config: Awaited>): string[] { + if (config.auth.providers && config.auth.providers.length > 0) { + return config.auth.providers; + } + if (config.auth.provider) { + return [config.auth.provider]; + } + return ["credentials"]; +} + export default async function LoginPage() { const t = await getTranslations("auth"); const config = await getConfig(); - const isCredentials = config.auth.provider === "credentials"; + const providers = getProviders(config); + const hasCredentials = providers.includes("credentials"); + const hasOnlyCredentials = providers.length === 1 && hasCredentials; return (
@@ -20,13 +33,13 @@ export default async function LoginPage() {

{t("login")}

- {isCredentials ? t("loginDescription") : t("loginDescriptionOAuth")} + {hasOnlyCredentials ? t("loginDescription") : t("loginDescriptionOAuth")}

- +
- {isCredentials && ( + {hasCredentials && (

{t("noAccount")}{" "} {t("register")} diff --git a/src/app/(auth)/register/page.tsx b/src/app/(auth)/register/page.tsx index 9718d8da..bbd27ffd 100644 --- a/src/app/(auth)/register/page.tsx +++ b/src/app/(auth)/register/page.tsx @@ -10,13 +10,25 @@ export const metadata: Metadata = { description: "Create a new account", }; +// Helper to get providers from config (supports both old `provider` and new `providers` array) +function getProviders(config: Awaited>): string[] { + if (config.auth.providers && config.auth.providers.length > 0) { + return config.auth.providers; + } + if (config.auth.provider) { + return [config.auth.provider]; + } + return ["credentials"]; +} + export default async function RegisterPage() { const t = await getTranslations("auth"); const config = await getConfig(); - const isCredentials = config.auth.provider === "credentials"; + const providers = getProviders(config); + const hasCredentials = providers.includes("credentials"); - // Block registration if disabled or using OAuth providers - if (!isCredentials || !config.auth.allowRegistration) { + // Block registration if disabled or credentials not enabled + if (!hasCredentials || !config.auth.allowRegistration) { redirect("/login"); } @@ -28,7 +40,7 @@ export default async function RegisterPage() {

{t("registerDescription")}

- +

{t("hasAccount")}{" "} diff --git a/src/components/auth/auth-content.tsx b/src/components/auth/auth-content.tsx index 30ceb336..948c55be 100644 --- a/src/components/auth/auth-content.tsx +++ b/src/components/auth/auth-content.tsx @@ -5,7 +5,7 @@ import { RegisterForm } from "./register-form"; import { OAuthButton } from "./oauth-button"; interface AuthContentProps { - provider: string; + providers: string[]; mode: "login" | "register"; } @@ -16,17 +16,39 @@ const providerNames: Record = { credentials: "Email", }; -export function AuthContent({ provider, mode }: AuthContentProps) { - // For OAuth providers, show the OAuth button - if (provider !== "credentials") { - return ( - - ); - } +export function AuthContent({ providers, mode }: AuthContentProps) { + const hasCredentials = providers.includes("credentials"); + const oauthProviders = providers.filter((p) => p !== "credentials"); - // For credentials, show the appropriate form - return mode === "login" ? : ; + return ( +

+ {/* OAuth providers */} + {oauthProviders.length > 0 && ( +
+ {oauthProviders.map((provider) => ( + + ))} +
+ )} + + {/* Separator when both OAuth and credentials are enabled */} + {oauthProviders.length > 0 && hasCredentials && ( +
+
+ +
+
+ or +
+
+ )} + + {/* Credentials form */} + {hasCredentials && (mode === "login" ? : )} +
+ ); } diff --git a/src/lib/auth/index.ts b/src/lib/auth/index.ts index 77d537c9..c6dc4b47 100644 --- a/src/lib/auth/index.ts +++ b/src/lib/auth/index.ts @@ -102,18 +102,43 @@ function CustomPrismaAdapter(): Adapter { }; } +// Helper to get providers from config (supports both old `provider` and new `providers` array) +function getConfiguredProviders(config: Awaited>): string[] { + // Support new `providers` array + if (config.auth.providers && config.auth.providers.length > 0) { + return config.auth.providers; + } + // Backward compatibility with old `provider` string + if (config.auth.provider) { + return [config.auth.provider]; + } + // Default to credentials + return ["credentials"]; +} + // Build auth config dynamically based on prompts.config.ts async function buildAuthConfig() { const config = await getConfig(); - const authPlugin = getAuthPlugin(config.auth.provider); + const providerIds = getConfiguredProviders(config); + + const authProviders = providerIds + .map((id) => { + const plugin = getAuthPlugin(id); + if (!plugin) { + console.warn(`Auth plugin "${id}" not found, skipping`); + return null; + } + return plugin.getProvider(); + }) + .filter((p): p is NonNullable => p !== null); - if (!authPlugin) { - throw new Error(`Auth plugin "${config.auth.provider}" not found`); + if (authProviders.length === 0) { + throw new Error(`No valid auth plugins found. Configured: ${providerIds.join(", ")}`); } return { adapter: CustomPrismaAdapter(), - providers: [authPlugin.getProvider()], + providers: authProviders, session: { strategy: "jwt" as const, }, diff --git a/src/lib/config/index.ts b/src/lib/config/index.ts index ebfd7805..f5abec7f 100644 --- a/src/lib/config/index.ts +++ b/src/lib/config/index.ts @@ -19,8 +19,13 @@ export interface ThemeConfig { }; } +export type AuthProvider = "credentials" | "google" | "azure" | "github" | string; + export interface AuthConfig { - provider: "credentials" | "google" | "azure" | "github" | string; + /** @deprecated Use `providers` array instead */ + provider?: AuthProvider; + /** Array of auth providers to enable (e.g., ["github", "google"]) */ + providers?: AuthProvider[]; allowRegistration: boolean; } @@ -104,7 +109,7 @@ export async function getConfig(): Promise { }, }, auth: { - provider: "credentials", + providers: ["credentials"], allowRegistration: true, }, storage: { diff --git a/src/lib/plugins/auth/index.ts b/src/lib/plugins/auth/index.ts index 744038a4..6db273a7 100644 --- a/src/lib/plugins/auth/index.ts +++ b/src/lib/plugins/auth/index.ts @@ -1,16 +1,15 @@ import { registerAuthPlugin } from "../registry"; -// import { credentialsPlugin } from "./credentials"; -// import { googlePlugin } from "./google"; -// import { azurePlugin } from "./azure"; +import { credentialsPlugin } from "./credentials"; +import { googlePlugin } from "./google"; +import { azurePlugin } from "./azure"; import { githubPlugin } from "./github"; // Register all built-in auth plugins export function registerBuiltInAuthPlugins(): void { - // registerAuthPlugin(credentialsPlugin); - // registerAuthPlugin(googlePlugin); - // registerAuthPlugin(azurePlugin); + registerAuthPlugin(credentialsPlugin); + registerAuthPlugin(googlePlugin); + registerAuthPlugin(azurePlugin); registerAuthPlugin(githubPlugin); } -// export { credentialsPlugin, googlePlugin, azurePlugin, githubPlugin }; -export { githubPlugin }; \ No newline at end of file +export { credentialsPlugin, googlePlugin, azurePlugin, githubPlugin }; \ No newline at end of file diff --git a/src/lib/plugins/index.ts b/src/lib/plugins/index.ts index 0e2585c3..2e106056 100644 --- a/src/lib/plugins/index.ts +++ b/src/lib/plugins/index.ts @@ -19,22 +19,46 @@ export function initializePlugins(): void { initialized = true; } +// Helper to get providers from config (supports both old `provider` and new `providers` array) +function getProviderIds(config: Awaited>): string[] { + if (config.auth.providers && config.auth.providers.length > 0) { + return config.auth.providers; + } + if (config.auth.provider) { + return [config.auth.provider]; + } + return ["credentials"]; +} + /** - * Get the configured auth plugin based on prompts.config.ts + * Get the configured auth plugins based on prompts.config.ts */ -export async function getConfiguredAuthPlugin() { +export async function getConfiguredAuthPlugins() { initializePlugins(); const config = await getConfig(); - const plugin = getAuthPlugin(config.auth.provider); + const providerIds = getProviderIds(config); - if (!plugin) { + const plugins = providerIds + .map((id) => getAuthPlugin(id)) + .filter((p): p is NonNullable => p !== null && p !== undefined); + + if (plugins.length === 0) { throw new Error( - `Auth plugin "${config.auth.provider}" not found. ` + + `No auth plugins found for configured providers: ${providerIds.join(", ")}. ` + `Available plugins: credentials, google, azure, github` ); } - return plugin; + return plugins; +} + +/** + * @deprecated Use getConfiguredAuthPlugins() instead + * Get the first configured auth plugin based on prompts.config.ts + */ +export async function getConfiguredAuthPlugin() { + const plugins = await getConfiguredAuthPlugins(); + return plugins[0]; } /**