Skip to content

fix(auth): give context on the login page and tolerate transient 401s - #76425

Draft
posthog[bot] wants to merge 2 commits into
masterfrom
posthog-self-driving/fixauth-stop-dead-ending-users-on-a-e0553f
Draft

fix(auth): give context on the login page and tolerate transient 401s#76425
posthog[bot] wants to merge 2 commits into
masterfrom
posthog-self-driving/fixauth-stop-dead-ending-users-on-a-e0553f

Conversation

@posthog

@posthog posthog Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

Problem

  • Users bounced to /login had no explanation for why they were there or where they were headed. ?next= is only ever consumed post-auth by getRelativeNextPath (frontend/src/lib/utils/url.ts) as a redirect target; it is never shown to the user.
  • Separately, apiStatusLogic's 401 auto-logout (frontend/src/lib/logic/apiStatusLogic.ts) re-checks api/users/@me/ exactly once and logs the user out (logout(true)) if that also 401s, with no tolerance for a single transient blip (a load-balancer hiccup, a race during token rotation).
  • Both land on the one path every user has to walk through, so the friction is broad even though each individual case is recoverable (a reload or re-login works).

Changes

  • Login page: when the login-required redirect carries a ?next= path (and the session-risk banner isn't already covering it), show a banner naming where the user was headed, so a returning tab reads as recoverable instead of a mystery.

    Login page showing a session-expired banner naming the redirect destination

  • apiStatusLogic: on a 401, give a live session one more chance. If the immediate recheck still comes back unauthorized, wait a couple of seconds and check once more before ejecting the user.

How did you test this code?

  • Added sessionExpiredRedirectPath cases to loginLogic.test.ts covering the next-present, session-risk-present, no-next, and sanitized-away-next paths - guards the banner condition logic.
  • Added a case to apiStatusLogic.test.ts asserting a transient 401 that clears on recheck does not trigger logout, alongside the existing always-401 and impersonation cases.
  • Ran the full loginLogic.test.ts and apiStatusLogic.test.ts suites (29 tests, all passing).
  • Rendered the new SessionExpired Login story in Storybook via a headless browser to visually confirm the banner text and placement (screenshot above), and confirmed the existing SSOError/session-risk banners still render as before.

Automatic notifications

  • Publish to changelog?
  • Alert Sales and Marketing teams?

Docs update

N/A - internal auth UX behavior, no documented workflow changed.

🤖 Agent context

Autonomy: Fully autonomous

I (Claude) investigated two session recordings referenced in the originating report: one stuck 55 minutes on /login?next=/settings/user-api-keys after an expired-session bounce, another showing an authenticated user pushed to a bare /login who returned to the app 32 seconds later without re-entering credentials. I confirmed the auto-logout listener already calls logout(true) (which preserves the current location as next), so it does not explain the bare-/login bounce by itself - I've noted that as an open question rather than claiming it as the root cause. The two changes here address the two concrete, confirmable causes: the login page giving no context, and the auto-logout having zero tolerance for a transient 401.

No competing open PR or issue was found for this (searched by keywords and by the touched files).

Skills invoked: /writing-user-facing-copy (banner copy), /writing-tests (before adding test cases).


Created with PostHog Desktop from this inbox report.

Users bounced to `/login` had no idea why they were there or where they were headed, and a single transient 401 was enough to auto-log-out an otherwise-valid session.

- Show a banner on the login page naming the page the user was redirected from, when `?next=` is present (unless the session-risk banner already covers it).
- Tolerate a single transient 401 on `apiStatusLogic`'s auto-logout check by rechecking once, a couple seconds later, before ejecting a live session.

Generated-By: PostHog Code
Task-Id: 14bc39fc-c83a-435f-b6ea-14615195c029
@trunk-io

trunk-io Bot commented Aug 2, 2026

Copy link
Copy Markdown

Merging to master in this repository is managed by Trunk.

  • To merge this pull request, check the box to the left or comment /trunk merge below.

After your PR is submitted to the merge queue, this comment will be automatically updated with its status. If the PR fails, failure details will also be posted here

@github-actions

github-actions Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

🤖 CI report

⚠️ Bundle size — 🔺 +339 B (+0.0%)

Uncompressed size of every built .js bundle, compared against the base branch.

Total: 65.51 MiB · 🔺 +339 B (+0.0%)

No file changed by more than 1000 B.

Posted automatically by build-bundle-size-report · uncompressed bytes from dist-report

Eager graph — within budget

How much code each root ships on the eager path — downloaded and parsed before the surface is interactive. Measured from the esbuild output chunks (post-tree-shake, static imports only); lazy import() / React.lazy chunks are not counted.

Root Eager (shipped) Δ vs base Budget
entry (logged-out pages, app bootstrap)
src/index.tsx
1.25 MiB · 22 files no change ███░░░░░░░ 27.7% of 4.51 MiB
authenticated shell (every logged-in page)
src/scenes/AuthenticatedShell.tsx
8.14 MiB · 3,035 files 🔺 +331 B (+0.0%) ████████░░ 83.8% of 9.71 MiB

🟢 node_modules/monaco-editor/ stays out of src/index.tsx
🟢 src/lib/components/ActivityLog/describers stays out of src/index.tsx
🟢 [object Object] stays out of src/index.tsx
🟢 [object Object] stays out of src/index.tsx
🟢 node_modules/monaco-editor/ stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/lib/components/ActivityLog/describers stays out of src/scenes/AuthenticatedShell.tsx
🟢 [object Object] stays out of src/scenes/AuthenticatedShell.tsx
🟢 [object Object] stays out of src/scenes/AuthenticatedShell.tsx

Largest files eagerly shipped from src/index.tsx
Size File
126.8 KiB ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js
24.6 KiB ../node_modules/.pnpm/buffer@6.0.3/node_modules/buffer/index.js
6.3 KiB ../node_modules/.pnpm/react@18.3.1/node_modules/react/cjs/react.production.min.js
4.5 KiB ../node_modules/.pnpm/@jspm+core@2.1.0/node_modules/@jspm/core/nodelibs/browser/process.js
3.9 KiB ../node_modules/.pnpm/scheduler@0.23.2/node_modules/scheduler/cjs/scheduler.production.min.js
1.4 KiB ../node_modules/.pnpm/base64-js@1.5.1/node_modules/base64-js/index.js
1.3 KiB src/RootErrorBoundary.tsx
912 B ../node_modules/.pnpm/ieee754@1.2.1/node_modules/ieee754/index.js
789 B src/scenes/ChunkLoadErrorBoundary.tsx
762 B src/index.tsx
Largest files eagerly shipped from src/scenes/AuthenticatedShell.tsx
Size File
285.6 KiB ../node_modules/.pnpm/posthog-js@1.409.5/node_modules/posthog-js/dist/rrweb.js
267.7 KiB ../node_modules/.pnpm/@posthog+icons@0.38.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js
235.5 KiB src/taxonomy/core-filter-definitions-by-group.json
231.5 KiB ../node_modules/.pnpm/posthog-js@1.409.5/node_modules/posthog-js/dist/module.js
154.3 KiB ../node_modules/.pnpm/re2js@0.4.1/node_modules/re2js/build/index.esm.js
126.8 KiB ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js
105.3 KiB src/lib/api.ts
94.7 KiB ../packages/quill/packages/quill/dist/index.js
93.3 KiB ../node_modules/.pnpm/prosemirror-view@1.40.1/node_modules/prosemirror-view/dist/index.js
90.6 KiB ../node_modules/.pnpm/@tiptap+core@3.20.6_@tiptap+pm@3.20.6/node_modules/@tiptap/core/dist/index.js

Posted automatically by check-eager-graph · sizes are eager output bytes (shipped, post-tree-shake) from the esbuild metafile · part of #32479

Toolbar bundle — eager 2.19 MiB within budget

What the toolbar ships to customer pages, measured from the esbuild output (minified, post-tree-shake). The eager set is the entry plus everything statically imported from it — fetched before any feature runs; deferred chunks load lazily. The eager guardrail is 5.72 MiB. Each output file must also stay below 10 MB, where CloudFront stops compressing it. The module boundary is enforced separately by check-toolbar-graph.

Metric Size Δ vs base Budget
Eager (shipped)
entry + static imports
2.19 MiB · 17 files no change ████░░░░░░ 38.3% of 5.72 MiB
Deferred (lazy) 2.08 MiB · 33 files no change n/a — loads on demand
Loader dist/toolbar.js 1.1 KiB no change █░░░░░░░░░ 5.8% of 19.5 KiB
Largest eagerly-shipped chunks
Size File
718.3 KiB dist/toolbar/toolbar-app-FT4UJ3IP.css
551.4 KiB dist/toolbar/chunk-chunk-AGSGCCBT.js
484.6 KiB dist/toolbar/chunk-chunk-T44C2V5C.js
133.6 KiB dist/toolbar/chunk-chunk-KBLX73CM.js
131.8 KiB dist/toolbar/chunk-chunk-T5KY5WYR.js
71.0 KiB dist/toolbar/toolbar-app-FKUW2FOM.js
69.0 KiB dist/toolbar/chunk-chunk-27JL52RE.js
35.6 KiB dist/toolbar/chunk-chunk-3JVI3ZTF.js
20.9 KiB dist/toolbar/chunk-chunk-HJ3ZJMTU.js
12.2 KiB dist/toolbar/chunk-chunk-PIK3PADE.js

Posted automatically by check-toolbar-size · sizes are toolbar output bytes (shipped, post-tree-shake) from the esbuild metafile

Dist folder size — 🔺 +10.1 KiB (+0.0%)

Total size of the built frontend/dist folder (all assets), compared against the base branch.

Total: 1381.31 MiB · 🔺 +10.1 KiB (+0.0%)

@posthog posthog Bot added the run-ci-frontend Force ci-storybook's full visual-regression matrix to run even on a draft PR label Aug 2, 2026
Also triggers a fresh CI run so the run-ci-frontend label (already applied) forces the full sharded frontend Jest matrix — the draft's selective related-tests run for this PR's changed files expands via the import graph to nearly the whole suite and blows the single job's 20 minute timeout.

Generated-By: PostHog Code
Task-Id: 14bc39fc-c83a-435f-b6ea-14615195c029
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

run-ci-frontend Force ci-storybook's full visual-regression matrix to run even on a draft PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants