Skip to content
Agent Identity

IETF · October 2021

JSON Web Token (JWT) Profile for OAuth 2.0 Access Tokens

RFC 9068

V. Bertocci

RFCStableAuthorizationFoundationField guide

When an agent calls an API, the RS should see both who the user is (sub) and which agent/client is calling (client_id), plus optional act. Opaque tokens hide that from the RS unless it introspects.

At a glance

Problem
RFC 6749 access tokens are opaque. Resource servers need a standard JWT layout so they can validate tokens locally: issuer, expiry, client, subject, audience, scopes.
Identity / authn / authz
Authorization credential format that can also carry a subject identifier. Not an ID Token: typ is at+jwt, not the OIDC ID Token typ.

Actors

  • Authorization server
  • Resource server
  • Client

01

The gap for agents

RFC 6749 access tokens are opaque. Resource servers need a standard JWT layout so they can validate locally: issuer, expiry, client, subject, audience, scopes. When an agent calls an API, the RS should see both who the user is (sub) and which agent/client is calling (client_id), plus optional act.

This is not an ID Token. typ is at+jwt. Sending an ID Token because 'it is a JWT with a sub' is the classic mix-up.

02

Actors and trust boundaries

The RS trusts the AS JWKS. aud must be this RS. client_id names the OAuth client, not a portable agent. Opaque tokens hide all of this unless the RS introspects — which agents that fan out to many APIs make expensive and easy to skip.

03

Mechanics

RFC 9068: signed JWT, typ at+jwt, required iss, exp, aud, client_id, sub, iat; scope or authorization_details as granted. RS validates signature, exp, aud (the RS), client_id, and scope. Optional cnf for DPoP/mTLS.

typ: at+jwtfrom spec
Quoted: distinguishes access tokens from ID Tokens.
audfrom spec
Quoted: the resource server. Mandatory in this profile.
client_idfrom spec
Quoted: the OAuth client that received the token.
subfrom spec
Quoted: resource owner, or the client itself for client-credentials.

04

Step-by-step flows

Flow 1

RS local validation

  1. 1

    AS issues at+jwt with aud=canonical RS URI (RFC 8707 resource).

  2. 2

    Agent presents Bearer or DPoP.

  3. 3

    RS checks typ, sig, exp, aud==itself, then scope/authorization_details, then optional cnf proof.

  4. 4

    Reject tokens minted for a different MCP server or API even if the signature is valid.

05

Identity vs authentication vs authorization

Authorization credential format that can also carry a subject identifier. Authentication of the presenter is Bearer or PoP. Identity of the user is sub, not a substitute for an ID Token at the client.

06

How it composes

07

What bites agent implementers

  • Missing aud

    If your AS emits JWTs without aud, you do not have 9068. MCP will fail closed — or worse, a sloppy RS will accept anything from that issuer.

  • ID Token confusion

    Check typ. Check aud is the API, not the client_id.

08

Stability — what you can ship

RFC 9068, October 2021, V. Bertocci. Stable. https://www.rfc-editor.org/rfc/rfc9068.html

Catalog claims (short form)

typ: at+jwt
Distinguishes access tokens from ID Tokens.
aud
The resource server. Mandatory in this profile.
client_id
The OAuth client that received the token.
sub
Resource owner, or the client itself for client-credentials.

Implementer notes

Always set and check aud. An agent presenting a token minted for a different MCP server must be rejected (MCP makes this a MUST via RFC 8707).

Relationship to others

Primary sources

  • RFC 9068https://www.rfc-editor.org/rfc/rfc9068.html