fix(sso): support IdP-initiated chiclet flow on /auth/sso/login#4679
Open
igor-raits wants to merge 1 commit intoIBM:mainfrom
Open
fix(sso): support IdP-initiated chiclet flow on /auth/sso/login#4679igor-raits wants to merge 1 commit intoIBM:mainfrom
igor-raits wants to merge 1 commit intoIBM:mainfrom
Conversation
Two changes to mcpgateway/routers/sso.py so an Okta (or any OIDC
provider) IdP-initiated login URL pointed at /auth/sso/login/{provider}
just works as a chiclet entry point, while the existing SP-initiated
form on the gateway's login page keeps behaving as before.
1. Make `redirect_uri` optional with a sensible default. When omitted,
build it from `request.url_for("handle_sso_callback", ...)` so it
resolves to this gateway's own /auth/sso/callback/{provider} on the
request origin (honouring app_root_path / proxy headers). Skipping
the user-input `_validate_redirect_uri` check is safe as long as the
request host is itself trustworthy (proxy-normalized in production);
that check exists to defend against open redirects on caller-supplied
URIs, not server-built ones.
2. Content-negotiate the response. Browser navigation (Accept: text/html
without application/json) gets a 302 straight to the IdP's
authorization URL; XHR clients sending Accept: application/json keep
getting the SSOLoginResponse JSON they parse today. The
session-binding cookie is set on the RedirectResponse explicitly
because returning a Response object bypasses the injected \`response\`
parameter.
Combined effect: an Okta app can register
Login Flow = Redirect to app to initiate login (OIDC Compliant)
Login URI = https://<host>/auth/sso/login/okta
and clicking the chiclet lands the user signed in at /admin in one hop.
The existing /admin/login form path is byte-identical to before.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Signed-off-by: Igor Raits <igor.raits@gmail.com>
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.
✨ Feature / Enhancement PR
🔗 Epic / Issue
Link to the epic or parent issue:
Closes #
🚀 Summary (1-2 sentences)
Make
/auth/sso/login/{provider_id}usable as an IdP-initiated chiclet entry point:redirect_uribecomes optional (server-built default) and the response is content-negotiated so browsers get a 302 to the IdP while XHR clients keep getting JSON.🧪 Checks
make lintpasses (black,ruffclean on the touched file)make testpasses📓 Notes
Two changes to
mcpgateway/routers/sso.py:redirect_uriis now optional. When omitted, it is built fromrequest.url_for("handle_sso_callback", ...)so it resolves to this gateway's own/auth/sso/callback/{provider_id}on the request origin (honouringapp_root_path/ proxy headers). Skipping the user-input_validate_redirect_uricheck is safe as long as the request host is itself trustworthy (proxy-normalized in production); that check exists to defend against open redirects on caller-supplied URIs, not server-built ones.Content-negotiated response. Browser navigation (
Accept: text/htmlwithoutapplication/json) gets a 302 straight to the IdP's authorization URL; XHR clients sendingAccept: application/jsonkeep getting theSSOLoginResponseJSON they parse today. The session-binding cookie is set on theRedirectResponseexplicitly because returning aResponseobject bypasses the injectedresponseparameter.Combined effect: an Okta app can register
and clicking the chiclet lands the user signed in at
/adminin one hop. The existing/admin/loginform path is byte-identical to before.sequenceDiagram participant User participant Okta participant Gateway User->>Okta: clicks chiclet Okta->>User: 302 to /auth/sso/login/okta User->>Gateway: GET /auth/sso/login/okta (Accept: text/html) Gateway->>User: 302 to Okta /authorize (cookie set) User->>Okta: /authorize Okta->>User: 302 to /auth/sso/callback/okta?code=... User->>Gateway: GET /auth/sso/callback/okta Gateway->>User: signed in, 302 to /admin