Skip to main content

Clients and access

A client is anything that asks the authorization server for a token, such as a web app, a backend service or an AI agent. Policy decides what each client gets from three things. It looks at how the client registered, what the client is entitled to, and which resource types it asks for.

What policy sees of a client​

Every decision carries the client under input.context.client. These fields come from a real token request.

FieldMeaning
client_idThe client's id
client_typeconfidential when the client holds a secret, public when it cannot
registration_typeHow the client registered. See the next table.
software_statementEvery claim of the client's software statement, or {} when it has none
is_resource_serverWhether the client is a resource server that calls introspection
dpop_bound_access_tokensWhether the client's tokens are bound to a DPoP key
redirect_uriThe redirect URI of this request, when it has one

How a client registers​

registration_type takes one of five values.

ValueHow the client got here
PRE_REGISTEREDThe default, for a client that did not come through /register, such as one an operator created
SOFTWARE_STATEMENTIt registered at /register with a signed software statement from a trusted issuer
DCR_PLAINIt registered at /register with no statement
CIMDIt presented a client metadata document by URL
SPIFFE_SVIDIt is a workload that authenticates with a SPIFFE ID

A software statement is a signed JWT that says what the client is and what it may request. The server accepts one only from an issuer in the trusted issuers row, pbac.operator.controls.trust. Every claim in it reaches policy, including claims you add yourself. Attribute-based access uses a department claim this way.

Resource types and scopes​

Policy grants access to resource types, and each type has a list of scopes. The types live in the resource registry row, pbac.operator.controls.resource_registry. A new instance ships four of them, for user info, introspection, AuthZEN and MCP servers.

A client names what it wants in the token request. It can send a resource indicator in resource, which must resolve to a known type, or name the type in resource_types. When we sent a resource the server could not resolve, it answered invalid_target with Resource could not be resolved to a known type.

Entitlements​

An entitlement says which grant types a client may use and which scopes of which types it may receive. The token policy takes the first of these that exists.

  1. An entry for the client_id in the client entitlements row, pbac.operator.controls.client_entitlements
  2. An entry under software_id in the same row, keyed by the sub claim of the client's software statement
  3. The grant_types and granted_resources claims of the client's software statement

A SPIFFE client has no software statement. Its entitlement comes from path_grants in the SPIFFE row, pbac.operator.controls.spiffe_policy, keyed by its SPIFFE ID path.

A new instance also ships bindings that entitle every DCR_PLAIN and CIMD client to the authorization_code and refresh_token grants, to openid, profile and email on urn:as:userinfo, and to mcp:tools and mcp:resources on urn:mcp:server over the MCP interface only. A managed resource that is exposed over MCP adds one entry for its own type when you register it. There is no read scope and no entry for every type, so these clients get nothing on a REST-only resource without an entitlement of their own. A binding adds to what the entries above resolved. Control data shows how to write an entitlement.

The granted scopes are what the client asked for, cut down to its entitlement, and then cut down again by any control that denies an action. Policy model walks through that order.

Next steps​