Skip to content

Commit f291a75

Browse files
committed
feat: add BETTER_AUTH_TRUSTED_ORIGINS support for Better Auth CSRF checks and enhance origin resolution logic
1 parent b16ee20 commit f291a75

2 files changed

Lines changed: 27 additions & 2 deletions

File tree

server/utils/auth.ts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,22 @@ import * as schema from '../database/schema'
66
type Auth = ReturnType<typeof betterAuth>
77
let _auth: Auth | undefined
88

9+
function resolveTrustedOrigins(baseUrl: string): string[] {
10+
const configuredOrigins = env.BETTER_AUTH_TRUSTED_ORIGINS
11+
const baseOrigin = new URL(baseUrl)
12+
const isLocalBase = baseOrigin.hostname === 'localhost' || baseOrigin.hostname === '127.0.0.1'
13+
const defaultDevOrigins = (import.meta.dev || isLocalBase)
14+
? [
15+
'http://localhost:3000',
16+
'http://localhost:3001',
17+
'http://127.0.0.1:3000',
18+
'http://127.0.0.1:3001',
19+
]
20+
: []
21+
22+
return Array.from(new Set([baseOrigin.origin, ...configuredOrigins, ...defaultDevOrigins]))
23+
}
24+
925
function resolveBetterAuthUrl(): string {
1026
const explicitUrl = env.BETTER_AUTH_URL?.trim()
1127
const railwayDomain = env.RAILWAY_PUBLIC_DOMAIN?.trim()
@@ -53,8 +69,11 @@ function resolveBetterAuthUrl(): string {
5369
*/
5470
function getAuth(): Auth {
5571
if (!_auth) {
72+
const baseURL = resolveBetterAuthUrl()
73+
5674
_auth = betterAuth({
57-
baseURL: resolveBetterAuthUrl(),
75+
baseURL,
76+
trustedOrigins: resolveTrustedOrigins(baseURL),
5877
database: drizzleAdapter(db, {
5978
provider: 'pg',
6079
schema,

server/utils/env.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,12 @@ const envSchema = z
3939
DATABASE_URL: z.url(),
4040
BETTER_AUTH_SECRET: emptyToUndefined.pipe(z.string().min(32, 'BETTER_AUTH_SECRET must be at least 32 characters')),
4141
BETTER_AUTH_URL: emptyToUndefined.pipe(z.url()).optional(),
42+
/** Comma-separated list of additional trusted origins for Better Auth CSRF checks. */
43+
BETTER_AUTH_TRUSTED_ORIGINS: emptyToUndefined
44+
.pipe(z.string())
45+
.transform(value => value.split(',').map(origin => origin.trim()).filter(Boolean))
46+
.optional()
47+
.default([]),
4248
/** Railway environment metadata for PR/preview detection. */
4349
RAILWAY_ENVIRONMENT_NAME: emptyToUndefined.optional(),
4450
/** PR number provided by Railway for GitHub-triggered deployments. */
@@ -109,7 +115,7 @@ export const env = new Proxy({} as z.infer<typeof envSchema>, {
109115
`Ensure these variables are set in your Railway service (Settings → Variables).\n` +
110116
`Required: DATABASE_URL, BETTER_AUTH_SECRET, S3_ENDPOINT, S3_ACCESS_KEY, S3_SECRET_KEY, S3_BUCKET\n` +
111117
`Required outside Railway PR/preview environments: BETTER_AUTH_URL\n` +
112-
`Optional: S3_REGION (default: us-east-1), S3_FORCE_PATH_STYLE (default: true), TRUSTED_PROXY_IP, DEMO_ORG_SLUG\n`,
118+
`Optional: BETTER_AUTH_TRUSTED_ORIGINS, S3_REGION (default: us-east-1), S3_FORCE_PATH_STYLE (default: true), TRUSTED_PROXY_IP, DEMO_ORG_SLUG\n`,
113119
)
114120
throw result.error
115121
}

0 commit comments

Comments
 (0)