fix(#412): add OIDC_REDIRECT_URI to startup validation
All checks were successful
ci/woodpecker/push/api Pipeline was successful
All checks were successful
ci/woodpecker/push/api Pipeline was successful
Add OIDC_REDIRECT_URI to REQUIRED_OIDC_ENV_VARS with URL format and path validation. The redirect URI must be a parseable URL with a path starting with /auth/callback. Localhost usage in production triggers a warning but does not block startup. This prevents 500 errors when BetterAuth attempts to construct the authorization URL without a configured redirect URI. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -6,7 +6,12 @@ import type { PrismaClient } from "@prisma/client";
|
||||
/**
|
||||
* Required OIDC environment variables when OIDC is enabled
|
||||
*/
|
||||
const REQUIRED_OIDC_ENV_VARS = ["OIDC_ISSUER", "OIDC_CLIENT_ID", "OIDC_CLIENT_SECRET"] as const;
|
||||
const REQUIRED_OIDC_ENV_VARS = [
|
||||
"OIDC_ISSUER",
|
||||
"OIDC_CLIENT_ID",
|
||||
"OIDC_CLIENT_SECRET",
|
||||
"OIDC_REDIRECT_URI",
|
||||
] as const;
|
||||
|
||||
/**
|
||||
* Check if OIDC authentication is enabled via environment variable
|
||||
@@ -52,6 +57,52 @@ export function validateOidcConfig(): void {
|
||||
`The discovery URL is constructed by appending ".well-known/openid-configuration" to the issuer.`
|
||||
);
|
||||
}
|
||||
|
||||
// Additional validation: OIDC_REDIRECT_URI must be a valid URL with /auth/callback path
|
||||
validateRedirectUri();
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the OIDC_REDIRECT_URI environment variable.
|
||||
* - Must be a parseable URL
|
||||
* - Path must start with /auth/callback
|
||||
* - Warns (but does not throw) if using localhost in production
|
||||
*
|
||||
* @throws Error if URL is invalid or path does not start with /auth/callback
|
||||
*/
|
||||
function validateRedirectUri(): void {
|
||||
const redirectUri = process.env.OIDC_REDIRECT_URI;
|
||||
if (!redirectUri || redirectUri.trim() === "") {
|
||||
// Already caught by REQUIRED_OIDC_ENV_VARS check above
|
||||
return;
|
||||
}
|
||||
|
||||
let parsed: URL;
|
||||
try {
|
||||
parsed = new URL(redirectUri);
|
||||
} catch {
|
||||
throw new Error(
|
||||
`OIDC_REDIRECT_URI must be a valid URL. Current value: "${redirectUri}". ` +
|
||||
`Example: "https://app.example.com/auth/callback/authentik".`
|
||||
);
|
||||
}
|
||||
|
||||
if (!parsed.pathname.startsWith("/auth/callback")) {
|
||||
throw new Error(
|
||||
`OIDC_REDIRECT_URI path must start with "/auth/callback". Current path: "${parsed.pathname}". ` +
|
||||
`Example: "https://app.example.com/auth/callback/authentik".`
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
process.env.NODE_ENV === "production" &&
|
||||
(parsed.hostname === "localhost" || parsed.hostname === "127.0.0.1")
|
||||
) {
|
||||
console.warn(
|
||||
`[AUTH WARNING] OIDC_REDIRECT_URI uses localhost ("${redirectUri}") in production. ` +
|
||||
`This is likely a misconfiguration. Use a public domain for production deployments.`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -71,6 +122,7 @@ function getOidcPlugins(): ReturnType<typeof genericOAuth>[] {
|
||||
clientId: process.env.OIDC_CLIENT_ID ?? "",
|
||||
clientSecret: process.env.OIDC_CLIENT_SECRET ?? "",
|
||||
discoveryUrl: `${process.env.OIDC_ISSUER ?? ""}.well-known/openid-configuration`,
|
||||
pkce: true,
|
||||
scopes: ["openid", "profile", "email"],
|
||||
},
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user