The industry has settled where an authorization decision gets made and how it gets asked. The Authorization API 1.0, finalized by the OpenID AuthZEN working group in January 2026, standardizes the call between an enforcement point and a decision point over a subject, an action, a resource and a context. It deliberately stops there. Where the decision point gets the facts, what is cached and what happens when the source is unreachable are left to the implementer.
That second half is where most of the work sits, and the most common answer is the oldest one. A signed token records what the directory said when someone logged in. Groups, department, cost centre, entitlement claims, all accurate then, and every request after that reads the same values back.
Most of the time this does not matter. Names rarely change. Entitlements do. Someone moves team on Monday morning, and the token in their browser still says the old one until it expires.
The difference shows up in a loop that takes about a minute. A user signs in against a real OIDC provider and a set of routes comes back allowed. An administrator changes their department in the provider's console. The same request goes again, same token, and it flips from allowed to denied. No new sign in, no new token, no redeploy.
Why JWT claims go stale after sign in
The appeal of claims in a token is real. Verification is stateless. A service checks a signature against a cached key set and reads the payload, with no call to the identity provider on the hot path.
Those properties come from one design decision. The token is a copy, fast because it is local and wrong the moment the original changes. Directory data is precisely the category that changes without the holder of the token doing anything, because somebody else administers it. A manager reassigns a report, an offboarding job strips a group, a contractor's clearance is downgraded, and none of it touches a token that has already been signed. Identity providers are good at authentication and at coarse group membership, and turning that into fine grained access is the separate job where freshness starts to matter.
Do shorter token lifetimes fix stale claims?
The standard mitigation is to shrink the window. Five minute access tokens instead of hour long ones, so an entitlement change lands within five minutes. That reduces the number without removing it, and it moves cost elsewhere. Every expiry is a refresh, so the identity provider absorbs proportionally more traffic and rate limits on the token endpoint start to matter. The window never reaches zero either, because a lifetime of zero is a lookup on every request described in different words.
So the real question was never stale token or fresh token. It is where the lookup happens and who absorbs the cost.

How to look up identity attributes at decision time
The architecture that makes this possible splits the two questions a token normally answers at once. Envoy handles authentication at the edge, where its jwt_authn filter verifies issuer, audience and signature against the tenant key set, and anything that fails gets a 401 before it reaches the authorization layer. That half should come from the token, because a signature is a statement about the moment of issue.
Authorization is where the request leaves the token behind. Envoy forwards the verified request over the external authorization API to Cerbos Synapse. A data source takes the verified subject, calls the provider's management API, and returns the user's current profile and group memberships. Those land on the request as principal attributes, and a resource policy decides whether this caller may reach this route. The policy reads an attribute. It never sees a claim.
Both halves are configuration rather than code, so the lookup runs as an extension inside Synapse rather than as a service someone operates. The companion piece on the Envoy edge relates that to enforcement inside a service.

The same request, a different answer
Run the loop from the top against that and the previously allowed route returns a 403 naming the department it evaluated, while the route matching the new department opens up. The token is still valid and still verifies. It simply stopped being the source of the department.
A second source can sit alongside the directory just as easily. A SQL database holds clearance level, which belongs to HR rather than to the identity provider, and one policy reads both without knowing where either value came from. The piece on SQL sources covers that half in more depth.
What AuthZEN standardizes, and what it leaves to you
AuthZEN fixes the shape of the question and the shape of the answer. A subject, an action, a resource, a context, and a decision that defaults to closed. It says nothing about how the subject's department got into the request, which is the correct scope for a wire protocol and also the reason this article exists.
The older vocabulary is more precise about the gap. NIST SP 800-162 describes an access control mechanism in three parts rather than two. There is the component that renders the decision, the component that enforces it, and a context handler that assembles the subject, object and environment attributes the decision needs. That third role is the one most architectures never name and every deployment ends up building anyway. Giving it a dedicated layer in front of the decision point is the whole move.
Naming it makes the real design choice visible, which is the shape of the request rather than the location of the lookup. An enforcement point can send minimal identifiers and let the layer behind it resolve everything derived. It can send a fully qualified request carrying every attribute a policy might need, which couples it to the policies and grows the payload. Or it can send only the instant attributes it alone knows, the source address, the headers, the path, the device posture. Real deployments mix all three. Envoy contributes the path and the verified subject because only Envoy has them, and nothing downstream needs to know which attribute came from where.
Caching turns the staleness window into a number you choose
Resolving behind the interface has a cost, and it runs deeper than latency. Policy quality depends on runtime information being complete, accurate and available, so centralizing every attribute can move the bottleneck out of authorization and into the data layer. Where information gets resolved has to be designed alongside where the decision gets made, not discovered afterwards.
Synapse data sources cache their results. The backend is either in memory inside the Synapse process or a shared Redis instance, set once in configuration. Each lookup carries a cache key and an expiry, so different sources hold different freshness policies. A profile that changes weekly can sit for minutes. A risk signal that changes constantly gets seconds, or no cache at all.
That expiry is the real control, chosen per data source on a component you operate. Point a fleet at one Redis and load on the provider scales with the TTL window rather than with request rate.

Most teams already build this, one application at a time
Teams running a policy decision point arrive at the context handler role on their own, usually within months of the first policy going live. A scheduled job pulls users, groups and profile fields into a local table, and application code joins against it to assemble the principal before calling the PDP. It works, and it creates a second copy of the directory with its own sync interval, its own failure modes and its own schema to keep aligned as the provider's API changes.
Then a second application needs the same attributes and builds its own version, because the first was written into a service rather than into shared infrastructure. Utility Warehouse runs authorization across 4,500 services, roughly the scale at which a per application copy of the directory stops being defensible. Cerbos Synapse exists because that pipeline is the same every time, so it gets written once and configured per source.

What changes in the architecture
Entitlement changes take effect on the next request after the cache expires, so offboarding and team moves stop having an unbounded tail attached to a long lived token.
The application also stops learning the identity provider's schema. It forwards a token or a subject id, and never has to know whether department lives in a profile field, a group name or a custom attribute. Because policies read attributes rather than claims, the same policy runs at the edge or inside a service, and adding a provider becomes a change at the enrichment layer rather than in every application. The shape holds across Cognito, Keycloak, Entra ID through Microsoft Graph and directory servers over LDAP, because the only thing that varies is which API the data source calls. The article on legacy applications takes the harder version, where the application cannot call a PDP at all.
One version of this stops being a refinement. An agent chain turns one authenticated request into hundreds of downstream actions at machine speed, and a scoped token is a single decision taken at issuance with no way to reconsider the thousandth action. Resolving attributes at the point of decision is what makes per action evaluation possible at all. The piece on per tool authorization takes that on directly.
The cost of a live identity provider lookup on the request path
A live lookup is a runtime dependency on the identity provider, and that has to be deliberate rather than discovered later. Synapse extensions can be marked required, in which case a failure terminates the pipeline and the caller gets an error. Left unmarked, a failing extension is skipped and the request continues unmodified, so the attribute is absent and a policy that depends on it denies. Both behaviours are defensible. Neither should be found out during an incident.
The resilience argument also cuts the other way. A decision point that must reach a directory on the request path is less available than one answering from what it already holds, which is why serious deployments treat local caching of policies and attributes as a design requirement rather than a tuning exercise. Germany's federal infrastructure for API authorization, published in full with its architecture decision records, is the most complete worked example to read. All of which makes cache TTL a correctness decision, and setting it generously recreates the staleness window inside infrastructure you own.
Enforcing at the edge has its own boundary. A gateway is close to a pure configuration enforcement point, which is its strength, and the caveat is that every call has to route through it. Anything reaching the service another way is unauthorized rather than exempt, and internal traffic is where that happens.
Lineage sits underneath all of it. A decision now depends on values read at a particular moment, which is harder to reconstruct afterwards than one derived from a token you still hold, so recording which values were in play is worth designing for. Audit logs are where that gets asked.
A claim and an attribute differ only in when they were read
Both can hold the same value. The difference is when it was read, and who could change it in between. The standards settle how a decision gets asked, but what sits behind that interface is still a design problem, and moving the read next to the decision is neither simple nor free. It makes the staleness explicit and gives you a dial for it, per source, in a component you run. For entitlements that change while a session is open, that is the difference between a policy that is correct and one that was correct at login.
Try Cerbos to see how this works in practice, or book a call to talk through your architecture with the team.
Go deeper:
- How to adopt externalized authorization (eBook) for a structured route to moving authorization logic and its data out of application code
FAQ
Tagged in




