Problem/Motivation
The module's declared per-environment agent principals authenticate over simple_oauth with the client_credentials grant. The site exposes RFC 8414 / OpenID Connect discovery and a JWKS, so an external OAuth resource server (for example the Drupal MCP Connector's protected-resource mode, or any RFC 9728-style gateway) can validate these tokens cryptographically. Two claim gaps stop it there:
- No client identity claim. The access token carries neither
azpnorclient_id. A resource server that keys entitlement grants on the caller's client identity resolves it to nothing, and a grants table entitles the token to zero targets. Fail-closed, but it means a legitimately issued token can never be granted anything. - The audience is the client id, not a resource.
audis the consumer's client id (observed:"aud": "content-staging"). A protected resource that validates the audience against its own HTTPS resource identifier (RFC 8707 style) must refuse every token, because a client id can never match a resource URL.
Observed at 2.13.2: a token minted by the site validates by signature and issuer at an external resource server and is then refused on audience — correct fail-closed behavior, and structurally unable to become an allow.
Steps to reproduce
- Mint a token:
curl -s -X POST https://example.com/oauth/token -d grant_type=client_credentials -d client_id=CLIENT -d client_secret=… - Decode the payload:
audis the client id; there is noazporclient_idclaim. - Configure any audience-validating resource server against the site as issuer: the token can never carry the resource's identifier, and no claim identifies the client.
Proposed resolution
Mint the missing claims on the site's access tokens (simple_oauth provides claim alteration seams):
- add
client_id(and/orazp) with the consumer's client id; - optionally support an audience/resource value per consumer (or honor an RFC 8707
resourceparameter on the token request) soaudcan name the protected resource the token is intended for.
Alternatively, document that entitlement-filtered resource servers require an external issuer (e.g. Keycloak) that mints these claims, and that the site-as-issuer path is limited to first-party southbound authentication.
No security impact today: every observed outcome is a refusal. This is an enablement gap, not a bypass.
Comments
Comment #2
jmcerdaComment #3
jmcerdaShipped in 2.14.0.
hook_simple_oauth_private_claims_alterfillsclient_idandazpfrom the consumer identifier without overwriting values another alter already set. Scope honestly bounded as recorded:audremains the consumer id (registered claim, set upstream withpermittedFor()), so RFC 8707 resource audience support stays a simple_oauth change.