Skip to content

Conversation

@UNILORN
Copy link

@UNILORN UNILORN commented Nov 13, 2025

☕️ Reasoning

This PR restores X-Forwarded-Host and X-Forwarded-Proto header handling that was present in [email protected] but was lost during the migration to the current main branch architecture.

Problem

When running behind reverse proxies or load balancers (e.g., nginx, Vercel, Cloudflare), OAuth provider callback URLs are generated with internal hostnames instead of the public domain. This causes OAuth authentication to fail with "redirect_uri mismatch" errors.

In [email protected] , the toInternalRequest() function used detectOrigin() to extract the origin from X-Forwarded-* headers. This logic was removed in the refactoring to the current architecture, where toInternalRequest() directly uses new URL(req.url) without considering proxy headers.

Behavior

The fix only activates when one of the following conditions is met

  • AUTH_URL is not set
  • AUTH_TRUST_HOST=true is set
  • Running on Vercel (VERCEL=1)
  • Running on Cloudflare Pages (CF_PAGES=1)
  • Development mode (NODE_ENV=development)

References

🧢 Checklist

  • Documentation
  • Tests
  • Ready to be merged

🎫 Affected issues

Fixes: #10928

📌 Resources

@UNILORN UNILORN requested a review from ThangHuuVu as a code owner November 13, 2025 05:54
@vercel
Copy link

vercel bot commented Nov 13, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
auth-docs Ready Ready Preview Comment Nov 15, 2025 11:50am
1 Skipped Deployment
Project Deployment Preview Comments Updated (UTC)
next-auth-docs Ignored Ignored Preview Nov 15, 2025 11:50am

@github-actions github-actions bot added the core Refers to `@auth/core` label Nov 13, 2025
@vercel
Copy link

vercel bot commented Nov 13, 2025

@UNILORN is attempting to deploy a commit to the authjs Team on Vercel.

A member of the Team first needs to authorize it.

@github-actions
Copy link

Broken Link Checker

1 broken links found. Links organised below by source page, or page where they were found.

1) /getting-started/migrate-to-better-auth

Target Link Link Text
/docs "documentation"

@UNILORN UNILORN marked this pull request as draft November 13, 2025 09:29
@UNILORN
Copy link
Author

UNILORN commented Nov 15, 2025

I have identified a workaround on the application side. Given this, the changes in this PR may not be required, so I am marking it as a draft for the time being.

@xzhayon
Copy link

xzhayon commented Nov 15, 2025

I have identified a workaround on the application side. Given this, the changes in this PR may not be required, so I am marking it as a draft for the time being.

@UNILORN

Can you explain the workaround? Meanwhile, I've applied your patch and managed to make the redirect work.

@UNILORN
Copy link
Author

UNILORN commented Nov 15, 2025

@xzhayon

While testing on the application side, we observed the following behavior:

req.headers.get("x-forwarded-host") // 'example.com'
req.headers.get("x-forwarded-proto") // 'https'
req.headers.get("host") // 'example.com'
req.url // 'https://my-app-pod-1234:3000/api/auth/...'

After implementing a wrapper for the request in route.ts—as well as for the headers passed to NextAuth()—so that the correct x-forwarded-host value is used, the behavior became correct.

function wrapWithForwardedHost(req: NextRequest): NextRequest {
  const headersList = headers();
  const forwardedHost = headersList.get('x-forwarded-host');
  const forwardedProto = headersList.get('x-forwarded-proto');

  if (!forwardedHost || !forwardedProto) {
    return req;
  }

  const newHeaders = new Headers(req.headers);
  newHeaders.set('x-forwarded-host', forwardedHost);
  newHeaders.set('x-forwarded-proto', forwardedProto);

  const originalUrl = new URL(req.url);
  const protocol = forwardedProto.endsWith(':') ? forwardedProto : `${forwardedProto}:`;
  const correctedUrl = `${protocol}//${forwardedHost}${originalUrl.pathname}${originalUrl.search}`;

  return new Request(correctedUrl, {
    method: req.method,
    headers: newHeaders,
    body: req.body,
    // @ts-expect-error duplex is required for streaming request bodies
    duplex: 'half',
  }) as unknown as NextRequest;
}

export function GET(req: NextRequest) {
  return handlers.GET(wrapWithForwardedHost(req));
}

export function POST(req: NextRequest) {
  return handlers.POST(wrapWithForwardedHost(req));
}

The changes I pushed earlier include this logic implemented on the Auth.js side.

Could you please review this update and let me know if there are any issues?

I apologize for putting the PR back into draft status after you had already reviewed it, but I would appreciate it if you could review it once again.

@UNILORN UNILORN marked this pull request as ready for review November 15, 2025 12:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

core Refers to `@auth/core`

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Authjs v5 redirecting to the wrong URL

2 participants