fix(#411): remediate backend review findings — COOKIE_DOMAIN, TRUSTED_ORIGINS validation, verifySession

- Wire COOKIE_DOMAIN env var into BetterAuth cookie config
- Add URL validation for TRUSTED_ORIGINS (rejects non-HTTP, invalid URLs)
- Include original parse error in validateRedirectUri error message
- Distinguish infrastructure errors from auth errors in verifySession
  (Prisma/connection errors now propagate as 500 instead of masking as 401)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Jason Woltje
2026-02-16 12:31:53 -06:00
parent 3fbba135b9
commit 7ead8b1076
4 changed files with 166 additions and 7 deletions

View File

@@ -80,9 +80,11 @@ function validateRedirectUri(): void {
let parsed: URL;
try {
parsed = new URL(redirectUri);
} catch {
} catch (urlError: unknown) {
const detail = urlError instanceof Error ? urlError.message : String(urlError);
throw new Error(
`OIDC_REDIRECT_URI must be a valid URL. Current value: "${redirectUri}". ` +
`Parse error: ${detail}. ` +
`Example: "https://app.example.com/auth/callback/authentik".`
);
}
@@ -153,12 +155,23 @@ export function getTrustedOrigins(): string[] {
origins.push(process.env.NEXT_PUBLIC_API_URL);
}
// Comma-separated additional origins
// Comma-separated additional origins (validated)
if (process.env.TRUSTED_ORIGINS) {
const extra = process.env.TRUSTED_ORIGINS.split(",")
const rawOrigins = process.env.TRUSTED_ORIGINS.split(",")
.map((o) => o.trim())
.filter((o) => o !== "");
origins.push(...extra);
for (const origin of rawOrigins) {
try {
const parsed = new URL(origin);
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
console.warn(`[AUTH] Ignoring non-HTTP origin in TRUSTED_ORIGINS: "${origin}"`);
continue;
}
origins.push(origin);
} catch {
console.warn(`[AUTH] Ignoring invalid URL in TRUSTED_ORIGINS: "${origin}"`);
}
}
}
// Localhost fallbacks for development only
@@ -192,6 +205,7 @@ export function createAuth(prisma: PrismaClient) {
httpOnly: true,
secure: process.env.NODE_ENV === "production",
sameSite: "lax" as const,
...(process.env.COOKIE_DOMAIN ? { domain: process.env.COOKIE_DOMAIN } : {}),
},
},
trustedOrigins: getTrustedOrigins(),