fix: header sign in honors configured path and preserves callbackurl (#961)#962
Conversation
There was a problem hiding this comment.
Pull request overview
This PR updates the library Header authentication UX to (1) honor a consumer-configured sign-in path and (2) preserve the user’s current location via a callbackUrl query parameter, improving compatibility with NextAuth pages.signIn configurations and middleware-driven flows.
Changes:
- Widened
HeaderProps.authenticationEnabled(and related props) frombooleantoboolean | string, where a string represents a custom sign-in path. - Updated the header Sign In navigation to push
{ pathname, query: { callbackUrl: asPath } }and introduced agetSignInPathhelper to keep decoding logic out of the component. - Added unit/component tests covering default and custom destinations, callbackUrl propagation, and basic rendering behavior.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| tests/getSignInPath.test.ts | Adds unit coverage for getSignInPath default vs custom path behavior. |
| tests/authentication.test.tsx | Adds component-level coverage for Sign In button rendering and Router navigation payload (including callbackUrl). |
| src/components/Layout/components/Header/hooks/useHeaderVisibility.ts | Coerces isActionsIn to boolean to avoid union type leakage after widening authenticationEnabled. |
| src/components/Layout/components/Header/header.tsx | Updates HeaderProps typing + documentation for authenticationEnabled behavior. |
| src/components/Layout/components/Header/components/Content/components/Actions/components/Menu/components/Toolbar/toolbar.tsx | Prop type widened to match HeaderProps change so menu toolbar passes through custom sign-in path. |
| src/components/Layout/components/Header/components/Content/components/Actions/components/Authentication/utils.ts | Introduces getSignInPath helper encapsulating default vs configured sign-in path selection. |
| src/components/Layout/components/Header/components/Content/components/Actions/components/Authentication/authentication.tsx | Updates Sign In click handler to navigate to resolved path and include callbackUrl from asPath. |
…961) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
9abcaab to
a327097
Compare
Code review findingsTargeted, correct fix with good test coverage and full back-compat — no blocking issues. A few notes for consideration: 1. 2. 3. 4. Mixed Verified: rules-of-hooks respected ( |
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Summary
HeaderProps.authenticationEnabledfrombooleantoboolean | string. Passtrue(current default) for the legacy/logindestination, or pass a path string to tell the Sign In button where to navigate (e.g. when NextAuth'spages.signInis configured elsewhere).asPathas a?callbackUrl=query param, so paired withLoginView's query-callbackUrl preference (feat: LoginView should honor NextAuth callbackUrl from the query string (middleware-friendly) #955) the user lands back where they were after authenticating.getSignInPathhelper colocated inAuthentication/utils.tskeeps the prop-decoding logic out of the component body.Closes #961
Why
Today the Sign In button does
Router.push("/login")unconditionally, ignoring both the consumer's NextAuthpages.signInconfig and the user's current location. Repro for a consumer withpages.signIn = "/":/help(public).Router.push("/login")./login→ redirects to/?callbackUrl=/login./loginpath (callbackUrl preserved via feat: LoginView should honor NextAuth callbackUrl from the query string (middleware-friendly) #955), which doesn't exist in the consumer app → they end up wherever the consumer's catch-all routes 404s to.End result: the user wanted to be back on
/helpbut lands somewhere unrelated.Back-compat
authenticationEnabled?: boolean→authenticationEnabled?: boolean | stringis purely additive. Existing consumers passingtrue/false/undefinedsee no behavior change for the destination (still/login).?callbackUrl=is appended unconditionally — but with no consumer of that query param, it's a no-op cosmetic addition. Consumers running feat: LoginView should honor NextAuth callbackUrl from the query string (middleware-friendly) #955-awareLoginViewstart honoring it.useHeaderVisibility.isActionsIngot aBoolean(...)coercion so the union widening doesn't leak into the visibility return type.Test plan
tests/getSignInPath.test.ts(2 cases) — pure-helper coverage.tests/authentication.test.tsx(4 cases) — covers: not rendered when disabled; default/logindestination whentrue; custom path when string;closeMenucalled after navigation. All assertions check thatRouter.pushreceives{ pathname, query: { callbackUrl: <asPath> } }.npm run lint,npm run check-format,npx tsc, fullnpm test(475 tests) all clean.hca-atlas-tracker) via local tarball install: Sign In from/requesting-elevated-permissionsnow navigates to/?callbackUrl=/requesting-elevated-permissions, and after Google OAuth the user lands back on/requesting-elevated-permissions(no detour through/atlases).🤖 Generated with Claude Code