Skip to content

fix: stop auth=success login loop on cross-app cookie conflict#1960

Open
emlimlf wants to merge 3 commits into
mainfrom
fix/login-loop
Open

fix: stop auth=success login loop on cross-app cookie conflict#1960
emlimlf wants to merge 3 commits into
mainfrom
fix/login-loop

Conversation

@emlimlf

@emlimlf emlimlf commented Jun 17, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Prevents infinite ?auth=success&auth=success&... URL accumulation when a user is logged into crowdfunding.linuxfoundation.org (which shares cookie names with insights) and then visits insights
  • Three compounding bugs were fixed:
    1. callback.ts: Strip any pre-existing ?auth param from redirectTo before appending auth=success, preventing accumulation across redirect cycles
    2. callback.ts: On silent auth failure (login_required, interaction_required, consent_required), redirect back cleanly without appending auth=success — the user isn't authenticated so the flag is misleading and perpetuates the loop
    3. useAuth.ts + auth.client.ts: Don't reset silentLoginAttempted flag inside login() for silent calls — the flag was being cleared before the redirect completed, so the guard never fired on the next page load

Root cause

Both apps use the same auth cookie names (auth_oidc_token, auth_refresh_token). If crowdfunding sets these with a parent-domain scope (.linuxfoundation.org), they bleed into insights requests. Insights then fails JWT validation (different signing secret), returns shouldAttemptSilentLogin: true, and triggers a silent re-auth — which previously looped forever.

Test plan

  • Log into crowdfunding.linuxfoundation.org, then navigate to insights — URL should not accumulate ?auth=success params; page settles as unauthenticated after one silent login attempt
  • Manual login on insights still works and lands on /?auth=success exactly once
  • Deleting auth_oidc_token cookie and refreshing no longer throws Authentication error: consent_required
  • Silent login succeeds (lands authenticated) when a valid Auth0 session exists

Notes

  • frontend/app/plugins/auth.client.ts is a protected file — code owner review required before merge
  • Tracked under LFXV2-2255

🤖 Generated with Claude Code

Signed-off-by: Efren Lim <elim@linuxfoundation.org>
Copilot AI review requested due to automatic review settings June 17, 2026 01:33
@emlimlf emlimlf requested review from gaspergrom and joanagmaia June 17, 2026 01:35

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 hardens the Auth0 login/callback flow to prevent an infinite silent-login redirect loop (and repeated auth=success query growth) when cross-app cookie name conflicts cause JWT validation to fail.

Changes:

  • In callback.ts, treat additional silent-auth failure cases as non-fatal redirects and strip stale auth params before redirecting.
  • Ensure successful callback redirects don’t accumulate repeated auth=success params across redirect cycles.
  • Preserve the silentLoginAttempted guard flag across silent login redirects so the client can stop retrying.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
frontend/server/api/auth/callback.ts Cleans auth query handling for silent failures and success redirects to prevent redirect loops / param accumulation.
frontend/composables/useAuth.ts Avoids resetting the silent-attempt flag during silent logins so retry prevention works.
frontend/app/plugins/auth.client.ts Strips auth from the client redirectTo path before triggering silent login (protected file per hook).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +203 to +210
const successUrl = new URL(redirectTo, 'https://placeholder.example');
successUrl.searchParams.delete('auth');
const cleanRedirectTo =
successUrl.pathname + (successUrl.search || '') + (successUrl.hash || '');
const finalRedirect =
redirectTo === '/'
!cleanRedirectTo || cleanRedirectTo === '/'
? '/?auth=success'
: `${redirectTo}${redirectTo.includes('?') ? '&' : '?'}auth=success`;
: `${cleanRedirectTo}${cleanRedirectTo.includes('?') ? '&' : '?'}auth=success`;
emlimlf added 2 commits June 17, 2026 09:51
…app conflict LFXV2-2255

Signed-off-by: Efren Lim <elim@linuxfoundation.org>
…auth LFXV2-2255

Signed-off-by: Efren Lim <elim@linuxfoundation.org>
Copilot AI review requested due to automatic review settings June 17, 2026 11:42

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 3 comments.

Comment on lines 224 to +228
// Clean up all auth cookies on unrecoverable error
deleteCookie(event, 'auth_pkce');
deleteCookie(event, 'auth_redirect_to');
deleteCookie(event, 'auth_oidc_token');
deleteCookie(event, 'auth_refresh_token');
deleteCookie(event, 'insights_oidc_token');
deleteCookie(event, 'insights_refresh_token');
Comment on lines +36 to +39
// auth_pkce and auth_redirect_to are short-lived flow cookies — no explicit domain set,
// so plain deleteCookie is fine here.
deleteCookie(event, 'auth_pkce');
deleteCookie(event, 'auth_redirect_to');
Comment on lines 87 to 90
const logoutHandler = async () => {
document.cookie = 'auth_oidc_token=; Path=/; Max-Age=0; SameSite=None; Secure';
document.cookie = 'insights_oidc_token=; Path=/; Max-Age=0; SameSite=None; Secure';
await logout();
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants