Skip to content

Auth: land back on the /app/<name> the user came for after login/signup#3435

Open
jelveh wants to merge 1 commit into
mainfrom
auth-land-on-app
Open

Auth: land back on the /app/<name> the user came for after login/signup#3435
jelveh wants to merge 1 commit into
mainfrom
auth-land-on-app

Conversation

@jelveh

@jelveh jelveh commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Problem

If a logged-out user lands on an app URL (/app/<name>) and has to log in or sign up, several auth paths dumped them at the root dashboard afterward instead of the app they came for:

  • OIDC login/signup: the GUI only sent return_to for /desktop and /dashboard, and the backend whitelist only accepted those two — OIDC from an app landing always redirected to /.
  • Password signup: UIWindowSignup defaulted its post-success redirect to /, so signup reached via the session list, ?action=signup, or in-app signup prompts (IPC.js) lost the app.
  • OIDC errors: error redirects always went to /?action=…, so even after the user recovered (e.g. account-not-found bounced to signup, then signed up) the app was gone.

(Password login already redirected back to the current URL; that path is unchanged in behavior.)

Changes

New src/gui/src/helpers/auth_redirect.js

  • get_auth_redirect_url() — post-auth destination: stay on the page auth started from; standalone /action/* pages go to /; strips action/auth_error (+ their message/request_code companions) so the reload doesn't re-open the auth window or forward auth params to the app as launch args.
  • get_oidc_return_to() — the return_to to send when starting an OIDC flow; now includes /app/<name> landings (trailing slash normalized).

UIWindowLogin.js / UIWindowSignup.js — both use the helpers for their default redirect_url and OIDC return_to.

OIDCController.ts

  • Whitelist extracted into a shared isWhitelistedReturnPath() accepting /desktop, /dashboard, and /app/<name> (charset mirrors APP_NAME_REGEX: [a-zA-Z0-9_-]{1,100} — still a strict whitelist, no open-redirect surface; the callback's same-origin clamp is unchanged).
  • buildErrorRedirectUrl() now lands error redirects on the whitelisted originating page (from the signed state's redirect_uri, path re-checked against the whitelist) instead of always /. Popup-flow error URLs are unchanged.

Testing

  • OIDC controller suite: 47/47 pass, including 4 new tests — return_to accepted (/app/<name>) and rejected (extra segments, bad charset, >100 chars, //evil.test) on start; success redirect to /app/<name>; error redirect keeping /app/<name>.
  • tsc --noEmit clean; GUI webpack build clean.
  • Verified live on local dev: first-visit temp-user creation, password signup (including the email-confirmation gate mid-flow), and password login as a returning visitor all land on /app/camera with the app open. OIDC not exercised live (no provider configured locally); covered by the unit tests above.

Landing on /app/<name> logged-out and authenticating used to dump the
user at the root dashboard on several paths, losing the app they came
for:

- OIDC login/signup only sent return_to for /desktop and /dashboard
  (and the backend whitelist only accepted those two), so OIDC from an
  app landing redirected to /.
- UIWindowSignup defaulted its post-success redirect to /, so password
  signup reached via the session list, ?action=signup, or in-app signup
  prompts (IPC.js) lost the app.
- OIDC error redirects always went to /?action=..., so a recovered
  attempt (e.g. account-not-found bounced to signup) also lost the app.

New helpers in src/gui/src/helpers/auth_redirect.js:
- get_auth_redirect_url(): stay on the page auth started from;
  /action/* pages go to /; strips action/auth_error/message/
  request_code so the reload doesn't re-open the auth window or pass
  auth params through to the app as launch args.
- get_oidc_return_to(): pathname when whitelistable, now including
  /app/<name> (trailing slash normalized).

Backend (OIDCController):
- Shared isWhitelistedReturnPath() accepts /desktop, /dashboard, and
  /app/<name> (charset mirrors APP_NAME_REGEX — no open redirect).
- buildErrorRedirectUrl() lands on the whitelisted originating page
  from the signed state's redirect_uri instead of always /.

Tested: 47/47 OIDC controller tests pass (4 new: return_to accepted/
rejected on start, success redirect to /app/<name>, error redirect
keeping /app/<name>); verified live on local dev for first-visit temp
user, password signup (incl. email-confirmation gate), and password
login — all land on /app/camera with the app open.
@github-actions

Copy link
Copy Markdown
Contributor

Coverage Report

Status Category Percentage Covered / Total
🔵 Lines 77.08%
⬆️ +0.01%
16755 / 21735
🔵 Statements 75.37%
⬆️ +0.01%
17841 / 23670
🔵 Functions 73.68%
🟰 ±0%
2764 / 3751
🔵 Branches 63.94%
⬆️ +0.02%
11753 / 18381
File Coverage
File Stmts Branches Functions Lines Uncovered Lines
Changed Files
src/backend/controllers/oidc/OIDCController.ts 97.56%
⬆️ +0.60%
82.27%
⬆️ +1.05%
100%
🟰 ±0%
98.46%
⬆️ +0.57%
135, 139, 285-289, 577-579, 651
Generated in workflow #565 for commit 3ac1983 by the Vitest Coverage Report Action

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.

1 participant