For APIs with per-resource permissions, design token acceptance and resource authorization as separate responsibilities: establish trusted authorization context, then decide whether it permits the requested action on the target resource. OAuth supports application access on its own behalf or on behalf of a resource owner; relationship-based permission models express access between subjects and objects. RFC 6749 · Ory Keto documentation
The engineering task is to connect those responsibilities without treating an accepted service credential as permission to access every resource.
Separate service context from resource permission
Consider an illustrative billing system. A reconciliation worker needs to read invoices for one customer account. Design its authorization contract around three questions:
- Subject: Which service principal does the accepted authorization context represent?
- Action: Is the request a read, an update, or another protected operation?
- Resource: Which invoice, belonging to which account, is the operation targeting?
For this design, recognizing the reconciliation worker should not imply permission to read every invoice. Represent its account-specific access explicitly, and evaluate the requested operation against that access.
A relationship-based model is one way to express this distinction. Keto’s documentation describes fine-grained subject-to-object permissions and inheritance through groups, roles, and hierarchies. Its example derives document read and write permissions from viewer and editor relationships. That provides a starting point for the billing design, but the invoice model here is illustrative—not a supplied product configuration. Ory Keto documentation
Define token acceptance independently of resource checks
RFC 9068 defines a JWT access-token profile for interoperable issuance and consumption. It also discusses deployments switching from that profile to opaque tokens. Establish which token format and validation rules your API supports rather than assuming every OAuth access token follows the JWT profile. RFC 9068
Token introspection lets a protected resource query an authorization server for a token’s active state and associated metadata. RFC 7662 explicitly allows introspection alongside or independently of structured token values: introspection and JWT formatting are not mutually exclusive choices. RFC 7662
Whichever mechanisms your deployment uses, define two contracts:
- Token acceptance: How does the API validate the presented token and obtain trusted authorization context?
- Resource authorization: How does that context determine whether this action on this object is permitted?
In the billing example, token acceptance supplies an input to the invoice decision. It does not replace the account-specific permission check. If token claims carry authorization information, specify how those claims combine with the resource policy. RFC 9068 recommends using authorization claims together with other available contextual information when deciding whether to authorize a call. RFC 9068
Make the context-to-permission mapping explicit
A practical application contract for the billing API is:
- Establish trusted context. Complete the configured token checks before using token-derived information in a permission decision.
- Resolve the permission subject. Map that context to the service principal used by the permission model.
- Resolve the operation and object. Derive the action from the API operation and identify the target invoice and its account using authoritative application data.
- Evaluate access. Ask whether that subject may perform that action on that resource.
- Enforce the result. Execute the protected operation only after an affirmative decision.
This is an application design, not an Ory SDK sequence. Specify which trusted identifier represents the worker, how resource identifiers are namespaced, and where account membership enters the permission model.
Make required mapping inputs explicit. For example, RFC 7662 makes client_id optional in an introspection response. If your mapping depends on that field, require it in your integration contract and do not proceed when it is missing. RFC 7662
For the resource model, define an account-level invoice_readers relationship and let an invoice’s read permission depend on its parent account. This applies the inheritance approach documented by Keto; your application must define the particular relationships and permission rules. Ory Keto documentation
Keep Hydra, Keto, and Kratos responsibilities distinct
Ory’s documentation for Ory Network describes three distinct responsibilities:
| Component | Documented responsibility | Role in this design |
|---|---|---|
| Ory OAuth2 and OpenID Connect, built on Hydra | OAuth 2.0 and OpenID Connect, including server-to-server communication | Provide OAuth infrastructure for service access |
| Ory Keto | Fine-grained permissions, including inheritance through groups, roles, and hierarchies | Model subject–action–resource decisions |
| Ory Kratos Identities | Identity and user management, including login, registration, recovery, and account management | Manage user accounts where the application needs them |
Sources: Hydra documentation, Keto documentation, and Kratos documentation.
Keep the resource API’s enforcement responsibility explicit. Define how accepted OAuth context becomes a permission subject, how the resource is identified, and how the decision controls execution. Treat token issuance and resource-permission evaluation as separate operations rather than assuming that selecting products also specifies their application-level integration.
Ory describes its OAuth service as a headless API that connects to Ory Identities by default but does not require a particular user-management system. That separation is useful when an application already has user-account infrastructure. Hydra documentation
Decide whose authority crosses a service boundary
A background worker acting under its own authority is a different design case from a service handling a user-initiated request. OAuth’s framework accommodates both own-behalf and resource-owner-based access. RFC 6749
For each downstream call, write down whether the intended authorization depends on the service, the user, or both. Do this before choosing how credentials travel through the service chain.
OAuth Token Exchange defines a protocol for requesting and obtaining security tokens, including tokens employing impersonation and delegation. RFC 8693 describes a resource server exchanging an incoming token for one appropriate for a backend call. It is relevant when evaluating service-chain designs, but verify implementation support in the chosen authorization server separately. RFC 8693
Distinguish mutual-TLS authentication from token binding
RFC 8705 describes both mutual-TLS client authentication to an authorization server and certificate-bound access tokens. For certificate-bound tokens, it provides a method for a protected resource to ensure that the token was issued to the client presenting it. These are distinct parts of the protocol design. RFC 8705
If certificate-bound tokens are part of your architecture, verify the resource-side binding check explicitly. Do not treat client authentication at the token endpoint as proof that the API enforces certificate binding. Keep that acceptance check separate from the invoice permission decision as well.
Test the permission boundary, not just the successful request
Turn the billing design’s authorization contract into acceptance tests. For the allow cases below, require all other token-acceptance and subject-mapping conditions to be satisfied.
| Test case | Intended result |
|---|---|
| Token accepted, worker subject resolved, and read permission granted for the target invoice | Allow the read |
| Accepted worker token but no relevant resource permission | Deny |
| Worker requests an invoice belonging to another account without a grant | Deny |
| Worker has only read permission but requests an update | Deny |
| Read permission is inherited through the configured invoice-to-account relationship | Allow the read |
| Token acceptance, subject mapping, or permission evaluation cannot establish authorization | Do not execute the protected operation |
Run these tests at the enforcement boundary so they exercise both the permission model and the application’s handling of its result.
The central design rule is simple: make token context, resource policy, and enforcement explicit. A service credential should start the authorization decision—not silently stand in for every permission the API needs to enforce.
Sources are linked throughout this guide. Product capabilities can change; consult the linked documentation for your deployment.
Read our editorial approach ↗