What is JWT Validation?
JWT validation is the critical security process of verifying the integrity, authenticity, and validity of a JSON Web Token (JWT) before acting on its claims. It requires checking the signature using the issuer's public key (e.g., via JWKS), verifying standard claims like exp (expiration), nbf (not before), and iss (issuer), and ensuring the structure is correct.
Key steps for JWT validation:
- Signature verification: The server verifies the cryptographic signature (e.g., RS256, HS256) to ensure the token hasn't been tampered with.
- Key retrieval: Public keys are fetched from a JSON Web Key Set (JWKS) endpoint, often using the kid (Key ID) in the header.
- Structural checks: Ensures the token has three base64url-encoded parts (header, payload, signature) separated by dots.
-
Claim validation:
- Exp (Expiration): Checks if the current time is before the expiration time.
- Nbf (Not Before): Ensures the token is not being used before its allowed time.
- Iss (Issuer): Confirms the token was issued by the expected authority.
- Aud (Audience): Verifies the token is intended for the resource server.
This is part of a series of articles about API security.
In this article:
API Gateways and Edge Validation
Validating JWTs at the API gateway or edge layer allows invalid requests to be rejected before they reach backend systems. This is especially important for distributed systems, as it reduces unnecessary load on internal services and prevents unauthorized traffic from propagating further into the network.
API gateways can verify token signatures, expiration, and other standard claims. Some also support integration with identity providers to fetch public keys dynamically. Since these layers are usually the first point of contact, early validation helps enforce a consistent security posture across services.
Backend Services and Microservices
Even when JWTs are validated at the edge, backend services should not assume that tokens are always trustworthy. Microservices should perform local validation of JWTs, especially when services communicate directly without going through the gateway.
This involves re-checking signatures and validating critical claims like aud (audience) and scope, to ensure the token is meant for the specific service. Doing so protects against token reuse or privilege escalation in case another service is compromised. In some architectures, services use short-lived access tokens or internal service tokens to mitigate the risk of accepting stale or misused JWTs.
Client-Side Validation Limits
Clients can decode JWTs and inspect their contents, but they should not be trusted to validate or enforce security decisions based on token data. Signature verification requires access to secrets or public keys that should not be exposed in client environments.
While client-side validation can help with local session handling or user feedback, all critical validation, including signature and claims verification, must occur on the server side. Relying on clients for validation opens the door to forged tokens and unauthorized access.
Signature Verification
Signature verification ensures that the JWT has not been altered and that it was issued by a trusted authority. A JWT consists of three parts: header, payload, and signature. The signature is computed by encoding the header and payload using base64url, concatenating them with a dot (.), and then signing the result using a cryptographic algorithm defined in the JWT header.
There are two primary signing mechanisms:
- HMAC (e.g., HS256): The same secret is used to both sign and verify the token. The server must securely store this shared secret and never expose it.
- Asymmetric signing (e.g., RS256, ES256): A private key signs the token, and a corresponding public key is used for verification. The server must ensure it uses the correct public key tied to the token issuer.
During verification, the server recalculates the signature using the received header and payload, and compares it against the signature provided in the JWT. If they don’t match, the token must be rejected. Failing to verify the signature makes the application vulnerable to forged tokens.
Key Retrieval
The key used for signature verification depends on the signing algorithm and must be fetched or referenced securely:
- For HMAC (HS) algorithms: The secret key is static and must be stored securely on the server. It is not exposed externally.
- For asymmetric algorithms (RS/ES): The server needs access to the public key corresponding to the private key used by the issuer. This key can be hardcoded in configuration (static public key) or retrieved dynamically from a JWKS (JSON Web Key Set) endpoint published by the identity provider.
JWT headers often include a kid (Key ID) field. When retrieving keys from a JWKS, this ID helps select the correct key from the set. Servers should cache JWKS responses and handle key rotation gracefully. Failure to retrieve or match the correct key results in invalid signature verification and token rejection.
Claim Validation
exp (Expiration)
The exp claim is used to limit the lifespan of a token. It is a numeric timestamp (in seconds since epoch) indicating the time at which the token must no longer be accepted.
To validate it:
- Retrieve the current server time.
- Compare it to the exp value in the token.
- If the current time is equal to or greater than exp, the token is expired and should be rejected.
Tokens without an exp claim should generally not be accepted, as they may never expire. Implementing proper expiration checks is critical to reduce the impact of token leakage or replay attacks.
nbf (Not Before)
The nbf (Not Before) claim defines a future time before which the token must not be considered valid. Like exp, it is expressed as a UNIX timestamp.
Validation steps:
- Compare the current time to the nbf value.
- If the current time is before the nbf timestamp, the token is not yet valid and must be rejected.
This is useful for scenarios where tokens are pre-issued but not intended to be used until a specific time. While optional, if present, the nbf claim must be enforced to prevent premature use of the token.
iss (Issuer)
The iss claim identifies who issued the token, typically the authentication server or identity provider. This value must be validated against a pre-configured, trusted issuer string.
Validation process:
- Extract the iss value from the token.
- Compare it against the expected issuer URI or identifier.
- If they do not match, the token should be rejected.
This check helps ensure the token came from an expected and authorized issuer. Skipping this validation could allow tokens from other environments (e.g., dev or test) to be accepted in production.
aud (Audience)
The aud claim defines the intended recipient(s) of the token. It ensures that a token issued for one service or client cannot be used by another.
To validate:
- Extract the aud value, which may be a string or an array of strings.
- Compare it against the identifier for the service, such as a client ID or service name.
- If the service’s identifier is not listed in aud, reject the token.
This is essential in multi-tenant or service-mesh architectures where tokens flow between multiple services. Without proper aud validation, a token for one service could be misused in another.
Structural Checks
Before processing a JWT, it should be validated for correct structure:
- The token must consist of three base64url-encoded parts separated by dots (.): header, payload, and signature.
- Each part should decode cleanly into valid JSON (for header and payload).
- The header must include a valid alg (algorithm) field and optionally typ (usually "JWT").
- The payload should contain required claims depending on the security policy (e.g., exp, aud, iss).
Reject tokens that fail any of these basic formatting checks. Structural validation prevents the system from attempting to parse or trust malformed, incomplete, or corrupted tokens.
Here are some of the ways to ensure that the JWT validation process is secure.
1. Always Enforce Expected Algorithms
JWTs specify the signing algorithm in the alg field of the header. A common attack involves manipulating this value (for example, changing it to "none") to bypass signature verification if the server fails to enforce proper checks.
To prevent this:
- Maintain a strict allowlist of supported algorithms in server configuration (e.g., "RS256" or "ES256").
- Reject any token where alg does not match a configured, expected value.
- Never allow alg: none unless there's a specific and justified use case (rare in production systems).
- Avoid dynamically selecting the validation algorithm based on the token header. Instead, configure the server to expect a fixed algorithm and verify the match during validation.
This ensures attackers cannot trick the server into using weaker or null validation mechanisms by altering the JWT header.
2. Ensure Strict Issuer and Audience Matching
The iss (issuer) and aud (audience) claims define where the token originated and who it is intended for. Trusting tokens without verifying these fields can lead to tokens from other systems or tenants being accepted incorrectly.
Best practices include:
- Configure the expected iss and aud values in the application settings (e.g., environment variables or config files).
- Perform exact string matches for both values, including protocol, hostname, and path (if applicable). Do not allow partial or wildcard matching.
- Reject tokens where the iss claim does not match the expected trusted issuer URI.
- If aud is an array, confirm that the service’s unique identifier is present in the list.
- For APIs supporting multiple audiences (e.g., in multi-tenant systems), make sure each token is scoped correctly and cannot be reused across tenants.
Skipping or loosening issuer or audience validation can result in token confusion or unauthorized access across environments or services.
3. Enable Short Token Lifetimes with Rotation
Long-lived tokens increase the risk of misuse if they are leaked or intercepted. Even with HTTPS, there are still risks (e.g., browser storage leaks, logging issues, or memory dumps). Short lifetimes reduce the attack window.
Recommendations:
- Set access token expiration (exp) to a short duration, typically 5 to 15 minutes.
- Use refresh tokens or re-authentication to obtain new access tokens when needed.
- Rotate refresh tokens upon use and store them securely (e.g., HTTP-only cookies).
- Detect reuse of old or revoked refresh tokens and treat it as a potential security incident.
- Use rotating token identifiers (e.g., jti) to support denylist-based revocation mechanisms if required.
Short lifetimes limit how long a stolen token remains usable and improve the overall security of the authentication flow.
4. Secure Key Storage and Retrieval
The strength of JWT validation depends on secure management of cryptographic keys. Exposing secrets or keys, even briefly, can completely undermine security.
For HMAC (HS*) algorithms:
- Store shared secrets in environment variables, secure vaults, or hardware modules.
- Avoid hardcoding secrets in codebases or configuration files checked into version control.
- Rotate secrets periodically and update all consumers accordingly.
For RSA/EC (asymmetric) algorithms:
- Retrieve public keys from a trusted JWKS (JSON Web Key Set) endpoint over HTTPS.
- Cache keys locally for performance and to tolerate temporary unavailability.
- Validate JWKS responses (e.g., signature or source validation) if supported by the identity provider.
- Use the kid (Key ID) field in the JWT header to select the appropriate key from the JWKS.
- Handle key rotation smoothly; e.g., support multiple active keys during transition periods.
Any failure in secure key storage or retrieval can result in accepting forged tokens or disrupting legitimate traffic.
5. Use Mature Libraries
JWT validation involves cryptographic operations, claim parsing, and edge-case handling. Writing this logic manually is error-prone and discouraged.
Choose libraries that:
- Support all major JWT standards (RFC 7519) and algorithms you plan to use.
- Enforce signature verification by default and prevent insecure configurations (e.g., alg: none).
- Provide built-in validation for standard claims like exp, nbf, iss, aud, and sub.
- Allow configuration of clock skew tolerance for time-based claims.
- Support JWKS integration and kid-based key selection for asymmetric tokens.
Examples of trusted libraries include:
- Node.js: jsonwebtoken, jose
- Python: PyJWT, authlib
- Java: Nimbus JOSE + JWT, jjwt
- Go: golang-jwt/jwt
- .NET: System.IdentityModel.Tokens.Jwt
Always use up-to-date versions, monitor for security advisories, and audit dependencies regularly. Proper library choice and configuration are critical to avoid silent validation bypasses or insecure defaults.
JWT validation is essential across API gateways, backend services, and distributed microservices, but misconfigurations, inconsistent enforcement, and evolving attack techniques still expose APIs to real-world risk. Radware helps organizations secure JWT-based architectures with continuous discovery, behavioral analysis, and runtime enforcement that detect token misuse, block exploitation attempts, and ensure consistent protection across environments.
Radware API Security provides continuous API discovery and behavioral analytics that identify abnormal token usage patterns, privilege escalation attempts, and business logic abuse tied to compromised or misused JWTs. Baseline profiling helps detect replay activity, unusual access sequences, and unauthorized function-level access. Centralized visibility supports enforcement consistency across distributed services. These capabilities help organizations strengthen JWT governance at scale.
Radware Application Protection Service protects JWT-enabled APIs through real-time inspection and ML-driven behavioral detection. Runtime enforcement blocks malformed tokens, algorithm manipulation attempts, and unauthorized access requests targeting weak validation logic. Integrated protections address OWASP API risks while maintaining consistent policy enforcement across environments. This ensures APIs remain protected even as architectures evolve.
Radware Cloud WAF Service mitigates JWT-related threats at the application edge by blocking malicious authentication requests and suspicious payloads before they reach backend services. Virtual patching helps reduce exposure when validation weaknesses are discovered but not immediately remediated. Adaptive protections help enforce request validation and reduce misconfiguration risk. Real-time monitoring improves visibility into authentication abuse patterns.
Radware Bot Manager mitigates automated attacks targeting authentication workflows, including credential stuffing, token harvesting, brute-force attempts, and replay automation. Advanced detection distinguishes legitimate automation from malicious actors abusing JWT flows. Reducing automated abuse limits large-scale exploitation risk. Continuous monitoring enhances visibility into attack behavior.