Pass user context to downstream services in a form each one can validate, and authenticate the calling service separately from the user. A signed identity proves who the user is and that the data was not changed. It does not, by itself, allow access to any resource.
Two identities in every call
When the orders service calls the billing service on behalf of a user, there are two parties: the calling service and the end user. The OWASP Microservices Security Cheat Sheet treats them as separate questions. Identity propagation carries the authenticated user context. Service to service authentication proves which service is calling.
Mixing them causes trouble. If only the user token is checked, any service holding a user's token can act as that user anywhere. If only the service is checked, the user's limits disappear.
Propagating the user
The sheet advises passing authenticated user context in a form each receiving service can validate. It also warns that a signature protects integrity but does not by itself grant access to a resource. So the receiver must still run its own authorization, using the user identity as one input.
Practical choices:
- Forward the original access token, if its audience and scope fit every service it reaches. This is simple but gives broad reach.
- Exchange it for a narrower token per downstream service. More work, smaller blast radius. See the delegation versus impersonation discussion for the same pattern with agents.
- Pass a signed internal context from the edge, and make sure internal callers cannot forge it.
Authenticating the calling service
The cheat sheet describes two approaches. With mutual TLS, each service holds a key pair and authenticates to its peers, and the hard parts are key provisioning, trust bootstrap, revocation and rotation. With token based authentication, the caller gets a signed token from a token service and attaches it, and the receiver validates it.
Validation details that bite
The sheet notes that online validation, such as introspection, adds latency and a dependency on the token service, and that caching delays revocation detection, so cache time should be bounded by the freshness you need. Local validation uses trusted issuer keys and the applicable token profile, and signature checks alone are not enough. It also says local validation does not detect revocation before expiry unless you use short lifetimes or another revocation method.
One line is worth repeating: reject requests when the required token validation cannot be completed. Failing open on a validation outage is a common design slip.
Keep tokens on TLS
The sheet says token authentication should run over TLS. A token on a plain internal link is a token any observer on that link can reuse.
A short checklist
- Check the audience, issuer, expiry and scope on every hop.
- Authenticate the service and the user separately.
- Keep token lifetimes short.
- Log both identities, with a correlation ID.
Safeguard can help here in a small way. Its SBOM and dependency scanning covers the broker client libraries and service frameworks your code pulls in, and reachability analysis shows which advisories your services actually call. You can try a free scan at gold.safeguard.sh/scan.
Quick check
If the user context is signed, can the service trust it fully?
It can trust that the data is intact. It still has to decide whether that user may do this thing to this object.
What if the token service is down?
Reject requests that need validation you cannot complete, as the OWASP sheet advises.
Sources
Last reviewed: 19 October 2026.