Skip to content

Token format is not a cosmetic detail.

It decides who can read claims, where validation happens, how quickly revocation becomes visible, and what a resource server must operate. A self-contained JWT access token is convenient because an API can validate it locally. A reference token moves the useful token contents back to the authorization server. An encrypted token hides claims from intermediaries. A JWT introspection response adds integrity to a live status check.

None of those choices is universally best. They solve different problems.

That distinction matters in the ProAuth v3 preview because the token toolbox is getting broader. The preview-era docs describe support for reference access tokens, encrypted ID and access tokens, encrypted UserInfo responses, and JWT-wrapped introspection responses. The useful work is not to enable every option everywhere. It is to choose the token shape that fits the API boundary and the operating model.

flowchart TD
    Boundary["API token boundary"] --> Latency{"Must the API validate locally?"}
    Latency -->|Yes| Confidential{"Must claims be hidden from intermediaries?"}
    Latency -->|No| Central{"Is immediate central status important?"}

    Confidential -->|No| Jwt["Signed JWT access token"]
    Confidential -->|Yes| Jwe["Encrypted self-contained token"]

    Central -->|Yes| Reference["Reference access token with introspection"]
    Central -->|Also needs signed status| JwtIntro["JWT introspection response"]

    Jwt --> JwtCost["Fast local validation, visible claims"]
    Jwe --> JweCost["Claim confidentiality, key operations"]
    Reference --> RefCost["Central status, introspection dependency"]
    JwtIntro --> IntroCost["Integrity-protected status, extra validation"]

    classDef question fill:#eef6ff,stroke:#2563eb,color:#10233f
    classDef pattern fill:#ffffff,stroke:#64748b,color:#172033
    classDef tradeoff fill:#f6f8fb,stroke:#94a3b8,color:#172033
    class Boundary,Latency,Confidential,Central question
    class Jwt,Jwe,Reference,JwtIntro pattern
    class JwtCost,JweCost,RefCost,IntroCost tradeoff

Start With The Visibility Problem

Signed JWTs are often treated as private because they look dense. They are not private.

A signed JWT protects integrity and issuer authenticity when the resource server validates the signature. It does not hide the claims inside the token. Anyone who can see the token string can usually decode the header and payload. That may include browser runtimes, API gateways, reverse proxies, telemetry pipelines, support logs, command histories, debugging tools, and partner systems.

Sometimes that is acceptable. A short-lived access token with a narrow audience and ordinary claims may be exactly the right tradeoff for a high-throughput API. The API validates issuer, signature, lifetime, audience, and scope locally, without calling the authorization server on every request.

The moment claims become more sensitive, revocation needs become tighter, or intermediary visibility becomes harder to tolerate, token format becomes an architecture decision rather than an implementation default.

Four Token Patterns, Four Different Tradeoffs

The decision is easier when the options are described by what they change at the resource-server boundary.

PatternWhat the client presentsHow the API validatesWhat it improvesMain cost
Signed JWT access tokenA readable, signed JWTLocal validation with issuer metadata and signing keysLow-latency validation and fewer runtime dependenciesClaims are visible to token holders and intermediaries; revocation is usually bounded by token lifetime unless extra checks exist
Reference access tokenAn opaque handleToken introspection at ProAuthServer-side token contents, central status, immediate inactive result after revocationThe API needs an introspection path, credentials, latency budget, and availability planning
Encrypted self-contained tokenA compact JWE containing an inner signed JWTDecrypt first, then validate the inner signed token, or introspectClaim confidentiality from browsers, proxies, logs, and other intermediariesKey management and decryption configuration move into the client or resource-server design
JWT introspection responseAn introspection result returned as a signed JWTIntrospect, then validate the introspection JWT signature, issuer, audience, and typIntegrity-protected live status and claims returned by introspectionMore validation work than plain JSON introspection

That matrix is deliberately not a ranking. It is a set of operational commitments.

Reference Tokens Keep Access-Token Contents Server-Side

The ProAuth v3 preview documentation describes Access Token Type on the client application. The default is SelfContainedJwtToken, where ProAuth returns a signed JWT access token. The alternative is ReferenceToken, where ProAuth returns an opaque 32-byte base64url handle and stores the signed JWT access-token payload server-side.

That changes the API boundary. The resource server no longer reads claims directly from the presented token. It calls the introspection endpoint and receives the token status and payload data, such as scope, client ID, audience, subject, issuer, issued-at time, and expiration.

This is a better fit when central status matters more than offline validation. The reference-token docs state that revoking a reference access token marks the stored token payload revoked immediately, so introspection returns inactive right away. Missing, expired, or revoked reference tokens return active: false.

The tradeoff is real. Resource servers now depend on introspection. That means client credentials for the API, network paths, timeout behavior, caching decisions, monitoring, and failure handling become part of the design. Reference tokens reduce token visibility, but they do not make resource-server validation optional.

RFC 7662 defines OAuth token introspection. RFC 7009 defines token revocation. The ProAuth implementation details are covered in the reference access token documentation.

JWE Hides Claims, But It Adds Key Operations

Encrypted tokens solve a different problem.

With JWE, the token can still be self-contained, but its claims are not readable by every component that sees the token string. The ProAuth v3 preview docs describe encrypted JWTs for access tokens, ID tokens, and UserInfo responses. They use compact JWE serialization and contain an inner signed JWT. The resource server or client decrypts the outer token, then validates the inner signed JWT.

That is useful when token contents should not be visible in browser tooling, proxies, gateway logs, or support traces. It does not remove the need for normal token validation. It moves confidentiality into the token format and moves decryption keys into the operational model.

In ProAuth, token encryption is configured on the client application. ID token and UserInfo encryption require both alg and enc settings and a matching client encryption key from Client App Key Sets. Access-token encryption has a per-client override that can inherit the tenant default. Reference access tokens are unaffected by access-token encryption settings because they are already opaque handles.

One implementation detail is worth calling out because it is the sort of thing that prevents accidental downgrade: the docs state that if encryption is configured but no usable key is available, ProAuth fails closed instead of returning plaintext.

RFC 7516 defines JSON Web Encryption. The ProAuth configuration details are in the token encryption documentation and the Client App Key Sets documentation.

JWT Introspection Protects The Status Check

Plain RFC 7662 introspection returns JSON. That is simple and widely understood. In some deployments, the resource server also wants cryptographic integrity on the introspection response itself.

The ProAuth v3 preview docs describe support for RFC 9701 JWT responses at the token introspection endpoint. A resource server requests the JWT response with Accept: application/token-introspection+jwt. ProAuth returns application/token-introspection+jwt, signs the JWT with the authorization-server signing key, and uses the typ header value token-introspection+jwt.

The payload contains wrapper claims and a nested token_introspection object. Resource servers must validate the JWT signature with the ProAuth discovery jwks_uri, check the issuer, check the audience, and require the typ header to be token-introspection+jwt. If the token is inactive or not intended for the authenticated resource server, ProAuth returns a signed JWT whose nested object contains only { "active": false }.

That last behavior matters. The integrity protection is not just about active tokens. It also lets the resource server verify that an inactive answer came from the authorization server and was intended for that resource server.

JWT introspection responses can also be encrypted. In that case, the docs describe a nested model: ProAuth signs the JWT first and then encrypts it as JWE when introspection response encryption is configured.

Resource Servers Still Own The Final Check

Token format can reduce exposure, centralize state, or add cryptographic protection around introspection. It cannot move all authorization responsibility out of the API.

The ProAuth v3 preview includes ProAuth.Oidc.ResourceServer.AspNetCore for ASP.NET Core APIs that consume ProAuth access tokens. The resource-server documentation says the package validates normal bearer JWTs and can additionally enforce sender-constrained access tokens, encrypted access tokens, and reference tokens.

For this article, the important part is the validation split:

  • readable JWT access tokens are validated locally
  • JWE access tokens are decrypted when token decryption is configured
  • opaque reference tokens are resolved through IAccessTokenIntrospectionClient
  • JWT introspection responses are supported when the API supplies validation parameters for issuer, audience, signing keys, and optional decryption keys

That means a migration to reference tokens or encrypted tokens is not only an authorization-server setting. The resource server has to be ready for the token it accepts. If an API will accept reference tokens, introspection must be configured. If it will accept encrypted self-contained tokens locally, decryption keys and validation behavior must be in place. If it will rely on JWT introspection, the API must validate the introspection JWT rather than treating the response body as trusted because it arrived over HTTPS.

The resource-server package documentation is the right starting point for API-side behavior: ASP.NET Core Resource Server.

A Practical Selection Rule

Start from the API, not the feature list.

Use self-contained signed JWT access tokens when local validation, low latency, and simple API deployment matter more than immediate central revocation or claim confidentiality from intermediaries.

Use reference tokens when the API can operate introspection reliably and the design benefits from server-side token contents, central status, and revocation becoming visible immediately through introspection.

Use encrypted tokens when claims should remain confidential from components that may see the token string, and the team is ready to manage encryption keys and decryption behavior.

Use JWT introspection responses when the API already depends on introspection and needs signed, and optionally encrypted, status responses rather than plain JSON.

Many systems will use more than one pattern. A public-facing API might use short-lived JWTs. An administrative API might require sender-constrained tokens and JWT introspection. A browser-adjacent path might avoid browser-visible access tokens entirely through a BFF, while an API-to-API path uses reference tokens for revocation-sensitive access.

The wrong move is to decide from the acronym outward.

For implementation details, start with the ProAuth docs for reference access tokens, token encryption, and ASP.NET Core resource servers. The broader v3 security scope is tracked in the ProAuth 3.0.0 release notes. Because this post is dated during the v3 preview window, treat product behavior as preview-era guidance and confirm the exact docs for the build you deploy.