fix(api): default OIDC discovery issuer to API_EXTERNAL_URL#2505
Open
mastermanas805 wants to merge 1 commit intosupabase:masterfrom
Open
fix(api): default OIDC discovery issuer to API_EXTERNAL_URL#2505mastermanas805 wants to merge 1 commit intosupabase:masterfrom
mastermanas805 wants to merge 1 commit intosupabase:masterfrom
Conversation
The /.well-known/openid-configuration handler used config.JWT.Issuer unconditionally, returning an empty issuer and relative endpoint URLs for self-hosted operators who configure API_EXTERNAL_URL but leave GOTRUE_JWT_ISSUER unset. That violates OpenID Connect Discovery 1.0 section 4.2 (issuer MUST be present) and RFC 8414 section 3 (endpoint URLs MUST be absolute). Default issuer to config.API.ExternalURL when JWT.Issuer is empty; API.ExternalURL is required:"true" in the config struct so it is always populated. Also use the trailing-slash-stripped local variable when returning the Issuer field so it matches how endpoint URLs are constructed. Adds in-process tests asserting that issuer and endpoint URLs are absolute when JWT.Issuer is empty, and that a trailing slash on a configured JWT.Issuer is stripped consistently from the issuer field. Fixes supabase#2487 Signed-off-by: Manas Srivastava <mastermanas805@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.
What
Fixes #2487.
The
/.well-known/openid-configurationhandler ininternal/api/jwks.goreadsconfig.JWT.Issuerdirectly. When self-hosted operators configureAPI_EXTERNAL_URL(which isrequired:"true"perinternal/conf/configuration.go) but leaveGOTRUE_JWT_ISSUERunset, the response comes back with an emptyissuerfield and relative endpoint URLs. That violates OpenID Connect Discovery 1.0 section 4.2 (issuer MUST be a non-empty URL) and RFC 8414 section 3 (endpoint URLs MUST be absolute).A second smaller bug: even when
JWT.IssuerIS set, the response uses the un-cleaned config value atjwks.go:76instead of the trailing-slash-stripped local variable that the endpoint URLs at lines 77-80 use, soissuerand the endpoint paths can drift apart on configs with a trailing slash.How to reproduce on master (for reviewers)
You will see this response on master:
{ "issuer": "", "authorization_endpoint": "/oauth/authorize", "token_endpoint": "/oauth/token", "jwks_uri": "/.well-known/jwks.json", "userinfo_endpoint": "/oauth/userinfo", ... }Empty
issuer+ relative endpoints. That is the bug.Root cause
internal/api/jwks.go, functionWellKnownOpenID:issuer := config.JWT.Issuerreads the issuer with no fallback. IfJWT.Issueris empty,issueris empty for the rest of the function.Issuer: config.JWT.Issuerrather thanIssuer: issuer, so the trailing-slash strip at lines 71-73 never reaches the response field.Fix
Two-line change in
WellKnownOpenID:issuertoconfig.API.ExternalURLwhenJWT.Issueris empty (API.ExternalURLis alreadyrequired:"true"so it is always populated).Issuer: config.JWT.IssuertoIssuer: issuerso it picks up the cleaned value.How to verify the fix manually (for reviewers)
After applying this PR's diff:
Expected response:
{ "issuer": "http://localhost:9999", "authorization_endpoint": "http://localhost:9999/oauth/authorize", "token_endpoint": "http://localhost:9999/oauth/token", "jwks_uri": "http://localhost:9999/.well-known/jwks.json", "userinfo_endpoint": "http://localhost:9999/oauth/userinfo", ... }To verify the trailing-slash handling specifically, set
GOTRUE_JWT_ISSUER="https://auth.example.com/"in.env.docker(note the trailing slash), restart, and the responseissuershould come back ashttps://auth.example.comwithout the slash.Automated tests
internal/api/jwks_test.go(added in this PR):TestWellKnownOpenIDIssuerFallbackToExternalURL— asserts the responseissuerand endpoint URLs are absolute and rooted atAPI.ExternalURLwhenJWT.Issueris empty. Fails on master, passes after this fix.TestWellKnownOpenIDIssuerStripsTrailingSlash— setsJWT.Issuer = "https://auth.example.com/"and asserts the responseissuerishttps://auth.example.com. Fails on master, passes after this fix.Run them:
go test ./internal/api/ -run TestWellKnownOpenID -v -count=1Verification I ran locally
go test ./internal/api/ -run TestWellKnownOpenID -v -count=1— both new cases red on master, green after the fixgo test ./... -count=1 -p 1 -race— full module suite greengofmt -l internal/api/jwks.go internal/api/jwks_test.go— emptygo vet ./...— emptyBehavior change
API_EXTERNAL_URL: discovery now returns spec-compliant absolute URLs. Previous behavior was a spec violation.GOTRUE_JWT_ISSUERexplicitly: behavior unchanged, except trailing slashes are now stripped fromissuer(already stripped from endpoints). Returning the stripped value matches what the endpoints already use, eliminating an inconsistency.