diff --git a/app/api/integrations/github/callback/route.ts b/app/api/integrations/github/callback/route.ts index cbb56ebc..030f74a0 100644 --- a/app/api/integrations/github/callback/route.ts +++ b/app/api/integrations/github/callback/route.ts @@ -32,7 +32,7 @@ function bounce(origin: string, returnTo: string, params: Record export async function GET(req: Request) { const url = new URL(req.url); - const origin = url.origin; + const origin = (process.env.NEXTAUTH_URL ?? url.origin).replace(/\/$/, ""); // Recover the original target from the state cookie *before* any error path. const cookieState = req.headers.get("cookie") diff --git a/app/api/integrations/github/connect/route.ts b/app/api/integrations/github/connect/route.ts index b3d64942..564045df 100644 --- a/app/api/integrations/github/connect/route.ts +++ b/app/api/integrations/github/connect/route.ts @@ -33,7 +33,11 @@ export async function GET(req: Request) { } const url = new URL(req.url); - const callbackUrl = `${url.origin}/api/integrations/github/callback`; + // Use NEXTAUTH_URL when available — behind a proxy req.url.origin + // resolves to the internal bind address (0.0.0.0) rather than the + // public hostname, which GitHub then rejects as an unregistered URI. + const appOrigin = (process.env.NEXTAUTH_URL ?? url.origin).replace(/\/$/, ""); + const callbackUrl = `${appOrigin}/api/integrations/github/callback`; const returnTo = url.searchParams.get("returnTo") ?? "/"; const state = randomBytes(16).toString("hex");