diff --git a/app/oauth/callback/route.ts b/app/oauth/callback/route.ts index 2f66a10..2fcdd0a 100644 --- a/app/oauth/callback/route.ts +++ b/app/oauth/callback/route.ts @@ -19,6 +19,8 @@ export async function GET(request: NextRequest) { const state = searchParams.get("state"); const error = searchParams.get("error"); const errorDescription = searchParams.get("error_description"); + // Use configured base URL when behind a reverse proxy, falling back to request origin for local dev. + const baseUrl = process.env.APP_BASE_URL ?? request.nextUrl.origin; // Handle OAuth errors if (error) { @@ -27,14 +29,14 @@ export async function GET(request: NextRequest) { errorDescription, }); return NextResponse.redirect( - new URL(`/login?error=${encodeURIComponent(errorDescription || error)}`, request.url), + new URL(`/login?error=${encodeURIComponent(errorDescription || error)}`, baseUrl), ); } if (!code || !state) { logger.error("Missing code or state in OAuth callback"); return NextResponse.redirect( - new URL("/login?error=Missing+authorization+code", request.url), + new URL("/login?error=Missing+authorization+code", baseUrl), ); } @@ -51,20 +53,20 @@ export async function GET(request: NextRequest) { storedState: storedState ? "[present]" : "[missing]", }); return NextResponse.redirect( - new URL("/login?error=Invalid+state", request.url), + new URL("/login?error=Invalid+state", baseUrl), ); } if (!codeVerifier) { logger.error("Missing code verifier in OAuth callback"); return NextResponse.redirect( - new URL("/login?error=Missing+code+verifier", request.url), + new URL("/login?error=Missing+code+verifier", baseUrl), ); } try { // Determine the redirect URI (must match what was used in the authorization request) - const redirectUri = `${process.env.APP_BASE_URL}/oauth/callback`; + const redirectUri = `${baseUrl}/oauth/callback`; // Exchange authorization code for tokens const tokens = await exchangeCodeForTokens(code, codeVerifier, redirectUri); @@ -99,7 +101,7 @@ export async function GET(request: NextRequest) { email: claims.email, }); return NextResponse.redirect( - new URL("/login?error=Failed+to+create+user", request.url), + new URL("/login?error=Failed+to+create+user", baseUrl), ); } @@ -125,7 +127,7 @@ export async function GET(request: NextRequest) { idpUserId: claims.sub, }); return NextResponse.redirect( - new URL("/login?error=Account+is+deactivated", request.url), + new URL("/login?error=Account+is+deactivated", baseUrl), ); } @@ -168,7 +170,7 @@ export async function GET(request: NextRequest) { code: code ? "[present]" : "[missing]", }); return NextResponse.redirect( - new URL("/login?error=Authentication+failed", request.url), + new URL("/login?error=Authentication+failed", baseUrl), ); } } diff --git a/app/oauth/login/route.ts b/app/oauth/login/route.ts index 6b97356..5da568e 100644 --- a/app/oauth/login/route.ts +++ b/app/oauth/login/route.ts @@ -10,6 +10,9 @@ import { logger } from "@/lib/logger"; export async function GET(request: NextRequest) { const searchParams = request.nextUrl.searchParams; const returnUrl = searchParams.get("returnUrl") || "/"; + // Use configured base URL when behind a reverse proxy (Cloudflare Tunnel / Tailscale), + // falling back to request origin for local development. + const baseUrl = process.env.APP_BASE_URL ?? request.nextUrl.origin; try { // Generate PKCE values @@ -17,9 +20,7 @@ export async function GET(request: NextRequest) { const codeVerifier = generateRandomString(64); const codeChallenge = await generateCodeChallenge(codeVerifier); - // Determine redirect URI from the configured base URL, not the request origin, - // since the app runs behind a reverse proxy (Cloudflare Tunnel / Tailscale). - const redirectUri = `${process.env.APP_BASE_URL}/oauth/callback`; + const redirectUri = `${baseUrl}/oauth/callback`; // Store state and code verifier in cookies for validation in callback const cookieStore = await cookies(); @@ -64,7 +65,7 @@ export async function GET(request: NextRequest) { } catch (err) { logger.error("Failed to initiate OAuth login", err as Error); return NextResponse.redirect( - new URL("/login?error=Failed+to+start+login", request.url), + new URL("/login?error=Failed+to+start+login", baseUrl), ); } }