AUTH4D-85 CORS for discovery, JWKS and UserInfo
The browser SDK reads tenant discovery, the JWKS and UserInfo from the page’s own origin. Before
this change these paths only accepted origins on the deployment-wide CLIENT_ORIGINS list, so a
browser application’s registered Allowed origins were not enough to sign in. Now a registered
origin is enough. Only guest sign-in (POST /t/{tenantId}/guest) still needs CLIENT_ORIGINS.
Discovery and JWKS: public CORS
GET /t/{tenantId}/.well-known/openid-configuration and GET /t/{tenantId}/.well-known/jwks.json
are public metadata:
- Every response, including errors, carries
Access-Control-Allow-Origin: *and neverAccess-Control-Allow-Credentials. The wildcard is literal; the request origin is never reflected, so browsers refuse the response to credentialed requests. - Any
Originis accepted. - Preflights (
OPTIONS) are answered with204forGET, with at most theAuthorization,Content-TypeandX-Requested-Withrequest headers. Other methods or headers get403.
UserInfo: per-client CORS
GET /oauth/userinfo decides CORS per client, the same way as /oauth/token and /oauth/revoke
(AUTH4D-63 (repository file docs/api-spec/auth4d-63.md)), instead of using CLIENT_ORIGINS:
- With a valid bearer access token and an
Originheader, the response is readable only when the token’s client (looked up inside the token’s tenant) is an enabled browser application with that origin in itsallowedOrigins. The response then carriesAccess-Control-Allow-Origin: {origin}andVary: Origin, neverAccess-Control-Allow-Credentials. - Any other origin, including another application of the same tenant and the console origin, gets
403invalid_request(“The browser origin is not registered.”) without CORS headers and without claims. - An invalid or expired token gets
401without CORS headers, because no client can be trusted from it; the SDK reportsuserinfo_failedeither way. - Requests without an
Originheader (servers, native games) are unchanged.
Preflight
A preflight cannot see the bearer token, so the API cannot know the token’s client. The UserInfo
preflight is therefore answered with 204, Access-Control-Allow-Origin: {origin}, Vary: Origin,
Access-Control-Allow-Methods: GET and Access-Control-Allow-Headers: authorization when:
- the origin is a canonical HTTPS (or loopback HTTP) origin,
- the request method is
GETand the only requested header isAuthorization, and - the origin is registered on any enabled browser application of the active customer tenant
named by the
tenant_idquery parameter (discovery publishes the UserInfo endpoint with it).
Anything else gets 403 origin_denied without CORS headers. The preflight only lets the browser
send the request; the actual response still enforces the token’s own client as described above, so
tenant_id alone never decides who may read UserInfo.
Unchanged
- Management routes keep the console-only, credentialed CORS policy.
- The console’s backend-for-frontend is same-origin and unaffected.
/oauth/authorize, hosted-login routes, device routes and guest sign-in keep the deployment-wideCLIENT_ORIGINSpolicy.
Source: docs/api-spec/auth4d-85.md