Repository navigation
fix: accept a list of JWT audiences - #110
Merged
Merged
Conversation
REDASH_JWT_AUTH_AUDIENCE is now comma-separated. A Cognito deployment mints tokens for more than one app client, and the audience claim names the client a token was issued to, so a single configured value can only ever admit one of them. The console's own client was configured; a second client authenticating the same user -- the platform's MCP OAuth proxy, which obtains its own tokens on the user's behalf -- presents its own audience and was rejected with a 401 that was indistinguishable from a bad credential. PyJWT already accepts a list and passes a token matching any entry, so this is a settings change only. A value with no comma still yields a single-element list, and an empty one still yields something falsy, which jwt_token_load_user_from_request continues to read as "do not verify the audience".
squidsoup
approved these changes
Sep 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.
what
REDASH_JWT_AUTH_AUDIENCEbecomes comma-separated, parsed into a list the same wayREDASH_JWT_AUTH_ALGORITHMSon the next line already is. No other code changes: PyJWTalready accepts a list for
audience=and admits a token matching any entry.A value with no comma still yields a single-element list, and an empty one still yields
something falsy, which
jwt_token_load_user_from_requestcontinues to read as "do notverify the audience". So existing deployments are unaffected.
why
A Cognito deployment mints tokens for more than one app client, and the
audclaimnames the client a token was issued to, so a single configured value can only ever
admit one of them.
Stacklet's platform now fronts an MCP OAuth proxy that obtains its own Cognito tokens
on a user's behalf, through its own app client. Those tokens carry that client's id as
aud, while Redash is configured with the console's — sojwt.decoderaisesInvalidAudienceError,jwt_token_load_user_from_requestturns it intoUnauthorized,and the caller gets a 401 indistinguishable from a bad credential. Concretely, an MCP
client such as VS Code or Cursor authenticates fine and can reach the platform's
GraphQL API, but every AssetDB tool fails, because those reach Redash with the token in
the
stacklet-authcookie.The platform side already solved this for its own API by accepting a list of audiences.
This is the same fix for Redash.
testing
Two tests added to
TestJWTAuthentication: a token whoseaudis the second of severalconfigured audiences is accepted, and one whose
audmatches none is still rejected(401, since
verify_jwt_tokenraises rather than returning no user), so the list staysa closed set.
I could not run the suite — it needs the Postgres/Redis services from this repo's own
test setup, which I had no way to stand up. The change was syntax-checked, the parsing
verified against empty / single / multi / whitespace / empty-segment inputs, and PyJWT's
list-audience behaviour confirmed directly. The new tests themselves are unexercised
and should be run before merge.
docs
None needed — the setting keeps its name and its single-value behaviour.