DEV Community

StarkMan
StarkMan

Posted on

JWT access tokens need explicit issuer, algorithm, and audience checks

JWT access tokens need explicit issuer, algorithm, and audience checks

A JSON Web Token looks self-contained because the claims are readable and the signature can be checked locally. That convenience can hide a weak validation path. A service that accepts any valid-looking signature, chooses a key from attacker-controlled metadata, or treats a token without checking its audience may turn a valid token from one context into authority in another.

RFC 8725 collects current best practices for JSON Web Tokens. It calls for the application to specify the algorithms it accepts and verify the header before using a key. It warns against the none algorithm and against algorithms selected solely by the token header. It also recommends validating the issuer, audience, and type according to the application's design. The token format does not provide these decisions automatically.

Make the verifier a policy

A verifier should have a narrow purpose: issuer endpoint, acceptable algorithms, key source, audience, allowed clock skew, required claims, and token type. If an access token for the reporting API is presented to the administration API, the audience check should fail. If an ID token is presented as an access token, the token type and claim structure should fail. A signature over the wrong kind of token is still a valid signature.

RFC 9068 profiles JWTs for OAuth 2.0 access tokens. It requires the resource server to reject a token whose audience does not contain its resource identifier. It also describes issuer and signature validation. Those requirements complement OAuth Resource Indicators because the authorization server can encode a specific target in the token, while the resource server enforces that target at the point of use.

Do not infer the key from a claim the caller can choose. Maintain a trusted set of issuer metadata and key identifiers. Cache keys for a bounded period, support rotation, and handle unknown key IDs as an error rather than falling back to a broad key. For symmetric algorithms, never share the public verification key as a secret signing key. For asymmetric algorithms, reject key types that do not match the configured algorithm.

Claims need application meaning

sub, scope, and custom role claims are inputs to an authorization decision, not permissions by themselves. A role such as admin may be global in one issuer and project-scoped in another. A user identifier may identify a person in the identity provider but not the local tenant. The verifier should map claims into a local principal with explicit tenant and resource attributes.

Timing deserves attention. Check exp and nbf with a small, documented clock skew. Treat missing required claims as invalid. Prevent a token from an old issuer or an old environment from validating after a migration. If the service supports both access and identity tokens, give each a different parser and test the crossover cases.

Log validation outcomes in categories: expired, wrong issuer, wrong audience, unknown key, unsupported algorithm, invalid signature, and missing claim. Do not log the token. A dashboard that collapses every rejection into "401" makes a configuration error and an attack attempt look the same.

Rotation is part of the trust boundary

Key rotation creates a period when old and new tokens may coexist. Publish keys with overlap, include key identifiers, and keep the verifier's allowed algorithm list stable. Monitor unknown-key identifiers before removing an old key. If clients cache metadata for too long, a rotation can cause an outage that pressure teams into weakening verification.

Revocation requires a separate design. A short-lived token may be acceptable when the consequence of use is low. For high-impact services, pair the token with session state, introspection, or a revocation list that the resource server checks. Do not claim that a signature check proves the token has not been revoked.

The practical test is adversarial and boring: a token from the wrong tenant, the wrong audience, an expired time, an altered role, a foreign issuer, an unsupported algorithm, and a key with the wrong type. The service should reject every case for the correct reason. JWT best practice is not a library setting. It is a written contract between the issuer, the verifier, and the resource that depends on the result.

References

Top comments (0)