Token derivation limits
A token derived from another token — by introspection re-issue or by token exchange — may never carry more than the token it came from.
The description above is the control's intent. On 0.65.0 an exchange can carry more. See the known issue below.
- Control id:
token_derivation - Shape:
deny. Segment bindings do not reach this control, because its Rego does not read settings throughpbac.segments.settings. - Entry points:
token - Phases:
introspect,token_exchange
Policy data
This control owns no policy data row.
Reads
context.grant_typecontext.token_granted_resourcescontext.subject_token_granted_resourcescontext.actorcontext.actor.client_idresources
Emits
denyreason
Reason codes
| Code | Category | Entry point | Setting |
|---|---|---|---|
introspect_actions_exceeded | invariant | introspect | none |
token_exchange_actions_exceeded | invariant | token | none |
actor_not_registered | invariant | token | none |
Implementation
| Kind | Reference | Files | Role |
|---|---|---|---|
| rego_inline | oauth.token | opa/policies/oauth/token.rego | decides |
Known issue
On 0.65.0 the token exchange check compares the request with the subject token only for a resource the exchange did not derive itself (not r.derived in opa/policies/oauth/token.rego). When the subject token names a resource, the exchange inherits it and the check applies. Otherwise the server derives the resource from the requested scope and the check skips it. In our run a token for mcp:tools was exchanged for one with mcp:resources, and a token for introspection requested with resource_types=urn:as:introspect for one with mcp:tools. See Exchange a token.
Send feedback about this page