Repository navigation
feat(auth): accept an identity provider access token on the API for native clients - #1914
Merged
Merged
Conversation
…ative clients A native client, such as a mobile app, signs in to the identity provider itself as a public PKCE client and calls Studio's API with "Authorization: Bearer <access token>". Studio accepted only the session cookie, so that could not work. Opt-in through OIDC_BEARER_AUDIENCE under NEXT_PUBLIC_AUTH_PROVIDER=oidc. Unset, the Authorization header is ignored outside /api/mcp as before, so a reverse proxy that forwards Basic credentials changes nothing. The verifier is one leaf module (src/lib/oidc-bearer.ts) that the proxy and getSession() both call. It accepts an asymmetrically signed JWT from the issuer's key set, for the audience, unexpired, not an ID token, from OIDC_BEARER_CLIENT_IDS when set, naming a subject, an email or username and a role. A refusal is 401 with the bearer challenge and is audited; a provider that cannot be reached is 503. A bearer session sets and clears no cookie and cannot mint an MCP token. Under governance the access token meets the same sign-in rule as a cookie session.
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
…n copy Without governance the session's username keys the person's saved work, rate limit and audit lines. Both the OIDC callback and the bearer channel took it from email, else preferred_username, so a user who could set an unverified email or an email-shaped username at the provider could open another person's workspace. oidcUsername() (src/lib/oidc-identity.ts) now takes the email unless the provider marks it unverified (email_verified: false), else a preferred_username without an "@". The callback still falls back to sub; the bearer channel refuses the token. Behaviour change: an account whose email the provider marks unverified is now named by its preferred_username.
…ified Some providers send email_verified as a string. Compared only with the boolean false, "false" counted as verified, so an unverified email could still become the username. A provider that sends no email_verified, such as Microsoft Entra ID, is unchanged.
|
This was referenced Oct 22, 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.



A native client (a mobile app) signs in to the identity provider itself as a public PKCE client and calls Studio's API with
Authorization: Bearer <access token>. Until now Studio accepted only the session cookie.Opt-in. The channel exists only while
OIDC_BEARER_AUDIENCEis set underNEXT_PUBLIC_AUTH_PROVIDER=oidc. Unset, the header is ignored outside/api/mcpas before, so a proxy forwardingBasiccredentials (CapRover httpAuth) changes nothing.What it checks. An asymmetric JWT from the issuer's key set, for the audience, unexpired, not an ID token, from
OIDC_BEARER_CLIENT_IDSwhen set, with a subject, a username and a role. A refusal answers 401 withWWW-Authenticateand is audited. A provider outage answers 503. A bearer session writes no cookie and cannot mint an MCP token. Under governance it meets the same sign-in rule as a cookie session.Username fix, both channels. Without governance the username keys a person's saved work. It was taken from
email, elsepreferred_username, so an unverified email or an email-shaped username chosen at the provider could open someone else's workspace. Now:emailunlessemail_verified: false, else apreferred_usernamewithout@. Behaviour change: an account whose email the provider marks unverified is now named by itspreferred_username.Verified. Full suite, 100% line coverage, build,
build:libandattwpass locally. Live against Keycloak 26.8.1, by bearer and by browser sign-in: the mobile token runs a query; Studio's ID token, a token without the audience, one from an unlisted client and an unverified email with an email-shaped username are refused or not used.Docs:
OIDC.md,API_DOCS.md,GOVERNANCE.md,STORAGE.md,SECURITY.md(new control 1.11).