Skip to main content

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 through pbac.segments.settings.
  • Entry points: token
  • Phases: introspect, token_exchange

Policy data​

This control owns no policy data row.

Reads​

  • context.grant_type
  • context.token_granted_resources
  • context.subject_token_granted_resources
  • context.actor
  • context.actor.client_id
  • resources

Emits​

  • deny
  • reason

Reason codes​

CodeCategoryEntry pointSetting
introspect_actions_exceededinvariantintrospectnone
token_exchange_actions_exceededinvarianttokennone
actor_not_registeredinvarianttokennone

Implementation​

KindReferenceFilesRole
rego_inlineoauth.tokenopa/policies/oauth/token.regodecides

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.