Repository navigation
fix(sso): stop sending OIDC logins to localhost; return users to the UI - #136
Merged
Merged
Conversation
Two things sent an SSO login to the wrong place. The redirect/callback URL registered with the identity provider came from ANGLES_BASE_URL alone, defaulting to http://localhost:3000. Deployments set ANGLES_API_BASE_URL (for the UI and Swagger) and reasonably expected that to be used, and docker-compose passed ANGLES_BASE_URL=http://localhost:3000 explicitly whatever was configured. The base URL now falls back to ANGLES_API_BASE_URL (taking the Swagger scheme when it has none) before localhost, and docker-compose leaves ANGLES_BASE_URL empty unless set. After a login the API redirected to `/` (or `/login?error=true`) on its own origin, but the UI is usually on another port or host. The UI now passes its origin as `returnTo` when it starts a login; the API keeps it in the session for that login only and redirects back to it. Only an http(s) origin on the API's own host is accepted (the same rule CORS applies, now shared in app/utils/ui-origin.js), so it cannot be used as an open redirect. Without one the redirect stays relative, as before. A SAML assertion is usually posted back cross-site without the session cookie, so SAML keeps the old behaviour. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KgQXSUjuLVXmLWxobnMfSf
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
An Okta (OIDC) login could send the browser to
localhost, and after a successful login it ended up on the API rather than the UI. This PR fixes the two backend causes. The third cause is in the UI; see AnglesHQ/angles-ui (claude/fix-localhost-api-urls).1. The redirect URI registered with the IdP ignored the configured API URL
Each provider's callback URL came from
ANGLES_BASE_URLalone, which defaults tohttp://localhost:3000. Deployments setANGLES_API_BASE_URL, which the UI and Swagger already use, and expected SSO to use it too.docker-compose.ymlalso passedANGLES_BASE_URL=http://localhost:3000explicitly, whatever else was configured.ANGLES_BASE_URL, thenANGLES_API_BASE_URL, thenhttp://localhost:3000. A value without a scheme takes the first ofSWAGGER_SCHEMES, as Swagger does.docker-compose.yml,ANGLES_BASE_URLis empty unless set, andANGLES_API_BASE_URLis${ANGLES_API_BASE_URL:-http://localhost:3000}on both services.2. After the IdP, the API redirected to its own origin
The callback redirected to
/(or/login?error=true) relative to the API. The UI is usually on another port (3001) or host, so the user landed on the API.returnTo. The API keeps it in the session for that login only and redirects back to${origin}/or${origin}/login?error=true. The callback reads it beforereq.logIn()replaces the session.localhostand127.0.0.1treated as one host. It is now shared inapp/utils/ui-origin.js, which CORS uses as well. Paths, credentials, other hosts,javascript:and protocol-relative values are all ignored.returnTo, for example from an older UI, the redirect stays relative, as before.docs/authentication.mdsays so.Docs and config
docs/authentication.mddocuments the newANGLES_BASE_URLfallback and the return to the UI.docker-compose.ymland the Kubernetes ConfigMap are updated.Testing
test/sso-urls.tests.js: base URL resolution, and which origins are accepted.test/settings.tests.js, run against the real signed-token test IdP: return to the UI, a denied login returning to the UI login page, keeping only the origin, ignoring a foreign host and invalid values, and forgettingreturnToafter a login.npm testagainst a local MongoDB: 620 passing.npx eslint app test server.js configis clean.127.0.0.2:3000with onlyANGLES_API_BASE_URLset, the UI from the companion PR on127.0.0.2:3001, and the test OIDC provider as the IdP. Clicking "Sign in with Okta" in Chromium went UI → API (?returnTo=http://127.0.0.2:3001) → IdP withredirect_uri=http://127.0.0.2:3000/rest/api/v1.0/auth/sso/okta/callback→ API callback →http://127.0.0.2:3001/, signed in as the Okta user.Deploying
Deployments that set
ANGLES_BASE_URLare unaffected. Deployments that didn't will now registerANGLES_API_BASE_URLwith their identity provider, so make sure that URL is the one registered there. The admin UI shows each provider's callback URL.🤖 Generated with Claude Code
https://claude.ai/code/session_01KgQXSUjuLVXmLWxobnMfSf
Generated by Claude Code