How to Validate a JWT: Signature, Claims and Access
Validate signed JWTs with a configured issuer, trusted JWKS, expected audience, required claims, and token profile. Run rejection and rotation tests.
Validate a JWT against a configured issuer, key source, audience and token profile before using its claims. For a signed access token, verify the signature and required claims. Then enforce the permissions for the requested operation.
Decoding reveals data. Validation establishes whether the token meets the rules for your service. This guide uses a signed RS256 access-token example and includes runnable rejection tests.
Choose the expected token profile
A JWT can be signed or encrypted. This tutorial handles a compact signed JWS with three segments. Its encoded payload is readable. An encrypted JWE has a different representation and processing model. Accept only the profile your endpoint supports. JWT specification.
An ID token describes authentication to its client. It should not substitute for an access token at an unrelated API. Use access-token and ID-token boundaries when selecting validation rules.
Configure trust outside the token
| Value | Trusted source |
|---|---|
| Expected issuer | Application configuration |
| JWKS URL | Reviewed issuer metadata or pinned configuration |
| Allowed signing algorithms | The selected token profile |
| Expected audience | The receiving API's configured identifier |
| Required claims | The profile and application policy |
| Required permission | The requested application operation |
Do not fetch an arbitrary jku, certificate URL or issuer URL supplied inside an unverified token. Treat kid as a selection hint within an already trusted key set. Put limits on unknown-key refresh attempts.
Verify a signed API token
The following example assumes an approved RS256 issuer and a fixed JWKS URL. The audience is the API resource, not an arbitrary browser client identifier.
import jwt
from jwt import PyJWKClient
jwks = PyJWKClient("https://issuer.example.test/oauth/jwks.json")
def read_access_token(token: str) -> dict:
header = jwt.get_unverified_header(token)
if header.get("alg") != "RS256" or header.get("typ") != "at+jwt":
raise ValueError("Unexpected token profile")
key = jwks.get_signing_key_from_jwt(token)
claims = jwt.decode(
token,
key.key,
algorithms=["RS256"],
issuer="https://issuer.example.test",
audience="https://orders.example.test",
leeway=30,
options={"require": ["exp", "iat", "iss", "aud", "sub", "client_id", "jti"]},
)
if claims.get("token_use") != "access":
raise ValueError("Unexpected token use")
return claimsHere, token_use=access is an issuer-specific requirement. at+jwt identifies the expected access-token type. Confirm the actual issuer profile before adapting either rule. The 30-second leeway is an example policy, not a universal maximum. OAuth JWT access-token profile, PyJWT usage.
The header check only rejects an unexpected format. The signature and claim checks establish acceptance. Require claims explicitly when absence would otherwise be allowed by the library.
Enforce authorization after validation
A valid token can still lack permission to read an order. Check the granted scope and application resource policy after validation. Bind the decision to the active tenant or organization where relevant.
Do not use a display name, email suffix or missing role as a default administrator assignment. The multi-tenant access guide covers this boundary.
Run rejection tests before accepting traffic
Download the JWT validation example. It uses generated synthetic keys and a configured local key set. Its self-test does not require a live issuer.
python jwt-validation-example.pyThe fixture checks valid tokens and rejects wrong audiences, wrong issuers, expired tokens, missing claims, incorrect token use and untrusted keys. It also tests a rotated key after an approved key-set update.
For production, add a real approved issuer test and a bounded JWKS refresh policy. Keep old verification keys only for the intended overlap period. Record failures without storing raw tokens.
Track standards status accurately
RFC 8725 supplies published JWT security guidance. Its revision, draft-ietf-oauth-rfc8725bis-10, remained an Internet-Draft in the RFC Editor queue when checked on 12 November 2026. Treat draft changes as work in progress until publication. Published JWT BCP, revision status.
Review your verifier with NamoID
NamoID's current user access tokens use RS256, typ=at+jwt and token_use=access. Their audience identifies the authorized resource or userinfo endpoint. Management access uses a separate token-use value and audience.
Our engineers can help review your issuer configuration and API policy. Share your stack, expected audience and a synthetic failure case in Slack for an early response. Contact the NamoID team