TL;DR: JWTs are widely used for application authentication, but insecure browser storage can expose tokens to XSS, CSRF, and extension-based theft, according to Descope’s developer guide. The core issue is not token format but where the token lives, because storage choice directly changes the compromise path and revocation options.
NHIMG editorial — based on content published by Descope: The Developer’s Guide to JWT Storage
By the numbers:
- Only 20% have formal processes for offboarding and revoking API keys, and even fewer have procedures for rotating them.
- 71% of NHIs are not rotated within recommended time frames, increasing the risk of compromise over time.
- 96% of organisations store secrets outside of secrets managers in vulnerable locations including code, config files, and CI/CD tools.
Questions worth separating out
Q: How should security teams store JWTs in browser applications?
A: Prefer storage patterns that reduce script readability and replay risk.
Q: Why do JWT storage decisions matter for identity security?
A: Because a JWT is a bearer credential, whoever holds it can often use it.
Q: What breaks when JWTs are stored in local storage or session storage?
A: The main failure is script readability.
Practitioner guidance
- Move sensitive JWTs out of directly script-readable storage Prefer HttpOnly cookies or a backend-for-frontend pattern when a browser app must hold an access token, and reserve local storage only for low-risk scenarios with strong XSS hardening.
- Pair cookie sessions with anti-CSRF controls If you use cookies for JWT transport, enforce HttpOnly, Secure, and SameSite settings and add an explicit anti-CSRF mechanism for state-changing requests.
- Shorten token lifetime and design revocation paths Use short-lived access tokens, defined refresh logic, and server-side revocation or blacklist handling so a stolen JWT cannot remain useful for long.
What's in the full article
Descope's full blog post covers the implementation detail this post intentionally leaves at the architectural level:
- Step-by-step code examples for storing, reading, and clearing JWTs in local storage, session storage, cookies, and memory.
- Browser-specific implementation notes for HttpOnly, Secure, SameSite, and refresh handling across common web application patterns.
- Mobile storage guidance for Android Keystore, SharedPreferences, and iOS Keychain when JWTs must live on device.
- Troubleshooting tips for cross-domain cookie behaviour and backend-for-frontend session design.
👉 Read Descope's guide to secure JWT storage methods for web apps →
JWT storage methods: are your browser controls enough?
Explore further
View Full Forum → | NHI Foundation Course → | Our Services →
JWT storage is really bearer-credential governance. The article treats storage as an implementation choice, but the identity issue is whether the token can be extracted, replayed, and reused outside the intended session boundary. That is the same governance question we ask for NHIs: where does the secret live, who can read it, and how quickly can it be revoked. Practitioners should classify browser-held JWTs as reusable credentials and govern them accordingly.
A few things that frame the scale:
- Only 20% have formal processes for offboarding and revoking API keys, and even fewer have procedures for rotating them, according to the Ultimate Guide to NHIs.
- 91.6% of secrets remain valid five days after the targeted organisation is notified, showing how slowly credential exposure is removed in practice.
A question worth separating out:
Q: What should teams do when JWTs must work across multiple domains or mobile apps?
A: Use a backend-for-frontend pattern for web apps that span services, or rely on platform secure storage and short-lived tokens for mobile. That keeps token handling closer to the server or device security boundary and avoids forcing browser storage patterns into environments they do not fit well.
👉 Read our full editorial: JWT storage choices expose the browser attack surface