feat: add Google and Apple OAuth via better-auth socialProviders

This commit is contained in:
2026-04-08 09:12:50 -04:00
parent e59476dea9
commit 9dfd4ef326
9 changed files with 777 additions and 120 deletions

View File

@@ -3,43 +3,57 @@ import { drizzleAdapter } from "better-auth/adapters/drizzle";
import { genericOAuth } from "better-auth/plugins";
import { db } from "@/db/index";
import * as schema from "@/db/schema";
import { buildSocialProviders } from "@/lib/build-social-providers";
// Validate required environment variables
// ---------------------------------------------------------------------------
// Required vars — the app cannot start without these
// ---------------------------------------------------------------------------
if (!process.env.BETTER_AUTH_SECRET) {
throw new Error("BETTER_AUTH_SECRET is required");
}
if (!process.env.BETTER_AUTH_URL) {
throw new Error("BETTER_AUTH_URL is required");
}
if (!process.env.AUTH_AUTHENTIK_CLIENT_ID) {
throw new Error("AUTH_AUTHENTIK_CLIENT_ID is required");
}
if (!process.env.AUTH_AUTHENTIK_CLIENT_SECRET) {
throw new Error("AUTH_AUTHENTIK_CLIENT_SECRET is required");
}
if (!process.env.AUTH_AUTHENTIK_ISSUER) {
throw new Error("AUTH_AUTHENTIK_ISSUER is required");
}
export const auth = betterAuth({
secret: process.env.BETTER_AUTH_SECRET,
baseURL: process.env.BETTER_AUTH_URL,
trustedOrigins: [process.env.BETTER_AUTH_URL],
database: drizzleAdapter(db, {
provider: "pg",
schema,
}),
plugins: [
genericOAuth({
config: [
// ---------------------------------------------------------------------------
// Authentik is optional: only configured when all three vars are present.
// Google and Apple are also optional via buildSocialProviders().
// ---------------------------------------------------------------------------
const authentikConfig =
process.env.AUTH_AUTHENTIK_CLIENT_ID &&
process.env.AUTH_AUTHENTIK_CLIENT_SECRET &&
process.env.AUTH_AUTHENTIK_ISSUER
? [
{
providerId: "authentik",
providerId: "authentik" as const,
clientId: process.env.AUTH_AUTHENTIK_CLIENT_ID,
clientSecret: process.env.AUTH_AUTHENTIK_CLIENT_SECRET,
discoveryUrl: `${process.env.AUTH_AUTHENTIK_ISSUER}/.well-known/openid-configuration`,
scopes: ["openid", "email", "profile"],
},
],
}),
]
: [];
const socialProviders = buildSocialProviders(
process.env as Record<string, string | undefined>,
);
export const auth = betterAuth({
secret: process.env.BETTER_AUTH_SECRET,
baseURL: process.env.BETTER_AUTH_URL,
trustedOrigins: [
process.env.BETTER_AUTH_URL,
// Required for Sign in with Apple's form_post redirect
...(socialProviders.apple ? ["https://appleid.apple.com"] : []),
],
database: drizzleAdapter(db, {
provider: "pg",
schema,
}),
socialProviders,
plugins: [
...(authentikConfig.length > 0
? [genericOAuth({ config: authentikConfig })]
: []),
],
});