Your browser does not support JavaScript! This site works best with javascript ( and by best only ).9 JWT Security Best Practices for APIs | Antler Digital

9JWTSecurityBestPracticesforAPIs

2025-09-29

Sam Loyd
9 JWT Security Best Practices for APIs

JSON Web Tokens (JWTs) are widely used for API authentication, but poor implementation can expose your system to attacks. To protect your APIs, follow these nine best practices:

  1. Use HTTPS: Always encrypt JWT transmission to prevent interception, especially on public networks.
  2. Select Strong Algorithms: Avoid weak or deprecated algorithms like "none". Use secure options like RS256 or ES256.
  3. Set Short Expiration Times: Limit token validity to minimise risks if a token is compromised. Use refresh tokens for extended access.
  4. Secure Storage: Store tokens in HTTP-only cookies or secure device storage to reduce XSS vulnerabilities.
  5. Limit Payload Content: Include only essential claims in the payload. Avoid sensitive or frequently changing data.
  6. Validate Tokens on Every Request: Check signatures, claims, and expiration for every API call.
  7. Implement Revocation Mechanisms: Use blacklists or user-level revocation to handle compromised tokens.
  8. Defend Against XSS and CSRF: Use content security policies, secure cookies, and CSRF tokens for added protection.
  9. Review Security Regularly: Continuously monitor, test, and update your JWT practices to address emerging threats.

1. Use HTTPS for All JWT Transmission

Imagine sending your house keys through the post in a transparent envelope - that's what transmitting JWTs over an unencrypted HTTP connection looks like. Every bit of information travels in plain text, making it an open invitation for attackers to intercept and steal your tokens.

The danger escalates on public Wi-Fi networks, like those in cafés, airports, or hotels. On such networks, man-in-the-middle (MITM) attacks allow bad actors to capture JWTs. Once they have a token, they can impersonate the legitimate user, potentially bypassing even multi-factor authentication.

"If your app is sending JWTs without HTTPS, you're basically handing out free access keys." - Arunangshu Das

HTTPS changes the game. It encrypts all data during transit, ensuring that even if someone intercepts the traffic, all they see is encrypted gibberish - not the actual token. This encryption safeguards both the confidentiality and integrity of your JWTs, keeping them secure as they move between client and server.

But don't stop at client-to-server communication. In microservices architectures, JWTs are often exchanged internally between backend components. These internal communications need protection too, so always use Transport Layer Security (TLS) to maintain encryption within your private network.

"HTTPS isn't just for login pages or e-commerce sites. Any data transmitted between client and server, especially JWTs, should use HTTPS." - QwietAI

To fully secure your app, enforce HTTPS across all environments - production, staging, and development. Implement HTTP Strict Transport Security (HSTS) to ensure browsers automatically upgrade HTTP requests to HTTPS, blocking protocol downgrade attacks.

Finally, avoid sending JWTs in URLs or query parameters. These can be exposed in server logs, browser history, or referrer headers, creating unnecessary security risks.

2. Choose Strong, Recognised Algorithms

After ensuring secure transmission with HTTPS, the next crucial step is selecting robust cryptographic algorithms for your JSON Web Tokens (JWTs). Think of this as choosing the right lock for your valuables - picking a weak algorithm is like securing a bank vault with a flimsy paper lock. It might look safe, but it’s far from it.

Weak algorithms leave your system exposed. Take the "none" algorithm, for example - it allows tokens without any signature verification, essentially giving attackers free rein to create invalid tokens. Similarly, using HS256 with weak secrets (like short passwords or common dictionary words) makes your tokens vulnerable to brute force attacks, which could crack them in minutes.

Symmetric vs Asymmetric Algorithms

JWTs rely on two main types of algorithms: symmetric and asymmetric. The choice depends on the structure of your system.

  • Symmetric Algorithms: These (e.g., HS256, HS384, HS512) use the same secret key for both signing and verifying tokens. They’re straightforward and fast, making them perfect for single-application environments where one service handles both token creation and validation. However, as your system grows, sharing the secret key across multiple services increases the risk of exposure.
  • Asymmetric Algorithms: These (e.g., RS256, RS384, RS512, ES256, ES384, ES512) use a private key for signing and a public key for verification. This approach is ideal for distributed systems or microservices architectures. The private key remains securely with the authentication service, while public keys can be freely shared for token verification, reducing the risk of secret exposure.

Here are the algorithms you should consider for production environments:

  • RS256 (RSA with SHA-256): A widely supported choice that balances strong security with excellent library compatibility.
  • ES256 (ECDSA with SHA-256): Offers similar security to RS256 but with smaller key sizes and faster performance.
  • HS256 (HMAC with SHA-256): Suitable for single-application setups, provided you manage keys securely and use strong secrets.

Algorithms to Avoid

Some algorithms are too risky for production use and should be avoided entirely:

  • "none" algorithm: Allows unsigned tokens, which is a glaring security hole.
  • HS256 with weak secrets: Secrets shorter than 256 bits or easily guessable passwords are vulnerable to brute force attacks.
  • Deprecated algorithms: Anything based on outdated methods like MD5 is no longer secure.

Key Length and Configuration

To maintain strong security, enforce minimum key lengths: at least 2048 bits for RSA (preferably 4096 bits) and 256 bits for ECDSA. Additionally, configure your JWT libraries to explicitly allow only specific algorithms. This prevents algorithm confusion attacks, where attackers manipulate the algorithm field in a JWT header to bypass security checks.

3. Set Short Expiration Times and Use Refresh Tokens

After choosing the right algorithm, the next step is deciding how long your tokens should remain valid. Think of JWT expiration times like temporary parking permits - the shorter the validity, the less harm an attacker can cause if they manage to steal one. This is especially important because JWTs are self-contained tokens, making them difficult to revoke once issued. By setting shorter expiration times, you pave the way for using refresh tokens, which help maintain both security and a smooth user experience.

The key principle here is straightforward: reduce the window of opportunity for attackers. If a JWT is intercepted, a short lifespan limits how long it can be used to impersonate a user or access sensitive resources. This aligns with the broader goal of minimising potential exposure to threats.

Finding the Right Balance

Striking the right balance between security and usability means tailoring token expiration times to your specific needs:

  • High-security applications: Tokens should expire in 5–15 minutes.
  • Standard applications: Expiration times can range from 1–24 hours.
  • Low-risk scenarios: Longer expiration times can be reserved for refresh tokens only.

"Because of that, you should use as short an expiration time for your tokens as possible. A best practice is to set your JWT expiration to minutes or hours at maximum. You should avoid issuing access tokens valid for days or months." - Curity

Implementing the Refresh Token Pattern

Short expiration times work hand-in-hand with the refresh token pattern. This approach allows you to maintain security while ensuring users don’t have to log in repeatedly. It works like this: issue a short-lived access token alongside a longer-lived refresh token. The access token handles regular API requests, while the refresh token is securely stored and only used to get a new access token when the old one expires.

If your application encounters a 401 Unauthorized response due to an expired access token, it can use the refresh token to request a new access token without requiring the user to log in again.

Secure Storage and Implementation

Proper storage of refresh tokens is critical. Use HTTP-only cookies or encrypted local storage to protect them from cross-site scripting (XSS) attacks. Avoid storing refresh tokens in plain text or in locations that are easily accessible.

Equally important is token invalidation. When a user logs out, both the access and refresh tokens should be invalidated to prevent any misuse after the session ends.

Handling Time-Based Claims

When implementing expiration checks, account for possible clock differences between servers. Allow up to 30 seconds of clock skew when verifying time-based claims like exp (expiration), nbf (not before), and iat (issued at). This ensures that valid tokens aren’t mistakenly rejected due to minor time discrepancies.

Your system should automatically reject expired tokens with a 401 Unauthorized response. This prompts the client application to use its refresh token to obtain a new access token, maintaining a seamless user experience while keeping security intact.

4. Secure Storage and Transmission of Tokens

When it comes to safeguarding your API, the way you store tokens is just as important as how you transport them. Client-side token storage plays a critical role in your app's security. Each storage method comes with its own set of trade-offs between ease of use and protection. A poor storage choice can leave your users vulnerable to token theft, even if other security measures are in place.

Client-Side Storage Options

Local Storage is the simplest option, but it comes with significant risks. Any JavaScript code running on your page, including malicious scripts from XSS attacks, can access tokens stored here. Since local storage is persistent, the exposure risk increases if the token is compromised.

Session Storage offers slightly better security by clearing tokens automatically when the browser tab is closed. However, it still shares the same vulnerability as local storage - JavaScript can access the stored tokens, making it suitable only for applications with minimal security demands.

HTTP-Only Cookies are the most secure option for client-side storage. These cookies are inaccessible to JavaScript, shielding tokens from XSS attacks. Additionally, the browser automatically includes them in requests to your domain, simplifying token transmission. However, to guard against CSRF attacks, you’ll need to configure proper same-site attributes and use CSRF tokens.

Transmission Security Requirements

Always use HTTPS for transmitting JWTs, as outlined in Section 1. When sending tokens, include them in the Authorization header using the Bearer scheme: Authorization: Bearer <token>. This approach keeps tokens out of URL parameters, reducing the risk of exposure in server logs, browser history, or referrer headers.

Mobile Application Considerations

Mobile apps require a different approach to token storage. On iOS, Keychain Services, and on Android, the Android Keystore, provide hardware-backed security for sensitive data. These systems encrypt stored tokens and can even require biometric authentication for access.

Where possible, avoid storing long-lived tokens on mobile devices. Instead, use the refresh token pattern discussed earlier. Store short-lived access tokens in memory and secure refresh tokens in the device's secure storage. Pair this with properly configured transmission headers for added protection.

Token Transmission Headers

To secure token transmission, configure your application to include specific security headers:

  • Strict-Transport-Security: Enforces HTTPS connections and blocks protocol downgrade attacks.
  • Content-Security-Policy: Reduces XSS risks that could expose stored tokens.

If you’re using cookies for token storage, set appropriate security attributes:

  • Secure: Ensures cookies are sent only over HTTPS.
  • HttpOnly: Blocks JavaScript access to cookies.
  • SameSite=Strict: Protects against CSRF by limiting cross-site cookie sharing.

Memory-Based Storage

For applications requiring the highest level of security, consider storing tokens only in JavaScript memory variables. This method eliminates persistent storage, reducing the risk of token theft. However, it comes with the trade-off of requiring users to re-authenticate more frequently since tokens are not retained across page reloads. Pair this with short token expiration times and seamless refresh token mechanisms for the best results.

While memory-based storage prioritises security over convenience, it’s a viable option for scenarios where security is paramount, even if it adds some friction to the user experience.

5. Limit JWT Payload Content

When it comes to securing your application, keeping the JWT payload lean is a key practice. By including only the necessary authentication and authorisation data, you can improve both security and performance.

Why Minimal Payloads Matter

JWTs are sent with every API request, making them a tempting target for attackers. The more data you cram into the payload, the bigger the risk if the token is compromised. Sensitive information such as passwords, PINs, or detailed user profiles should never be part of a JWT payload. A streamlined payload not only reduces potential security risks but also improves system efficiency.

Essential vs. Non-Essential Claims

The focus of your JWT payload should be on identity and permissions. Essential claims might include a user ID, their role, and permissions required for authorisation. Here's an example of a minimal payload:

{
  "sub": "user123",
  "role": "admin",
  "permissions": ["read", "write"],
  "exp": 1640995200
}

Avoid adding details that change frequently or are unrelated to access control. Items like user preferences, profile pictures, or temporary session data should remain in your database. Use the user ID from the token to fetch this data when needed, instead of embedding it in the JWT.

Security Implications of Excessive Data

JWT payloads are base64-encoded, not encrypted, meaning anyone with the token can view its contents. If your payload includes sensitive details such as email addresses, phone numbers, or internal identifiers, a compromised token could lead to privacy breaches. For UK-based applications, this could also raise serious GDPR compliance issues.

Performance Impact of Large Tokens

Large tokens can bog down your system. If a token grows to 2-3 KB due to excessive data, the impact on network bandwidth and system latency can be significant, especially when handling thousands of API requests per minute. Keeping tokens under 1 KB is a good rule of thumb to avoid unnecessary overhead.

Proper Payload Design Principles

Design your JWT payload with a "need-to-know" approach. Only include claims that are absolutely necessary for immediate authorisation. If more data is required, use the user ID in the token to retrieve it through your API.

To keep payloads small, use short and meaningful claim names. For example:

  • Replace "user_permissions" with "perms".
  • Use "org_id" instead of "organisation_identifier".

Additionally, consider issuing different tokens for different access levels. For example, a regular user might get a basic token with minimal claims, while an admin token could include additional claims only when needed. This avoids sending unnecessary data to users who don’t require it.

Handling Dynamic Data

For data that changes frequently, separate static claims from dynamic information. Items like account balances, real-time statuses, or user preferences should stay in your database. Use the JWT to identify the user and fetch the latest data via API calls.

This separation simplifies token management. For instance, if user permissions change, you don’t need to revoke and reissue tokens immediately. The updated permissions will naturally take effect when the token expires and is refreshed.

Since JWTs are stateless by design, keeping their payloads minimal ensures your system remains scalable, secure, and efficient. By following these principles, you can deliver a smooth and reliable experience for your users while maintaining robust security.

6. Validate JWT Signatures and Claims on Every Request

Validating JSON Web Tokens (JWTs) is your first line of defence against tampering. Every API request that carries a JWT must undergo thorough validation, no matter how trustworthy the source might seem. This process sets the foundation for all other security checks.

The Importance of Signature Verification

The JWT signature is key to ensuring the token's integrity. It confirms that the token hasn't been altered since it was issued. Never trust a JWT without verifying its signature first.

Tokens with invalid signatures should be rejected immediately, before any further processing. To achieve this, your server must use the same algorithm and secret key (or public key for asymmetric algorithms) that was used to sign the token. If the signature fails verification, there’s no need to check claims or permissions - stop there.

Validating Claims: A Non-Negotiable Step

Once the signature is verified, it’s time to validate the token’s claims. Temporal claims like exp (expiration), nbf (not before), and iat (issued at) must be checked against the server’s current time, allowing for a slight time skew (30–60 seconds). If a token is even a second past its expiration, it should be rejected.

Pay close attention to the aud (audience) claim. This claim must match your API's identifier exactly. If your API serves multiple applications, assign each one a distinct audience identifier. For example, a token meant for your mobile app shouldn't work with your web dashboard, even if both rely on the same authentication service.

Why Validation Must Happen Server-Side

All critical JWT validation should take place on the server. Client-side checks can be bypassed by attackers, so server-side validation is the only reliable safeguard.

Make it a habit to validate JWTs before performing any actions, such as looking up user data or checking permissions. A consistent validation routine ensures that no step is skipped. To streamline this process, consider using middleware to handle JWT verification for all protected endpoints. This approach not only reduces the risk of oversight but also ensures uniform security across your API.

Common Validation Pitfalls

Some mistakes in JWT validation can leave your system vulnerable:

  • Allowing the none algorithm: Attackers can exploit this by removing the signature entirely. Similarly, they might alter an RS256 token to claim it uses HS256, then sign it with the public key as if it were a symmetric secret. Always verify tokens using the expected algorithm.
  • Ignoring custom claims: If your application relies on claims like role or permissions, ensure these are validated against your system's authorisation rules. A valid signature doesn’t automatically mean the claims are trustworthy.

Balancing Security and Performance

Validating JWTs does add some computational load, but security always takes precedence over performance. That said, there are ways to optimise without cutting corners.

  • Cache signing keys, especially for asymmetric algorithms that require fetching public keys. This reduces the need for repeated lookups.
  • Gracefully handle key rotation by allowing tokens signed with recently expired keys to pass during a brief transition period.
  • Optimise checks by verifying expiration (exp) before performing signature validation.

Handling Validation Failures

When validation fails, keep error messages minimal to avoid giving attackers insight into your system. A simple "Invalid token" message is enough, regardless of the specific reason - whether it’s an expired token, an invalid signature, or missing claims.

Log failure details securely for troubleshooting, but avoid exposing sensitive token data in logs. Use appropriate HTTP status codes to respond to validation issues: 401 Unauthorized for invalid tokens and 403 Forbidden for valid tokens with insufficient permissions. This consistency helps legitimate clients resolve issues while keeping system details hidden from attackers.

Finally, remember that validation isn’t a one-time check. You must validate the token on every single request. Even if it passed validation moments ago, check it again. JWTs are stateless, and this stateless nature demands constant validation to maintain security.

sbb-itb-1051aa0

7. Implement Token Revocation Mechanisms

After ensuring robust JWT signature and claims validation, managing token revocation becomes a critical step in securing your API. The stateless nature of JWTs, while efficient, poses challenges when it comes to revoking tokens. Once issued, a compromised JWT remains usable until it naturally expires, which could lead to unauthorised access.

The Stateless Challenge

JWTs are designed to be self-contained and stateless, meaning your server doesn't need to store token information or perform lookups. While this design supports scalability, it also means you can't easily revoke a token before its expiration. For instance, if an employee leaves your organisation or a user's device is stolen, their token remains valid until it expires - potentially leaving a security gap for hours or even days.

This trade-off between scalability and control is one of the key challenges of using JWTs.

Implementing Token Blacklisting

A practical solution to this issue is maintaining a blacklist of revoked tokens. When a token needs to be invalidated, its unique identifier (found in the jti claim) is added to a blacklist stored in a database or cache. During token validation, the system checks this blacklist to ensure the token hasn’t been revoked.

For efficiency, store the token’s jti value along with its expiration time. This allows you to automatically clean up expired entries - there’s no need to retain blacklisted tokens that have already expired. Tools like Redis are particularly effective here, as they support automatic expiration for stored entries.

To optimise performance, structure blacklist queries around the token’s jti as the primary key. You can also keep recent tokens in memory for faster access, while older tokens are stored in a database. This approach works well alongside short-lived tokens, which we’ll explore next.

Short-Lived Tokens with Refresh Mechanisms

Instead of fighting the stateless nature of JWTs, you can embrace it by issuing short-lived access tokens, typically valid for 15 to 30 minutes. These tokens are paired with refresh tokens, which are securely stored on the client.

This setup reduces the risk window significantly. Even if an access token is compromised, it becomes invalid within minutes. The refresh token, on the other hand, serves as the primary target for revocation. If access needs to be revoked, you blacklist the refresh token, preventing the issuance of new access tokens.

Handling Emergency Revocation

In urgent situations, such as when a user’s account is compromised or a device is reported stolen, you may need to revoke all of a user’s tokens immediately. To achieve this, implement a user-level revocation mechanism.

Store a tokens_invalid_before timestamp in the user’s record. During token validation, compare the token’s iat (issued at) claim with this timestamp. Any token issued before the timestamp is automatically rejected, regardless of its expiration time. This method allows you to invalidate all of a user’s tokens with a single database update.

Balancing Performance and Security

Adding token revocation mechanisms introduces some overhead to a stateless JWT system, as each token validation now requires additional checks. However, this trade-off is necessary to maintain security.

To minimise performance hits, utilise fast storage solutions like Redis for blacklists and cache user revocation timestamps to reduce database queries. For less critical operations, you might consider allowing a slight delay in revocation enforcement, while ensuring immediate action for high-security endpoints.

Practical Implementation Considerations

For token revocation to be effective, all API servers must access a shared revocation store. This ensures consistent enforcement across the system.

Plan for potential issues, such as network failures or cache unavailability, by rejecting tokens if revocation data cannot be verified. Implement monitoring systems to alert you of any failures in the revocation process.

Finally, remember that token revocation only works if it’s enforced everywhere your tokens are accepted. A single service that skips revocation checks can become a security loophole. Make revocation verification a mandatory part of your JWT validation middleware to ensure consistent protection across your API.

8. Protect Against Cross-Site Scripting (XSS) and Cross-Site Request Forgery (CSRF)

After covering secure token transmission and storage, let's dive into defending against two major threats to web applications: Cross-Site Scripting (XSS) and Cross-Site Request Forgery (CSRF). These attacks exploit the trust between users and web applications, potentially leading to stolen tokens or unauthorised actions. Here's how you can tackle these threats head-on.

Understanding XSS Attacks on JWTs

XSS attacks occur when malicious scripts are injected into web pages, targeting unsuspecting users. If your JWTs are stored in browser localStorage or sessionStorage, they can be vulnerable. A successful XSS attack can execute JavaScript to steal tokens and send them to an attacker's server.

To minimise this risk, store tokens securely. Instead of browser storage, use httpOnly cookies. These cookies are inaccessible to JavaScript, making them immune to XSS attacks targeting client-side storage.

When setting up cookies for JWTs, ensure the following:

  • Use the Secure flag so tokens are only sent over HTTPS.
  • Set the SameSite attribute to "Strict" or "Lax" to prevent the cookie from being sent with cross-site requests. This adds an extra layer of CSRF protection.

Implementing a Content Security Policy (CSP)

A well-configured Content Security Policy (CSP) is one of the most effective defences against XSS. CSP headers instruct browsers on which sources of content are trustworthy, blocking malicious scripts.

Start with script-src 'self' to restrict scripts to your domain. Avoid directives like 'unsafe-inline' and 'unsafe-eval' unless absolutely necessary. If inline scripts are unavoidable, use nonces or hashes to whitelist specific scripts while maintaining security.

Here’s an example of a CSP header configuration:
Content-Security-Policy: script-src 'self' 'nonce-abc123'; object-src 'none'; base-uri 'self';
This setup limits scripts to your domain or those with the specified nonce, blocks untrusted embeds, and prevents base tag modifications.

CSRF Protection Strategies

CSRF attacks trick users into performing actions they didn’t intend, often by exploiting authenticated sessions. Even with httpOnly cookies, CSRF attacks can manipulate these sessions to make unauthorised API calls.

To counteract CSRF:

  • Use the double-submit cookie pattern. Send a random CSRF token both as a cookie and in a custom header (e.g., X-CSRF-Token) with API requests. Since cross-site requests cannot access the cookie to replicate the header, this method blocks CSRF attempts.
  • If you use the Authorization header to send JWTs, CSRF protection is inherently stronger, as cross-site requests cannot include custom headers. However, for cookie-based token transmission, explicit CSRF protection is essential.

Token Storage Best Practices

How you store tokens plays a crucial role in mitigating XSS and CSRF risks. Here’s a quick breakdown of storage options:

  • HttpOnly cookies: These are highly secure against XSS but require robust CSRF protection. They’re convenient as they’re automatically included in requests.
  • Memory storage: Storing tokens in JavaScript variables offers protection against both XSS and CSRF, but tokens are lost on page refresh or navigation. This method works well with short-lived tokens and reliable refresh mechanisms.

Additional Security Headers

Beyond CSP, other HTTP headers can strengthen your defences against XSS and CSRF:

  • X-Frame-Options: Prevents clickjacking by blocking your site from being embedded in iframes.
  • X-Content-Type-Options: Set this to "nosniff" to stop browsers from interpreting files as a different MIME type, reducing script execution risks.
  • X-XSS-Protection: For older browsers, use "1; mode=block" to block detected XSS attacks. Modern browsers rely more on CSP for this purpose.

Input Validation and Output Encoding

To further protect against XSS, validate and encode all user input and output. This starts with the principle: never trust user input. Validate data on both the client and server sides. For database queries, use parameterised queries instead of string concatenation to avoid SQL injection risks.

When displaying user-generated content:

  • Use HTML encoding for content displayed in HTML contexts.
  • Apply JavaScript encoding for data inserted into JavaScript.
  • URL-encode parameters used in URLs.

Modern frameworks often provide built-in encoding functions to simplify these tasks. Additionally, use allowlists (approved inputs) rather than blocklists for more predictable security.

Monitoring and Detection

Stay vigilant by monitoring for XSS and CSRF attempts. Keep an eye on unusual token usage patterns, like tokens being accessed from unexpected locations or used rapidly from different IP addresses.

Deploy a Web Application Firewall (WAF) to detect and block common XSS and CSRF attack patterns. Configure your WAF to monitor for suspicious script injections and cross-site requests.

Finally, set up alerts for CSP violations. Modern browsers can report these violations to a designated endpoint, letting you respond quickly to potential threats in real-time.

9. Regularly Review and Update JWT Security Practices

Maintaining robust security for JSON Web Tokens (JWTs) requires continuous effort. With vulnerabilities evolving over time, regular reviews are essential to ensure your JWT implementation remains secure and resilient.

Establishing a Security Review Routine

Set up a structured schedule for security reviews. Aim for quarterly audits to examine token configurations, storage methods, and validation processes. Complement these with monthly log monitoring and weekly checks on token expiration settings and security headers.

Keeping Up with JWT Security Standards

Stay informed about the latest JWT standards and updates by following security advisories from OWASP and IETF. Industry conferences and expert insights are also valuable resources for understanding emerging threats. Regular updates to your practices ensure that your validation and storage methods align with current recommendations.

Monitoring Vulnerabilities and Applying Patches

Automate vulnerability scans for your JWT libraries using tools like npm audit or OWASP Dependency-Check. Establish a clear process for applying security patches promptly, especially in response to critical vulnerabilities.

Incorporating Security and Penetration Testing

Conduct JWT-specific penetration tests and integrate automated security tests into your CI pipeline. These tests can help identify issues like algorithm confusion, timing attacks, or improper token invalidation.

Enhancing Logging and Monitoring

Track JWT metrics closely. Set up alerts for unusual behaviours, such as rapid token generation, unexpected usage from different geographic locations, or repeated signature validation failures - these can indicate potential attacks.

Documentation and Team Education

Clearly document your JWT security policies and procedures. Provide your team with annual training sessions to stay updated on the latest best practices and threat mitigation techniques.

Leveraging Third-Party Security Assessments

Bring in external security experts periodically to conduct in-depth reviews of your codebase and architecture. These assessments should include JWT-specific penetration tests to uncover vulnerabilities you might have missed.

Preparing for Incident Response

Develop a detailed incident response plan tailored to JWT-related breaches. This should include steps for mass token revocation, emergency algorithm updates, and clear communication strategies for notifying affected users.

Addressing Legacy Systems

If you’re working with older JWT implementations, consider migration plans or adding protective measures. Legacy systems may lack modern security features, making them more vulnerable to attacks.

Comparison Table

Choosing the right JWT storage method requires balancing security, functionality, and user experience. These trade-offs are crucial for implementing secure JWT practices effectively.

Below is a comparison of the four main JWT storage methods, with considerations tailored for UK-based applications:

Storage Method Capacity Persistence XSS Vulnerability CSRF Vulnerability Server Access Best Use Case
localStorage 5–10MB Survives browser restarts High – direct JS access None Client-side only Long-term storage of non-sensitive data
sessionStorage 5MB Cleared on tab close High – direct JS access None Client-side only Temporary session data
Secure Cookies 4KB Configurable expiration Moderate – HttpOnly flag High (mitigated by SameSite) Automatic inclusion Authentication tokens with server validation
In-Memory Storage Unrestricted Lost on page refresh Moderate – harder to access None Client-side only Short-lived access tokens

Security Strengths and Weaknesses

Each storage method has its own security trade-offs.

  • localStorage offers generous capacity but is highly vulnerable to XSS attacks due to its direct JavaScript accessibility. Its persistence across browser sessions adds to the risk.
  • sessionStorage provides automatic cleanup when the browser tab closes, but like localStorage, it also remains exposed to XSS attacks since JavaScript can access it directly.
  • Secure Cookies offer a safer alternative when configured correctly. The HttpOnly flag prevents JavaScript access, significantly reducing XSS risks. Combined with Secure and SameSite attributes, cookies also mitigate CSRF risks. However, their 4KB size limit necessitates efficient payloads. Their automatic inclusion in HTTP requests makes them an excellent choice for server-validated authentication tokens.
  • In-Memory Storage is ideal for temporary token storage. Tokens stored this way disappear when the page refreshes, limiting the exposure window. However, sophisticated XSS attacks could still compromise these tokens.

UK Regulatory Considerations

The choice of JWT storage is not just a technical decision; it also has regulatory implications under UK GDPR and related data protection laws. Organisations must ensure robust security measures to protect personal data. Cookies, for instance, often require explicit consent notices, while localStorage and sessionStorage may fall under legitimate interest provisions, depending on their use.

A common approach for modern applications is to combine methods: using in-memory storage for short-lived access tokens and secure, HttpOnly cookies for refresh tokens. This strategy minimises risk while maintaining a smooth user experience.

For UK financial services, particularly those regulated by the FCA, secure cookies with strong security headers provide a reliable option. Their automatic inclusion in HTTP requests and built-in safeguards align with regulatory demands for secure authentication.

Antler Digital, experts in secure and scalable API solutions, can help integrate these best practices into your API strategy. Their guidance ensures your application meets both security and UK regulatory standards.

Conclusion

Following these nine JWT security best practices isn’t just a technical box to tick - it’s a necessity in today’s threat-heavy digital environment. Each step adds a protective layer, from ensuring secure HTTPS transmission and using strong algorithms to proper token storage and routine security reviews.

The risks are particularly severe for industries under strict regulations. For example, UK-regulated businesses and healthcare organisations face hefty fines for security lapses. A single compromised JWT could result in unauthorised access, data breaches, and significant reputational damage.

For companies utilising AI integrations and automated workflows, JWT security becomes even more critical. These systems often process sensitive operational data and make decisions based on user roles. A compromised token in such an environment could lead to unauthorised actions, data tampering, or the exposure of proprietary algorithms.

This highlights the importance of continuously assessing and updating your security measures. By combining the layered security strategies outlined above with regular reviews, you can ensure your JWT implementation evolves alongside emerging threats. Ongoing monitoring, timely vulnerability fixes, and frequent security testing are essential to keeping your defences effective.

The real challenge, however, lies in consistently applying these practices across your entire application ecosystem while balancing user experience and development speed.

To help meet these challenges, Antler Digital offers expertise in building secure, scalable web applications that integrate these JWT best practices from the start. With experience in FinTech, SaaS, and AI integrations, they ensure your APIs are not only secure but also compliant with regulatory standards. Whether you’re developing new platforms or fortifying existing ones, their comprehensive approach ensures robust JWT security without sacrificing functionality or usability.

Maintaining security is an ongoing process that requires expertise, vigilance, and the right technical partners. By embedding these practices into your operations, you can ensure your API security remains as strong and scalable as the systems it supports.

FAQs

Why is it important to use HTTPS when transmitting JWTs, and what risks arise if you don’t?

When transmitting JWTs, using HTTPS is non-negotiable. HTTPS encrypts the data, shielding it from prying eyes and safeguarding it against threats like man-in-the-middle attacks or eavesdropping. Without this layer of protection, JWTs are vulnerable, potentially allowing unauthorised access and causing serious security issues.

In the UK, handling sensitive data - such as user credentials and tokens - securely isn't just good practice; it's a legal obligation under data protection laws. Neglecting HTTPS could lead to compromised security, eroded user trust, and even financial or legal penalties.

What’s the best way to revoke tokens in a stateless JWT system?

Revoking tokens in a stateless JWT system can be tricky because of their self-contained design, but there are strategies to make it work. One common approach is using a server-side blacklist. This involves storing details like the token's unique identifier (e.g., the jti claim) or user ID and checking against this list whenever a token is validated.

Another option is to handle revocation by invalidating refresh tokens or session tokens linked to a user. This way, any future access tokens generated from these sessions are automatically rendered invalid. While this does require some server-side management, it’s an effective way to manage token revocation even in stateless systems.

What are the best practices for securely storing JWTs in mobile apps?

To keep JWTs safe in mobile apps, it's best to rely on secure, platform-specific storage solutions like Keychain on iOS or the Android Keystore. These systems are designed to encrypt sensitive data, making it harder for unauthorised users to access tokens.

Here are some additional steps to reinforce security:

  • Opt for short-lived tokens to limit potential damage if a token is ever exposed.
  • Add an extra layer of protection by encrypting JWTs before saving them.
  • Make sure all data exchanges happen over HTTPS to safeguard information during transmission.

By implementing these strategies together, you can significantly tighten the security of your mobile app and protect user data more effectively.

if (valuable) then share();

Lets grow your business together

At Antler Digital, we believe that collaboration and communication are the keys to a successful partnership. Our small, dedicated team is passionate about designing and building web applications that exceed our clients' expectations. We take pride in our ability to create modern, scalable solutions that help businesses of all sizes achieve their digital goals.

If you're looking for a partner who will work closely with you to develop a customized web application that meets your unique needs, look no further. From handling the project directly, to fitting in with an existing team, we're here to help.

How far could your business soar if we took care of the tech?

Copyright 2025 Antler Digital