Skip to content

fix(auth): use BASE_URL for redirects and handle __Secure- cookie prefix#418

Merged
peppescg merged 2 commits intomainfrom
issues/417
Mar 11, 2026
Merged

fix(auth): use BASE_URL for redirects and handle __Secure- cookie prefix#418
peppescg merged 2 commits intomainfrom
issues/417

Conversation

@peppescg
Copy link
Copy Markdown
Collaborator

Summary

Kapture.2026-03-11.at.15.49.48.mp4
  • route.ts: replace request.url with BASE_URL (BETTER_AUTH_URL) as the base for all
    redirects in the Route Handler. In production with output: standalone and HOSTNAME=0.0.0.0,
    request.url was built from the internal bind address (0.0.0.0:3000) instead of the external
    URL, producing unreachable redirects.

  • utils.ts: isTokenNearExpiry() never found the cookie in production HTTPS because Better
    Auth prefixes cookies with __Secure- on secure connections. The function was matching against
    better-auth.account_data while the actual cookie was named
    __Secure-better-auth.account_data, so it always returned true → infinite redirect loop.

    The second bug was masked by the first: before the routing fix, the redirect to 0.0.0.0:3000
    failed immediately with a connection error. Once redirects pointed to the correct origin, the
    loop became visible as ERR_TOO_MANY_REDIRECTS.

@peppescg peppescg self-assigned this Mar 11, 2026
Copilot AI review requested due to automatic review settings March 11, 2026 15:10
@github-actions github-actions bot added the size/S Small PR: 100-299 lines changed label Mar 11, 2026
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes production auth redirect behavior by ensuring redirects are built from the externally reachable BASE_URL (aka BETTER_AUTH_URL) and by correctly detecting Better Auth cookies that are __Secure- prefixed under HTTPS, preventing infinite refresh redirect loops.

Changes:

  • Update isTokenNearExpiry() to normalize cookie names by stripping the __Secure- prefix when locating/chunking better-auth.account_data.
  • Update the token refresh route handler to resolve and validate redirect targets against BASE_URL rather than request.url.
  • Add/extend unit tests covering __Secure- cookies and redirect/base-url behavior in the token refresh route.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
src/lib/auth/utils.ts Normalizes cookie names to support __Secure- prefixed Better Auth cookies and chunked cookie reads.
src/lib/auth/tests/utils.test.ts Adds tests ensuring __Secure- cookies (including chunked) are read/concatenated correctly.
src/app/api/auth/token-refresh/route.ts Builds redirect validation and redirect responses from BASE_URL to avoid internal bind-address redirects.
src/app/api/auth/token-refresh/route.test.ts Adds route handler unit tests for BASE_URL-based redirects, open-redirect protection, and Set-Cookie forwarding.

Comment thread src/app/api/auth/token-refresh/route.ts
Comment thread src/app/api/auth/token-refresh/route.test.ts Outdated
@peppescg
Copy link
Copy Markdown
Collaborator Author

@claude succinct review

@github-actions github-actions bot added size/S Small PR: 100-299 lines changed and removed size/S Small PR: 100-299 lines changed labels Mar 11, 2026
@claude
Copy link
Copy Markdown

claude bot commented Mar 11, 2026

Claude finished @peppescg's task in 54s —— View job


Code Review

Overall: Solid fix for two real production bugs. Code is clean, well-documented, and well-tested. A couple of minor issues worth addressing.


route.ts — Module-level URL parse (high priority)

// line 6
const BASE_ORIGIN = new URL(BASE_URL).origin;

If BETTER_AUTH_URL is unset or malformed in a deployment, this throws at module evaluation time, crashing the entire route before any request is handled. Copilot flagged this too. Consider moving it inside the handler with a clear error response, or pre-validate BASE_URL in constants.ts.

Fix this →


route.test.ts — Stale comment (low priority)

The comment describing BASE_URL defaulting to http://localhost:3000 because no BETTER_AUTH_URL is set is inaccurate — vitest.config.mts sets BETTER_AUTH_URL explicitly. Already flagged by Copilot with a suggested fix.


utils.ts — Cookie normalization ✅

The __Secure- stripping + chunked cookie re-assembly logic is correct. The numeric suffix sort (/\.(\d+)$/) works correctly on raw names (the __Secure- prefix doesn't interfere since the regex anchors at the end). The fallback to "0" on non-numeric suffixes is safe.


Open redirect protection ✅

The // prefix guard + origin comparison via new URL(..., BASE_URL).origin === BASE_ORIGIN is solid. javascript: URIs are correctly rejected because their .origin evaluates to "null".


Summary: The two bugs are correctly diagnosed and fixed. Only the module-level new URL() is a real risk worth addressing before merge.

Copy link
Copy Markdown

@samuv samuv left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't have much context, but looks good

@peppescg peppescg merged commit e0e6bb7 into main Mar 11, 2026
11 checks passed
@peppescg peppescg deleted the issues/417 branch March 11, 2026 15:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/S Small PR: 100-299 lines changed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: Token-refresh route redirects to 0.0.0.0:3000 when running behind a reverse proxy

3 participants