fix: derive redirect and origin check from Host header
req.url resolves to the internal hostname in Docker standalone mode. Read the Host header directly so redirects and CSRF origin checks use whatever host the browser actually used (IP, hostname, or domain). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -33,10 +33,22 @@ function isRateLimited(ip: string): boolean {
|
||||
function hasValidOrigin(req: NextRequest): boolean {
|
||||
const origin = req.headers.get('origin')
|
||||
if (!origin) return true // non-browser (curl, server-to-server)
|
||||
const expected = process.env.NEXTAUTH_URL
|
||||
? new URL(process.env.NEXTAUTH_URL).origin
|
||||
: req.nextUrl.origin
|
||||
return origin === expected
|
||||
// Accept the host the browser actually used to reach this server.
|
||||
const host = req.headers.get('x-forwarded-host') ?? req.headers.get('host')
|
||||
const proto = req.headers.get('x-forwarded-proto') ?? 'http'
|
||||
const requestOrigin = host ? `${proto}://${host}` : null
|
||||
if (requestOrigin && origin === requestOrigin) return true
|
||||
// Also accept the statically configured NEXTAUTH_URL origin (reverse-proxy setups).
|
||||
if (process.env.NEXTAUTH_URL && origin === new URL(process.env.NEXTAUTH_URL).origin) return true
|
||||
return false
|
||||
}
|
||||
|
||||
// Build an absolute URL using the Host header the browser sent, not the
|
||||
// internal hostname Next.js resolves to inside Docker.
|
||||
function siteUrl(req: NextRequest, path: string): URL {
|
||||
const host = req.headers.get('x-forwarded-host') ?? req.headers.get('host') ?? 'localhost:3000'
|
||||
const proto = req.headers.get('x-forwarded-proto') ?? 'http'
|
||||
return new URL(path, `${proto}://${host}`)
|
||||
}
|
||||
|
||||
export default auth((req) => {
|
||||
@@ -72,13 +84,13 @@ export default auth((req) => {
|
||||
if (pathname.startsWith('/api/')) {
|
||||
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
|
||||
}
|
||||
const loginUrl = new URL('/login', req.url)
|
||||
const loginUrl = siteUrl(req, '/login')
|
||||
loginUrl.searchParams.set('callbackUrl', pathname)
|
||||
return NextResponse.redirect(loginUrl)
|
||||
}
|
||||
|
||||
if (pathname === '/login') {
|
||||
return NextResponse.redirect(new URL('/dashboard', req.url))
|
||||
return NextResponse.redirect(siteUrl(req, '/dashboard'))
|
||||
}
|
||||
|
||||
return NextResponse.next()
|
||||
|
||||
Reference in New Issue
Block a user