The OIDC access zone: C=US agents in front of APIs that only understand OIDC
Most enterprise APIs cannot do mutual TLS with an agent or ask a trust registry. They can check a signed JSON Web Token against an issuer’s published keys, because that is how OpenID Connect works. The access zone is a boundary around such APIs: inside it, agents still prove who they are to C=US and C=US still decides; at its edge, a small sidecar turns each decision into a token the API already knows how to check.
The agent proves itself to C=US. C=US decides, signs, and hands the API only a token for one API, lasting about a minute.
The legacy API changes nothing but one setting: it trusts C=US as an issuer, as it already trusts its company’s identity provider.
The loop, step by step
| Step | What happens | Today |
|---|---|---|
| 1. The request | The agent calls the enterprise API. A lightweight C=US sidecar in front of the API intercepts the call; the API is not reachable any other way. | TESTED security/access-zone/sidecar.py, run on the laptop against the live gateway. The Cloudflare Workers at sugarbushagent.com already play this part for edge agents. |
| 2. Who is calling | The sidecar demands mutual TLS. The agent presents its short-lived client certificate, whose key was made in hardware at enrollment and which its directory entry binds by fingerprint. An agent on a native host instead presents its host’s workload identity through the token exchange. | TESTED Both, live at agents.cequs.com and cequs.com/agent-token/. |
| 3. Out-of-band check | Before anything reaches the API, the sidecar asks the C=US gateway for a token on the agent’s behalf, with its own client certificate, and the gateway decides by the same rules the trust registry (TRQP v2.0) answers by, fresh on every request. The answer is no if the agent is suspended, if its accountable person has stopped it with a passkey, if another system has sent a kill signal, or if its grant has ended. Then the loop ends. | TESTED These rules are live in the gateway and the registry. Drills: a kill signal took 0.35 seconds to reach the registry; a passkey stop on 17 October 2026. |
| 4. The token | If the answer is yes, the C=US gateway, acting as the token issuer, signs a JWT access token for exactly one API: its audience is that API, its scope the one action, and it expires in about a minute. The gateway signs the issuance into its decision log. | LIVE https://agents.cequs.com/access-zone/token, since 26 October 2026. A sidecar is listed against one API, so it gets tokens for that API only. |
| 5. The API | The sidecar forwards the request with Authorization: Bearer <token>. The API checks the signature against C=US’s published keys, then the issuer, audience and expiry, and serves the request, unaware of the mutual TLS behind it. | TESTED legacy_api.py stands in for the API, with the keys from the live discovery document. |
The token
A JWT access token in the profile of RFC 9068, signed by the gateway (EdDSA). Its claims, as the gateway issues them:
{
"iss": "https://cequs.com/access-zone",
"sub": "wimse://cequs.com/agents/vt-maple-quality-001",
"aud": "https://api.example-cooperative.com/lots",
"scope": "maple.lot.grade.propose",
"iat": 1793030400, "exp": 1793030460,
"client_id": "cooperative-lots",
"jti": "5f0c2a9e4b7d4e1a8c3f6d2b9e0a7c41",
"cnf": { "x5t#S256": "the SHA-256 thumbprint of the agent’s certificate" },
"agent_dn": "cn=maple-quality-agent,ou=AI-Agents,o=Cequs,c=US",
"accountable": "cn=Example Maple Farm Sponsor,ou=People,st=Vermont,c=US"
}
Its lifetime is at most a minute, and never runs past the agent’s grant or certificate. cnf ties it to the certificate the agent presented, for an API that can check that (RFC 8705); a legacy API ignores it.
The API finds C=US’s keys the way it finds any identity provider’s: from a discovery document (OpenID Connect Discovery, or RFC 8414 metadata) that names the issuer and its jwks_uri.
What the token can and cannot promise
- One API. The audience names a single API, so the token is useless anywhere else that checks
aud. - About a minute. A stop refuses the agent’s next request at step 3; a token already issued lasts until it expires. The time to stop is the token’s lifetime at most, so it is kept short.
- Single use only if the API counts. A legacy API that does not record each
jticannot refuse a replay within that minute. Where the API can do more, the token should be bound to a key instead of carried as a bearer token: DPoP (RFC 9449), as the token exchange already does, or mutual TLS (RFC 8705). - Fresh decisions. The sidecar asks for a new token on every request and caches nothing, and the gateway decides each one afresh, so a stop is not delayed by a cache.
- A sidecar for one API. Each sidecar is listed against the one API it fronts. An agent’s certificate is public, so a compromised sidecar could ask for tokens naming any registered agent, but only for its own API, which it already controls.
The person behind the agent: where Utah’s SEDI could fit
This section is a proposal. Utah has not chosen these protocols, and nothing here uses a Utah credential.
The zone answers for an agent; someone has to answer for the agent. In C=US that is a proofed person whose entry sits in their state’s directory, and Utah’s State-Endorsed Digital Identity (S.B. 275) is one way that proofing could be done. (Utah’s SEDI law and the Utah AI Policy Act and SEDI have the background.)
- It is a presentation, not a login. A SEDI is a credential the person holds in their own wallet, signed by the Department, and presented with only the attributes asked for. Utah’s implementation guide requires that it verify “without real-time communication with the Department” and that verifiers request only what their purpose needs. So the bridge is not an OIDC login to Utah; it is the person presenting their SEDI to a verifier. OpenID for Verifiable Presentations is one protocol proposed for this (the OpenID Foundation’s comments to Utah, 2025); Utah has not adopted it.
- The binding stays in the state. The verifier would be the Utah directory’s own enrollment, and the result, that this person is proofed, recorded under the person’s entry in
st=Utah,c=US. The agent’s entry names that person as accountable. C=US holds no copy: it reads the state’s entry when it decides, and has no dashboard or accounts of its own. - Then the zone carries it. Every token says, in
accountable, which entry answers for the agent, and every issuance is in the signed log.
What this would mean under Utah’s AI Policy Act
As the Utah AI Policy Act page sets out, the Act’s safe harbor concerns disclosing the use of generative AI, and its Office of Artificial Intelligence Policy can enter time-limited regulatory mitigation agreements with participants who test AI. C=US has not applied for one and claims none. What the zone would add is evidence: who was accountable (the state entry), that the grant was current (the directory), when the agent was stopped (the signed log), and that downstream access ended within one token lifetime of the stop. It is a record a person could show a regulator, not a guarantee of how a regulator would weigh it.
What exists, and what would have to be built
| Piece | Status |
|---|---|
| Mutual TLS and the token exchange for agents | TESTED Live. |
| Trust registry (TRQP v2.0), stops and kill signals | TESTED Live. |
| Tokens for one outside API, signed and logged; the discovery document and published keys | BUILT, NOT DEPLOYED 10 tests, end to end over real TLS on loopback, pass; the gateway’s 91 tests pass against a real OpenLDAP server. |
| The sidecar, and a stand-in legacy API | BUILT, NOT DEPLOYED security/access-zone/. |
| Running on cequs.com | LIVE Since 26 October 2026: the token endpoint, the discovery document and the keys. Drill that day: the registered agent vt-maple-quality-001 reached the stand-in API through the sidecar in 397 ms; a sidecar that is not listed was refused; the allow is signed in the live log. |
| SEDI presentation at a state directory’s enrollment | NOT BUILT The people in this demonstration are illustrative entries with simulated attestations. |
Limits
- The gateway’s half is live; the sidecar and the API ran on the project lead’s laptop, standing in for an enterprise. No real enterprise API is behind the zone.
- A sidecar that can be bypassed protects nothing: the API must accept traffic only through it, or check the token itself.
- A token is evidence about one request; it does not show what the API then did with it.
Sources
- This project: the code in
security/access-zone/andsecurity/agent-gateway/gateway.py(mint_zone_token); enterprise compatibility, native-hosted agents (the token exchange), trust registry, kill switch, zero trust, Utah’s SEDI law, the Utah AI Policy Act and SEDI. - Standards: IETF RFC 9068 (JWT access tokens), RFC 8414 (authorization server metadata), RFC 8693 (token exchange), RFC 9449 (DPoP), RFC 8705 (mutual-TLS bound tokens); OpenID Connect Discovery 1.0 and OpenID for Verifiable Presentations 1.0; Trust over IP Trust Registry Query Protocol.
- Utah: SEDI implementation guide, part 3 (the SEDI: endorsement, selective disclosure, offline presentation) and part 5 (verifiers); OpenID Foundation, comments on Utah’s SEDI request for information (6 October 2025).
Drafted by Claude Code (Claude Opus 5.5) at the project lead’s request, 2026-10-26, from a concept the project lead supplied (AI-generated) and corrected against the project’s code, its existing Utah pages and Utah’s SEDI implementation guide: SEDI is presented from a wallet rather than used as a login, the person’s binding stays in the state directory, the safe harbor concerns disclosure, and a bearer token is single-use only if the API records it. Built by Claude Code the same day: the gateway’s token endpoint, the sidecar, a stand-in API and their tests.