Warning
This document is for an old release of Galaxy. You can alternatively view this page in the latest release if it exists or view the top of the latest release's documentation.
OIDC authentication and account confirmation
Galaxy 25.1 has two authentication implementations. AuthnzManager routes
Keycloak, CILogon, and Custos to OIDCAuthnzBase in custos_authnz.py; other
providers use PSAAuthnz. Only the legacy OIDC implementation supports deferred
account creation on this release. It stores associations in CustosAuthnzToken,
using the provider’s subject as external_user_id. This backport does not migrate
those associations or add a confirmation pipeline to python-social-auth.
Request flow
Start authentication.
OIDCAuthnzBase.authenticatecreates the provider redirect and saves the nonce hash and optional PKCE verifier inFlowState. OAuth state identifies a record bound to the browser’s Galaxy session and the canonical provider name. These values no longer rely on separate cookies.Handle the callback.
callbackconsumes authentication state before the code exchange. It restores the PKCE verifier and supplies the consumed state toOAuth2Session, which checks the callback URL’s state during the exchange. A failed exchange or identity check requires a new login attempt.Establish identity.
_process_tokenreads the ID token returned directly by the configured token endpoint and checks the nonce, issuer, audience, expiry, subject, and authorized party when present. If it needs UserInfo for the email address, UserInfo’s subject must match the ID token’s subject. As in the legacy backend, trust in the token response relies on the direct exchange with the configured endpoint, rather than local signature verification. Production providers require HTTPS with certificate verification enabled. The callback never accepts a browser-supplied ID token.Defer creation. When a new account requires confirmation, the callback saves the established identity, provider tokens, and their original expiration times in a server-side confirmation record. It redirects to
login/start?confirm=true&provider=...&confirmation_id=.... The URL contains no provider credentials. Existing-account login, explicit linking, andfixed_delegated_authretain their legacy paths.Confirm or cancel.
NewUserConfirmation.vuesends a form-encoded POST to/authnz/{provider}/create_useror/authnz/{provider}/cancel_user_creation, withconfirmation_idandsession_csrf_tokenin the body. Both actions enforce POST, CSRF protection, and anonymous registration context, including through generic controller routes. Legacy token and JSONP parameters are rejected. Confirmation consumes the record, rejects existing email or subject associations, and creates throughUserManager, preserving activation policy. Cancellation consumes the record without creating an account.Refresh browser state. Successful confirmation logs in the user and returns JSON containing
redirect_uri. The client performs a full navigation to reload user and CSRF state. Cancellation returns an empty JSON object and the client returns to login. Responses useCache-Control: no-store.
State and failure boundaries
FlowState stores records in the existing PSAPartial table under a namespace
and negative step numbers separate from resumable python-social-auth pipelines.
No database migration is needed. Each record is bound to the Galaxy session,
canonical provider, and purpose (authentication or confirmation). Records
expire after at most ten minutes; confirmation expiry is also bounded by the ID
token’s expiry. A new attempt replaces pending state for that browser/provider.
Consumption uses a conditional database delete, checks that the Galaxy session is still valid, and requires exactly one affected row. Do not replace this with an unconditional delete following a read: two workers could reuse the same record. Consumption commits before account-creation helpers, which can commit independently. A subsequent exchange, account-creation, or association failure must not make the record reusable. Email and subject checks reject associations created while the confirmation page was open; database uniqueness constraints also guard concurrent inserts.
Confirmation never decodes tokens or recomputes identity from client input. It preserves the callback’s subject and token expiration times. Token refresh, association persistence, and provider logout continue through the legacy backend. In-flight cookie-based logins and old confirmation links must be restarted after upgrading.
Regression coverage
test/integration/oidc/test_auth_oidc.py uses real Docker Keycloak and a Galaxy
server. Its confirmation class enables PKCE and covers POST/CSRF, account
creation, session refresh, cancellation, browser isolation, and callback replay.
The other classes cover legacy login, account linking, logout, bearer tokens,
and the independent PSA path. Run these using:
./run_tests.sh -integration test/integration/oidc/test_auth_oidc.py
test/unit/authnz/test_flow_state.py covers persistence, expiry, purpose and
provider binding, invalidated sessions, and concurrent consumption. The
PostgreSQL unit-test workflow also runs it against PostgreSQL.
test_custos_confirmation.py covers forged browser credentials, identity
validation, activation policy, collision checks, and failures after consumption.
test_authnz_controller.py tests HTTP guards. The Jest Login component tests
cover confirmation bodies, cancellation, errors, duplicate submission, legacy
links, and full navigation after login, including applications under a URL prefix.