PLUGINS-350 Opt-in OIDC auto-login (prompt=none) - #10
Merged
Conversation
When a provider sets openid.<providerId>.autoLogin=true, an anonymous visitor to the XNAT login page is sent into that provider's OIDC flow with prompt=none, skipping the "Sign in with ..." button. If the visitor already has a session at the provider they are logged straight into XNAT; otherwise the provider reports that interaction is required and the user is returned to the normal login page. - OpenIdLoginExtension: on Login.vm, redirect an anonymous guest to /openid-login?providerId=<p>&prompt=none. Guarded by a short-lived first-party cookie (AUTO_LOGIN_ATTEMPTED_COOKIE, ~2 min) so it can't loop — a later visit retries; only for guests, only when the response is not already committed, and never over a pending error message. - PkceAuthorizationCodeAccessTokenProvider: forward a 'prompt' request parameter into the authorization request (absent on normal button-click logins). - OpenIdConnectFilter: intercept an ?error= callback. An interaction-required error (login_required and friends) is the expected "no session to reuse" result and returns the user to the login page quietly; any other error is a genuine failure. The decision keys off the OIDC error code alone, and the loop guard is a first-party cookie, so neither depends on server-side session state surviving the Login.vm -> provider -> callback redirect chain, across which the XNAT session is not reliably continuous. - OpenIdAuthPlugin.getAutoLoginProviderId(): resolves the single provider that opts in (warns if more than one). Other providers stay configured; their buttons still show. Opt-in and off by default; documented in the README and sample properties. On an open (requireLogin=false) XNAT this never touches normal anonymous browsing, which is served by Index.vm, not Login.vm. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
kathrynalpert
force-pushed
the
feature/auto-login
branch
from
July 28, 2026 13:09
7b7ad98 to
4738ee4
Compare
kathrynalpert
marked this pull request as ready for review
July 28, 2026 14:09
johnflavin
approved these changes
Jul 28, 2026
mohana-xw
approved these changes
Jul 28, 2026
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.
Adds an opt-in
openid.{provider}.autoLoginflag. With it on, an anonymous visitor who lands on the XNAT login page gets sent straight into the provider's OIDC flow withprompt=noneinstead of having to click "Sign in with …". In an SSO setup they're already logged into the provider for everything else, so they just end up in XNAT logged in. If they don't have a session at the provider, it comes back withlogin_requiredand we show the normal login page.The login-screen extension issues the redirect, the PKCE provider forwards the
promptparam, and the filter reads the callback.Worth calling out:
Login.vmand the callback — the Turbine login page and the Spring filter don't reliably see the sameHttpSession. So the guard is a short-lived first-party cookie (OPENID_AUTOLOGIN_TRIED) rather than a session attribute, and the fallback decision keys off the OIDC error code alone (login_requiredand the other interaction-required codes only come back from aprompt=nonerequest). The first cut leaned on a session flag for both and got it wrong — a failed attempt showed "OpenID Connect login failed" instead of the login page, because the flag was already gone by the time the callback came back. Best evidence points to the Turbine→Spring session handoff rather than pod-hopping (sticky sessions are configured) — inferred from the flow, not confirmed by capturing session IDs.prompt=none— it's standard OIDC, but not universal.requireLogin=false) XNAT this doesn't touch normal anonymous browsing — that's served byIndex.vm, notLogin.vm, so the extension never runs there.Testing
Built and deployed to dev04, which sits behind oauth2-proxy. The edge proxy authenticates everything before XNAT sees it, so to reach
Login.vmanonymously I temporarily pulled the oauth2-proxy forward-auth middleware off the XNAT ingress (and put it back after).prompt=none→login_required→ land back on the normal login page, no error banner. This is the case the fix is about.Unit tests cover the redirect decision matrix (guest vs authenticated, one-shot guard, response-already-committed, provider opt-in), the
promptforwarding, and the interaction-required error classification.