-
Notifications
You must be signed in to change notification settings - Fork 109
Description
Audience validation fails for RFC 8707 resource indicators with path
Problem
When using RFC 8707 Resource Indicators with a path component (e.g., resource=https://example.com/api), token validation fails with:
invalid_token: Token audience does not match resource server
This breaks OAuth flows for services like ChatGPT custom connectors, which send resource indicators as full URLs with paths.
Root Cause
In handleApiRequest, the resourceServer is computed using only the origin:
const resourceServer = `${requestUrl.protocol}//${requestUrl.host}`;However, RFC 8707 recommends using full URLs with paths for resource indicators. The audienceMatches function performs strict equality (===), so:
- Token audience:
https://example.com/api(from authorization request'sresourceparameter) - Resource server:
https://example.com(computed from request URL) - Result:
"https://example.com/api" !== "https://example.com"→ validation fails
Affected Code
Two locations in handleApiRequest:
Line ~1017 (internal token validation):
const resourceServer = `${requestUrl.protocol}//${requestUrl.host}`;
const audiences = Array.isArray(tokenData.audience) ? tokenData.audience : [tokenData.audience];
const matches = audiences.some((aud) => audienceMatches(resourceServer, aud));Line ~1038 (external token validation):
const resourceServer = `${requestUrl.protocol}//${requestUrl.host}`;
const audiences = Array.isArray(ext.audience) ? ext.audience : [ext.audience];
const matches = audiences.some((aud) => audienceMatches(resourceServer, aud));audienceMatches implementation (line ~1143):
function audienceMatches(resourceServerUrl, audienceValue) {
return resourceServerUrl === audienceValue;
}Minimal Reproduction
- Configure OAuth provider with
apiRoute: '/api' - Client sends authorization request with
resource=https://server.example.com/api - Token is issued with
aud: "https://server.example.com/api" - Client sends API request to
https://server.example.com/apiwith access token - Validation fails:
resourceServer="https://server.example.com"doesn't matchaud="https://server.example.com/api"
Expected Behavior
Token validation should succeed when the resource indicator includes the path component, as recommended by RFC 8707.
Proposed Fix
Include the pathname in resourceServer computation:
const resourceServer = `${requestUrl.protocol}//${requestUrl.host}${requestUrl.pathname}`;This ensures:
resourceServer = "https://example.com/api"- Token audience =
"https://example.com/api" - Validation succeeds:
"https://example.com/api" === "https://example.com/api"
References
- RFC 8707: Resource Indicators for OAuth 2.0
- Section 2: "The value of the 'resource' parameter MUST be an absolute URI"
- Section 3.1: "The authorization server MUST set the 'aud' claim to the resource value"
Workaround
Vendor the library and apply the fix locally:
// In oauth-provider.ts handleApiRequest method
const resourceServer = `${requestUrl.protocol}//${requestUrl.host}${requestUrl.pathname}`;Environment
- Package:
@cloudflare/workers-oauth-providerv0.1.0 - Runtime: Cloudflare Workers
- OAuth client: ChatGPT custom connector (and other RFC 8707-compliant clients)