A JWT access token is useful only when the receiving API can prove that the token was issued for it. Parsing the token and seeing a familiar user ID is not enough. The resource server must verify the signature, issuer, intended audience, time limits and the authorization claims it actually uses.

RFC 9068 defines an interoperable profile for OAuth 2.0 access tokens encoded as JSON Web Tokens. RFC 8707 defines how a client can name the protected resource it intends to call. Together, they put a practical boundary around one credential: who issued it, which API may accept it and what that API may authorize.

Start with the token type

A JWT-shaped string is not automatically an access token. RFC 9068 requires a JWT access token to carry the typ header value at+jwt and to be signed. The none algorithm is not permitted.

That type check helps prevent one kind of token from being accepted where another is expected. An ID token can also be a JWT, but it answers a different question: it describes an authentication event for a client. A resource API should not treat an ID token as an access token merely because both contain an issuer, subject and expiry.

Use a library that can enforce the expected token type and allowed algorithms. Do not select an algorithm just because the incoming header names it.

Verify the issuer and its signing key

The iss claim identifies the authorization server. The API should compare it with the exact issuer it trusts, then use that issuer’s current published verification keys and metadata.

Signature verification proves that a trusted issuer signed these bytes with an accepted key. It does not, by itself, prove that the token belongs at this API. A token can have a valid signature and still be intended for another resource.

Key rotation is normal. Cache the issuer’s key set with a bounded refresh policy, keep the last good set available through a short retrieval problem, and refresh when an unfamiliar key identifier appears. Do not fetch arbitrary key URLs from the token itself.

Match the audience to this API

The aud claim names the resource servers that may accept the token. RFC 9068 requires a resource server to reject a token when it is not listed as an audience.

This is the control that stops a token issued for one API from being replayed at another. Imagine a user authorizes a reporting service and receives a valid token for https://reports.example/. If a billing API accepts that token because the issuer and signature look right, the billing boundary has disappeared.

RFC 8707 lets a client send a resource parameter when it asks for authorization or a token. The authorization server can then mint a token with the appropriate audience and, where possible, downscope it to what that resource needs.

Prefer one audience when the architecture allows it. RFC 8707 warns that a bearer token valid at several resources can be presented by one of those resources to another, so multiple audiences require a higher degree of trust.

Treat time claims as policy inputs

Validate exp before accepting a token. Check nbf when present and allow only a small, documented clock-skew margin. Record the issuer time, API time and applied tolerance in diagnostics without logging the token.

Short lifetimes reduce the useful window after a token leaks, but they do not replace revocation, sender constraints or careful storage. A five-minute token can still authorize a damaging action for five minutes.

The iat claim helps with incident review and age policy. It should not become a made-up freshness rule unless the product has a clear maximum age independent of exp.

Separate identity from authorization

The sub claim identifies the subject in the issuer’s namespace. It is not automatically an email address, database key or permission. The API needs an explicit mapping from issuer and subject to its own identity model.

Authorization usually comes from scope, roles, groups, entitlements or a local policy decision. RFC 9068 standardizes several useful claim names, but the receiving API still decides what they mean.

A practical decision sequence is:

  1. verify token type, signature and allowed algorithm;
  2. verify the exact issuer;
  3. verify that this API is an audience;
  4. enforce expiry and not-before time;
  5. map the subject inside the issuer’s namespace;
  6. evaluate the action against scopes and local policy;
  7. apply object-level authorization to the requested record.

The final step matters. A valid invoice.read scope does not mean the caller may read every invoice. Our guide to object-level authorization covers the per-resource decision.

Be careful with claims that cross boundaries

A token may contain details that the target resource does not need. RFC 8707 encourages downscoping, partly because broad scope lists can reveal which services a person uses. The same privacy concern applies to identity and group claims.

Issue only what the receiving API needs. If two resources have different privacy or authorization requirements, separate tokens are easier to reason about than one broad token accepted everywhere.

Avoid copying claims into long-lived logs. For an authorization audit, record the issuer, a stable subject reference, token identifier when one exists, audience decision, policy version and result. Do not record the bearer credential.

Test rejection, not only acceptance

A validation suite should include:

  • a correctly signed token for another audience;
  • a token from an untrusted issuer;
  • a token signed with a disallowed algorithm;
  • an expired token and a not-yet-valid token;
  • an ID token presented to the API;
  • a token with the right scope but access to the wrong object;
  • an old signing key during and after a planned rotation;
  • a token with an unknown key identifier while the issuer’s key endpoint is unavailable.

Those cases expose boundary errors that a happy-path login test will not find.

Sources and version note

Checked 27 October 2026 against RFC 9068: JSON Web Token Profile for OAuth 2.0 Access Tokens (October 2021) and RFC 8707: Resource Indicators for OAuth 2.0 (February 2020). This is a design and validation guide, not a security assessment of a particular implementation.