Bug description
Clients registered via Client ID Metadata Documents (CIMD) can sign in but can never refresh. buildFositeClient in pkg/authserver/storage/cimd_decorator.go sets Audience: nil on every CIMD-resolved client, while the token handler (pkg/authserver/server/handlers/token.go) grants the session audience from the resource parameter (or defaults it to AllowedAudiences[0] for authorization_code grants, #4805). On the refresh grant, fosite's DefaultAudienceMatchingStrategy checks the granted audience against the client's audience list; an empty list matches nothing, so the grant fails with invalid_request. The authorization_code path never runs that check, which is why sign-in works.
This is the CIMD twin of #3777: DCR clients failed the same way, and #3796 fixed them by registering DCR clients with the server's AllowedAudiences. The CIMD resolution path never received that fix.
Steps to reproduce
- Run the embedded auth server with CIMD enabled and one allowed audience, e.g.
https://mcp.example.com/mcp.
- Complete an authorization code + PKCE flow with a CIMD client id (e.g.
https://claude.ai/oauth/claude-code-client-metadata), sending resource=https://mcp.example.com/mcp and scope offline_access. The code exchange succeeds and returns a refresh token.
- Send the refresh token back:
POST /oauth/token with grant_type=refresh_token, the token, and the same client_id.
Expected behavior
A new access token: offline_access was granted, and DCR clients refresh fine after #3796.
Actual behavior
HTTP 400
error: invalid_request
error_description: [...] Requested audience 'https://mcp.example.com/mcp' has not been whitelisted by the OAuth 2.0 Client.
Every CIMD client (ChatGPT connectors, Claude Code) has to re-authorize interactively once per access-token lifespan.
Environment (if relevant)
- ToolHive version: v0.46.0; the mechanism is unchanged on main (ee527be); fosite v0.49.0.
Additional context
Suggested fix, mirroring #3796: pass the server's AllowedAudiences into CIMDDecoratorConfig (constructed in pkg/authserver/server_impl.go) and set it as the resolved client's Audience in buildFositeClient, whose comment already states the AS should apply its own audience policy. A refresh-grant regression test would have caught this. Happy to send a PR.
Bug description
Clients registered via Client ID Metadata Documents (CIMD) can sign in but can never refresh.
buildFositeClientinpkg/authserver/storage/cimd_decorator.gosetsAudience: nilon every CIMD-resolved client, while the token handler (pkg/authserver/server/handlers/token.go) grants the session audience from theresourceparameter (or defaults it toAllowedAudiences[0]for authorization_code grants, #4805). On the refresh grant, fosite'sDefaultAudienceMatchingStrategychecks the granted audience against the client's audience list; an empty list matches nothing, so the grant fails withinvalid_request. The authorization_code path never runs that check, which is why sign-in works.This is the CIMD twin of #3777: DCR clients failed the same way, and #3796 fixed them by registering DCR clients with the server's
AllowedAudiences. The CIMD resolution path never received that fix.Steps to reproduce
https://mcp.example.com/mcp.https://claude.ai/oauth/claude-code-client-metadata), sendingresource=https://mcp.example.com/mcpand scopeoffline_access. The code exchange succeeds and returns a refresh token.POST /oauth/tokenwithgrant_type=refresh_token, the token, and the sameclient_id.Expected behavior
A new access token:
offline_accesswas granted, and DCR clients refresh fine after #3796.Actual behavior
Every CIMD client (ChatGPT connectors, Claude Code) has to re-authorize interactively once per access-token lifespan.
Environment (if relevant)
Additional context
Suggested fix, mirroring #3796: pass the server's
AllowedAudiencesintoCIMDDecoratorConfig(constructed inpkg/authserver/server_impl.go) and set it as the resolved client'sAudienceinbuildFositeClient, whose comment already states the AS should apply its own audience policy. A refresh-grant regression test would have caught this. Happy to send a PR.