Architecture

Verifier

The verifier is the enforcement point on the far side of the call. It is the middleware a resource server runs to check an intent token before it does any work. It is the second, independent Policy Enforcement Point: it re-verifies everything at the resource, trusting nothing the client asserted and never calling back to the Authority on the request path.

What it checks

Two things, both cryptographic and both stateless. First, the token itself: the verifier fetches the Authority’s public keys from its JWKS and confirms the signature, issuer, audience, and expiry. Second, the binding: if the token carries a cnf.jkt, the caller must present a matching DPoP proof. The verifier hashes the proof’s key, checks it equals the token’s thumbprint, and verifies the proof’s signature and that it matches the request it actually received.

Note

A token with no cnf is treated as a plain bearer token; a token with a cnf.jkt always has its DPoP proof verified. So a stolen intent token can’t be replayed. The attacker has the string but not the key.

Backward compatible

The verifier keeps a resource server’s existing shape. Each endpoint keeps its original require_auth(scopes=…, audience=…) declaration; the verifier is a thin middleware swapped in where the old bearer-token check used to be. A resource server that doesn’t understand the agentic claims simply ignores them and treats the token as an ordinary JWT. That is a property of the token format, not something the verifier has to special-case.

A swap-in-place enforcement point

In the reference deployment, the verifier replaces a legacy RSA proof-of-possession middleware with DPoP-based sender-constraint (cnf.jkt, RFC 9449) without touching the endpoints themselves. Audiences stay per-domain, matching what the agents already mint for and what the service already expected. It is a swap-in-place that keeps both the agents and existing callers working.

Statelessness is the scaling property that makes this practical: the verifier holds no session and calls nothing on the hot path (it caches the JWKS), so adding it imposes negligible overhead and scales horizontally with the resource server. RFC 9449