Ecosystem PentestHint Academy Labs Trionyx
API Security

JWT Security Best Practices: Secure JSON Web Token Implementation

JSON Web Tokens are widely used to carry authentication and authorization information between applications, APIs, identity providers, and microservices. Because JWTs can be verified without contacting the issuing server for every request, they are...

On this page
  1. What Is a JWT?
  2. Why JWT Security Matters
  3. How JWT Authentication Works
  4. JWT Security Best Practices
  5. 1. Explicitly Allow Only Expected Algorithms
  6. Avoid the none Algorithm
  7. 2. Prevent Algorithm Confusion Attacks
  8. 3. Use Strong Signing Keys
  9. 4. Validate the Signature Before Trusting Claims
  10. 5. Validate iss — The Issuer
  11. 6. Always Validate the Audience
  12. 7. Validate exp, nbf, and iat
  13. 8. Keep JWT Lifetimes Reasonably Short
  14. 9. Do Not Put Sensitive Data in JWT Claims
  15. 10. Protect JWTs During Storage
  16. 11. Do Not Log JWTs
  17. 12. Protect Against JWT Replay
  18. 13. Manage Key Rotation Properly
  19. 14. Never Blindly Trust jku, jwk, or x5u
  20. Common JWT Attacks
  21. Algorithm Confusion
  22. Weak Secret Attack
  23. alg: none Attack
  24. Token Tampering
  25. Token Replay
  26. Cross-JWT Confusion
  27. JWT Security Testing for Penetration Testers
  28. Inspect the Header
  29. Inspect the Claims
  30. Test Algorithm Restrictions
  31. Test Signature Validation
  32. Test Expiration
  33. Test Audience Validation
  34. Test Key Handling
  35. JWT Security Checklist
  36. JWT vs Traditional Server-Side Sessions
  37. JWTs in OAuth 2.0
  38. Recommended JWT Security Architecture
  39. Useful JWT Security Resources
  40. Frequently Asked Questions
  41. What are the most important JWT security best practices?
  42. Is JWT secure for authentication?
  43. Can a JWT be decoded without the secret key?
  44. What happens if a JWT is stolen?
  45. Should JWT contain passwords or sensitive information?
  46. What is an algorithm confusion attack in JWT?
  47. Should JWT use RS256 or HS256?
  48. What should penetration testers check in JWT authentication?
  49. Conclusion

JSON Web Tokens are widely used to carry authentication and authorization information between applications, APIs, identity providers, and microservices. Because JWTs can be verified without contacting the issuing server for every request, they are attractive for distributed systems and modern API architectures.

But a JWT is not automatically secure just because it is signed. Weak signing keys, incorrect algorithm validation, missing claim checks, poor token storage, excessive token lifetimes, and insecure key management can turn a JWT-based authentication system into an easy target.

The IETF published RFC 8725, JSON Web Token Best Current Practices, specifically to address common implementation and deployment problems. The guidance covers algorithm verification, key strength, issuer and audience validation, token confusion, and other JWT security concerns.

This guide explains practical JWT security best practices for developers, security engineers, and penetration testers.

What Is a JWT?

A JSON Web Token, commonly called JWT, is a compact representation of claims that can be digitally signed, protected with a MAC, and, in some designs, encrypted.

The JWT standard is defined in RFC 7519. A signed JWT commonly has three Base64URL-encoded components separated by periods:

header.payload.signature

For example:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
.
eyJzdWIiOiIxMjM0NTY3ODkwIiwicm9sZSI6InVzZXIifQ
.
signature

The three components are:

  1. Header — describes metadata such as the signing algorithm.
  2. Payload — contains claims.
  3. Signature — provides integrity and authenticity when correctly validated.

A JWT should not be treated as an encrypted password or secret container. In a typical signed JWT, the header and payload can be decoded by anyone who has the token. The signature protects integrity; it does not automatically provide confidentiality. RFC 7519 defines JWT as a claims representation format that can be signed, MACed, and/or encrypted depending on the JOSE construction being used.

Why JWT Security Matters

JWTs often sit directly in the authentication path.

A typical API request may look like:

GET /api/profile HTTP/1.1
Host: api.example.com
Authorization: Bearer <JWT>

If the server accepts the token, it may use claims such as sub, role, scope, iss, or aud to make authorization decisions.

This creates an important security boundary.

If an attacker steals a valid token, modifies claims, discovers a weak signing secret, or finds a validation flaw, the attacker may be able to impersonate a user or access resources they should not be able to reach.

The problem is not the JWT format itself. Most serious JWT vulnerabilities come from incorrect validation, weak cryptography, insecure key handling, or poor application design. RFC 8725 specifically notes that published JWT attacks have resulted from under-specified security mechanisms, incomplete implementations, and incorrect application usage.

For practical security learning, “https://vuln.pentesthint.com/” hands-on labs can help security professionals understand these weaknesses in controlled environments.

How JWT Authentication Works

A simplified JWT authentication flow looks like this:

User
  |
  | Login
  v
Authentication Server
  |
  | Creates and signs JWT
  v
Client
  |
  | Authorization: Bearer JWT
  v
API / Resource Server
  |
  | Verify signature + claims
  v
Protected Resource

The server should not simply decode the token and trust its contents.

A secure verification process should determine:

  • Is the token correctly signed?
  • Is the signing algorithm expected?
  • Is the signing key trusted?
  • Has the token expired?
  • Is the issuer trusted?
  • Is the audience correct?
  • Is the subject valid?
  • Is the token intended for this application?
  • Is the token type correct?
  • Does the token contain the required claims?
  • Has the token been revoked or otherwise invalidated where required?

This distinction between decoding and validating a JWT is extremely important.

Decoding a token only tells you what data it contains. Validation determines whether the application should trust that data.

JWT Security Best Practices

1. Explicitly Allow Only Expected Algorithms

One of the most important JWT security best practices is to control which algorithms the application accepts.

Do not blindly trust the alg value supplied by the token.

For example:

{
  "alg": "RS256",
  "typ": "JWT"
}

The application should already know which algorithm is valid for that token type and issuer.

RFC 8725 states that applications must restrict JWT processing to supported algorithms and that each key should be used consistently with the intended algorithm.

A dangerous implementation might effectively do this:

Read alg from token
        ↓
Use whatever algorithm the token requests
        ↓
Verify token

A safer approach is:

Identify trusted token profile
        ↓
Select approved algorithm
        ↓
Select correct key
        ↓
Verify signature
        ↓
Validate claims

Do not rely on an algorithm allowlist supplied by the attacker-controlled token itself.

Avoid the none Algorithm

Historically, some JWT implementations accepted:

{
  "alg": "none"
}

as an unsecured JWT.

Modern libraries should not accept unsecured JWTs unless the application explicitly requires that behavior for a protected use case. RFC 8725 discusses the risks of algorithm substitution and unsecured JWTs.

For normal authentication and authorization, an unsigned JWT should not be accepted as a valid credential.

2. Prevent Algorithm Confusion Attacks

Algorithm confusion occurs when an application incorrectly allows a token to switch between asymmetric and symmetric algorithms.

A classic example involves changing:

RS256

to:

HS256

If the vulnerable application then uses an RSA public key as an HMAC secret, an attacker may be able to create a forged token.

RFC 8725 specifically identifies this class of attack and recommends ensuring that the algorithm and key type are consistent.

OWASP also identifies key-type confusion as a JWT threat and recommends explicitly restricting accepted algorithms and using correctly typed keys.

During a penetration test, changing the alg header is therefore a useful test when the application appears to accept JWTs.

3. Use Strong Signing Keys

Cryptography is only as strong as the keys protecting it.

This becomes particularly important when using HMAC algorithms such as HS256.

Never use values such as:

password123
secret
admin123
company2026

as an HMAC signing secret.

A weak secret can allow offline brute-force or dictionary attacks if an attacker obtains a JWT.

RFC 8725 explicitly states that human-memorizable passwords must not be directly used as keys for keyed-MAC algorithms such as HS256.

OWASP recommends generating HMAC secrets using a cryptographically secure random source and ensuring sufficient entropy.

For larger systems, asymmetric signing can also simplify key distribution because services can verify signatures using public keys without receiving the private signing key.

4. Validate the Signature Before Trusting Claims

A common mistake is to decode the JWT and immediately use its contents.

Consider:

{
  "sub": "1001",
  "role": "admin"
}

The application must not assume that these claims are trustworthy merely because they look valid.

The signature must be successfully verified using a trusted key and an approved algorithm.

If signature validation fails, the complete JWT should be rejected.

RFC 8725 requires cryptographic operations used for JWT validation to be successfully validated and says the JWT must be rejected if validation fails.

5. Validate iss — The Issuer

The iss claim identifies the issuer that created the token.

Example:

{
  "iss": "https://identity.example.com"
}

An application should not accept a token simply because its signature is mathematically valid.

The signing key must also belong to an issuer the application trusts.

RFC 8725 requires applications to validate the issuer relationship and ensure that the cryptographic keys used for the JWT belong to the expected issuer.

This becomes particularly important when an application trusts multiple identity providers.

6. Always Validate the Audience

The aud claim identifies the intended recipient or audience of a JWT.

For example:

{
  "iss": "https://identity.example.com",
  "aud": "payments-api"
}

Suppose an identity provider issues tokens for:

profile-api
payments-api
admin-api

A token issued for profile-api should not automatically work against admin-api.

This is known as a token substitution or cross-service confusion problem.

RFC 8725 recommends audience validation when tokens may be issued for multiple relying parties or applications. A token with a missing or incorrect audience should be rejected when audience validation is required by the application profile.

7. Validate exp, nbf, and iat

Time-related claims should be validated according to the application’s requirements.

Common claims include:

{
  "iat": 1756000000,
  "nbf": 1756000000,
  "exp": 1756003600
}

They represent:

  • iat — issued at
  • nbf — not before
  • exp — expiration time

An expired token should not continue granting access simply because its signature remains valid.

Keep clock-skew tolerance small and deliberate rather than accepting tokens far outside their intended validity period.

8. Keep JWT Lifetimes Reasonably Short

JWTs are often described as “stateless,” but that does not mean they should live forever.

A stolen JWT can usually be replayed until it expires or is otherwise rejected.

For example:

Access token:
10–15 minutes

may provide a smaller attack window than:

Access token:
30 days

The correct lifetime depends on the application, risk level, and session architecture.

For high-value operations, consider additional controls instead of relying solely on a bearer token.

9. Do Not Put Sensitive Data in JWT Claims

JWT payloads are commonly Base64URL encoded rather than encrypted.

For example:

{
  "sub": "12345",
  "email": "user@example.com",
  "role": "admin"
}

Anyone who obtains the token can generally decode these values.

Do not place secrets, passwords, private keys, payment credentials, or unnecessary personal information inside a normal signed JWT.

If confidentiality is genuinely required, an appropriate encryption mechanism such as JWE may be considered. But encryption should not be used as an excuse to put unnecessary sensitive data into tokens.

10. Protect JWTs During Storage

Where a JWT is stored depends on the application architecture.

Browser applications require special care because tokens exposed to JavaScript may become accessible to malicious scripts after an XSS vulnerability.

For browser-based sessions, secure, appropriately configured cookies can provide strong protections when combined with controls such as:

Secure
HttpOnly
SameSite

The correct design depends on the application.

The important principle is to minimize token exposure and avoid casually storing long-lived credentials in browser-accessible locations.

OWASP also warns that JWTs are not always the best choice for session management and recommends considering traditional server-side session mechanisms when their operational characteristics are more appropriate.

11. Do Not Log JWTs

JWTs should never appear in:

  • Application logs
  • Error messages
  • Debug output
  • Analytics events
  • Monitoring dashboards
  • Support tickets
  • Screenshots
  • Client-side telemetry

A developer might write:

Authorization header: <JWT>

to simplify debugging.

That token can later end up in centralized logging systems where many employees, services, or third parties can access it.

Treat tokens like passwords from a logging perspective.

12. Protect Against JWT Replay

JWTs are often bearer credentials.

If an attacker steals one, they may be able to present it to the API without knowing the user’s password.

Short expiration periods reduce the attack window, but they do not completely solve replay.

For higher-risk environments, applications can consider mechanisms that bind a token to a particular client or cryptographic key.

OWASP discusses deny lists, token status mechanisms, nonces, short expiration times, and sender-constrained tokens as possible approaches depending on the use case.

13. Manage Key Rotation Properly

Signing keys should not remain unchanged forever.

A mature JWT infrastructure should support:

  • Key rotation
  • Key versioning
  • Secure key storage
  • Emergency key replacement
  • Public-key distribution
  • Overlapping old and new keys during migration

The kid header is commonly used to identify which key should be used for verification.

However, kid is attacker-controlled input.

Do not blindly insert it into a database query, LDAP query, filesystem path, or other backend lookup.

RFC 8725 specifically warns that received JWT claims and headers such as kid can become injection vectors.

14. Never Blindly Trust jku, jwk, or x5u

JWT headers can contain information related to key selection or key retrieval.

Examples include:

jwk
jku
x5u
kid

A dangerous implementation may automatically retrieve a verification key from a URL supplied by the JWT.

For example:

{
  "jku": "https://attacker.example/keys.json"
}

If the server blindly follows that URL, the JWT validation process itself can become an SSRF or key-injection vector.

RFC 8725 recommends establishing trust in keys independently rather than blindly trusting key material supplied by the token.

Common JWT Attacks

Algorithm Confusion

The attacker changes the JWT algorithm or attempts to make the verifier use the wrong key type.

Defense: Explicitly configure approved algorithms and associate each key with its intended algorithm.

Weak Secret Attack

The application uses a predictable HS256 secret.

The attacker obtains a token and attempts offline password or dictionary attacks against the signing secret.

Defense: Use high-entropy cryptographic keys rather than human-readable passwords.

alg: none Attack

The attacker attempts to remove the signature requirement by changing the algorithm to none.

Defense: Do not accept unsecured JWTs for normal authentication or authorization.

Token Tampering

An attacker modifies claims such as:

{
  "role": "user"
}

to:

{
  "role": "admin"
}

Defense: Verify the signature and reject modified tokens.

Token Replay

An attacker steals a valid token and reuses it.

Defense: Short token lifetimes, secure storage, revocation mechanisms where appropriate, and sender-constrained tokens for high-risk environments.

Cross-JWT Confusion

A JWT issued for one purpose is accepted in another context.

For example, an ID token might accidentally be accepted where an API access token is expected.

RFC 8725 specifically recommends making validation rules for different JWT types mutually exclusive. Explicit typing, different audiences, issuers, claims, or keys can help prevent this type of confusion.

JWT Security Testing for Penetration Testers

JWT authentication should be tested as a complete security mechanism rather than simply decoding the token.

Inspect the Header

Look for:

{
  "alg": "RS256",
  "typ": "JWT",
  "kid": "key-01"
}

Test whether changing alg, typ, or kid affects validation.

Inspect the Claims

Review:

  • iss
  • sub
  • aud
  • exp
  • nbf
  • iat
  • jti
  • scope
  • role
  • Application-specific claims

Look for excessive privileges and trust decisions based on attacker-controlled values.

Test Algorithm Restrictions

Try changing:

RS256 → HS256

where relevant.

Also test whether:

alg → none

is rejected.

Do this only against systems you are authorized to assess.

Test Signature Validation

Modify a claim without generating a valid signature:

{
  "role": "admin"
}

The server should reject the token.

If the modified token is accepted, the application has a critical authentication or authorization flaw.

Test Expiration

Take an expired token and send it to the API.

The application should reject it.

Also check whether different API endpoints apply the same expiration rules.

Test Audience Validation

Obtain a valid token intended for one API and test whether it can access another API that should not accept it.

This can expose cross-service authorization problems.

Test Key Handling

Review how the application handles:

kid
jku
jwk
x5u

Look for:

  • SQL injection
  • LDAP injection
  • SSRF
  • Local file access
  • Untrusted key retrieval
  • Key confusion

RFC 8725 specifically highlights these header values as potential sources of security problems when applications trust received values without appropriate controls.

Security professionals who want to improve practical application-security skills can use “https://academy.pentesthint.com/“cyber security training</a> and controlled “https://vuln.pentesthint.com/” vulnerability labs to practice JWT testing safely.

JWT Security Checklist

Before deploying JWT-based authentication, verify:

  • Approved signing algorithms are explicitly configured.
  • The application does not blindly trust the alg header.
  • none is rejected for normal authentication tokens.
  • Strong cryptographic keys are used.
  • HMAC secrets have sufficient entropy.
  • RSA, EC, or other asymmetric keys are protected appropriately.
  • JWT signatures are always validated.
  • iss is validated when applicable.
  • aud is validated when applicable.
  • exp is enforced.
  • nbf is validated where used.
  • Token lifetimes are appropriate for the risk.
  • Sensitive information is not unnecessarily placed in claims.
  • JWTs are not written to application logs.
  • Tokens are stored using an appropriate security model.
  • Replay risk has been considered.
  • Key rotation is supported.
  • kid is safely handled.
  • jku, jwk, and x5u are not blindly trusted.
  • Different JWT types have separate validation rules.
  • API audience restrictions are enforced.
  • Revocation requirements are documented.
  • JWT libraries are kept updated.
  • Security testing covers both token creation and token validation.

JWT vs Traditional Server-Side Sessions

JWTs are useful, but they are not automatically better than traditional sessions.

A server-side session can be easier to invalidate immediately because the server controls the session state.

JWTs can be useful when multiple services need to validate claims without continuously querying a central session store.

The trade-off is important.

With JWTs, revocation and immediate session invalidation can become more complicated. OWASP notes that using JWTs for stateless sessions may require a denylist or other mechanism when immediate invalidation is needed, which reduces some of the simplicity associated with a purely stateless design.

The right choice depends on the architecture.

Ask:

  • Do multiple services need independent token validation?
  • How important is immediate revocation?
  • How sensitive is the data?
  • How long do sessions need to remain active?
  • Can the application safely manage signing keys?
  • Would a traditional session store be simpler?

Do not introduce JWTs simply because they are popular.

JWTs in OAuth 2.0

JWTs are frequently used as OAuth 2.0 access tokens, but OAuth 2.0 does not require access tokens to use JWT format.

RFC 9068 defines a standardized JWT profile for OAuth 2.0 access tokens and specifies claims and validation requirements for this use case.

This distinction matters because developers sometimes assume:

OAuth access token = JWT

That is not universally true.

An OAuth authorization server can issue opaque access tokens or JWT access tokens depending on the architecture.

When JWTs are used as OAuth access tokens, the resource server should validate the token according to the applicable OAuth profile rather than treating it as a generic JWT.

A mature implementation can follow this pattern:

                  Identity Provider
                         |
                         | Sign JWT
                         v
                 +----------------+
                 | Token Service  |
                 +----------------+
                         |
                         | JWT
                         v
              +---------------------+
              | API Gateway / WAF   |
              +---------------------+
                         |
                         v
              +---------------------+
              | JWT Validation      |
              | - Signature         |
              | - Algorithm         |
              | - Issuer            |
              | - Audience          |
              | - Expiration        |
              | - Token Type        |
              +---------------------+
                         |
                         v
                 Protected API
                         |
                         v
                    Database

The important part is that every trust decision happens after validation.

A valid cryptographic signature alone does not mean that the token is valid for every API, user, or purpose.

Useful JWT Security Resources

For the formal JWT specification, consult the IETF’s RFC 7519.

For implementation security, RFC 8725 is particularly important because it provides the IETF’s Best Current Practices for JSON Web Tokens and covers algorithm verification, key management, issuer and audience validation, token confusion, and untrusted header values.

The OWASP JSON Web Token Cheat Sheet is also a useful practical reference for developers and penetration testers. It covers algorithm confusion, unsecured tokens, key management, replay protection, and JWT revocation.

For OAuth environments that use JWT access tokens, RFC 9068 provides the standardized JWT profile for OAuth 2.0 access tokens.

For broader application-security work, “https://pentesthint.com/” PentestHint provides cybersecurity resources focused on security testing, vulnerability research, and practical application security.

Frequently Asked Questions

What are the most important JWT security best practices?

The most important practices include explicitly allowing only approved algorithms, using strong signing keys, validating signatures and claims, checking iss and aud, enforcing expiration, protecting tokens from theft, rotating keys, and preventing token confusion.

Is JWT secure for authentication?

JWT can be used securely for authentication, but the security depends heavily on implementation. A JWT with a weak signing key or incomplete claim validation can be dangerous even when a strong cryptographic algorithm is used.

Can a JWT be decoded without the secret key?

Yes. Signed JWT headers and payloads are normally Base64URL encoded rather than encrypted. The signing key is needed to create or verify a valid signature, not simply to decode the contents.

What happens if a JWT is stolen?

A stolen bearer JWT may be replayed until it expires or is otherwise rejected. The impact depends on the token’s privileges, lifetime, storage model, and whether the application uses revocation or sender-constraining mechanisms.

Should JWT contain passwords or sensitive information?

No. Normal signed JWTs do not automatically hide their payload. Avoid putting passwords, private keys, payment credentials, or unnecessary sensitive information inside JWT claims.

What is an algorithm confusion attack in JWT?

An algorithm confusion attack occurs when a JWT verifier incorrectly allows an attacker to change the signing algorithm or key type, potentially causing the server to verify a forged token using an inappropriate key.

Should JWT use RS256 or HS256?

Neither is universally correct. The choice depends on the architecture and key-management model. The important requirement is to explicitly define acceptable algorithms, use sufficiently strong keys, and never allow the token itself to dictate unsafe verification behavior.

What should penetration testers check in JWT authentication?

Testers should examine algorithm handling, signature validation, weak keys, claim manipulation, issuer and audience checks, expiration, token replay, key rotation, kid handling, untrusted key URLs, token storage, and cross-JWT confusion.

Conclusion

JWTs provide a compact and flexible way to carry security claims across applications and APIs, but the format itself does not guarantee secure authentication.

The strongest JWT implementations make trust decisions explicit. They restrict algorithms, protect signing keys, verify signatures, validate issuer and audience, enforce expiration, control token lifetime, and carefully manage token storage and key rotation.

Security teams should also pay attention to less obvious issues such as algorithm confusion, weak HMAC secrets, malicious kid values, untrusted jku or x5u references, token replay, and cross-JWT confusion. These are exactly the types of implementation mistakes highlighted by RFC 8725 and OWASP’s JWT guidance.

For penetration testers, JWT security is especially valuable because authentication flaws often appear in the gap between token creation and token validation. Understanding the complete JWT lifecycle makes it easier to identify weaknesses that a simple token decoder will never reveal.

If you want to build stronger practical application-security skills, explore “https://academy.pentesthint.com/” learn cyber security resources and controlled “https://vuln.pentesthint.com/” cyber security labs from PentestHint.

Author

Saurabh Pareek

I'm an aspiring Penetration Tester who enjoys learning how applications work and, more importantly, how they can be secured. Cybersecurity isn't just something I'm studying—it's something I genuinely enjoy exploring every day. Most of my time goes into learning web application security, API security, and common vulnerabilities. I like breaking down technical topics into simple, easy-to-understand explanations, which is why I regularly write cybersecurity blogs on PentestHint. Some of the topics I've covered include Directory Traversal, Remote Code Execution (RCE), Broken Object Level Authorization (BOLA), and JWT Security. I believe the best way to learn cybersecurity is by doing it. That's why I spend time practicing in labs, solving security challenges, and researching how real-world attacks happen. Every vulnerability I study teaches me something new and helps me improve my skills. I also enjoy sharing what I learn with the cybersecurity community through blogs and LinkedIn. Writing not only helps me reinforce my own understanding but also makes technical concepts easier for others who are starting their journey. My goal is to grow into a skilled penetration tester who can help organizations identify security risks before attackers do. I'm always learning, always curious, and always looking for the next opportunity to improve.

Keep reading

Related posts

Leave a Reply

Your email address will not be published. Required fields are marked *