DEV Community

Thai Pangsakulyanont
Thai Pangsakulyanont

Posted on • Updated on • Originally published at

A survey of JWT storage locations in client-side app SDKs

The question about where to store JWTs (and access tokens in general) is a common one where there seems to be no consensus among developers.1

Some believe that JWTs should never ever be stored in localStorage, while others believe that it’s okay to store them there. Each side has their own reasonings and explanations for their beliefs. It has been discussed at length, and in my opinion, to the point of unproductivity.2

Rather than adding to this never-ending debate, let’s instead take a look at popular SDKs to see how they are helping single page applications (SPA) store their JWTs. Here we go!


Image description

  • For SPAs, Auth0 does not store a JWT in client-side storage at all.

  • Instead, Auth0 SDK embeds a hidden <iframe> which performs the Authorization Code Flow with Proof Key for Code Exchange (PKCE) in conjection with Silent Authentication. This flow is performed every time the SPA is loaded, so the JWT is not persisted at any storage location. Additionally, token requests are performed in Web Workers, providing additional layer of security.

Image description

AWS Amplify

Image description

  • ID tokens, access tokens, and refresh tokens are stored in localStorage

  • They are all JWTs. You know because they start with eyJ. They are RS256 signed.

Firebase Auth

Image description

  • Firebase Auth stores the access token and refresh tokens in IndexedDB by default.

  • The accessToken is a RS256-signed JWT. It also functions as an ID token (and are referred to as such in the documentation). Using RS256 JWT is convenient because third-party apps can verify the ID token using Firebase’s public keys without having to share any secret keys.

  • Meanwhile, the refresh token is an opaque string.


Image description

  • Supabase stores the access token and refresh token in localStorage.

  • The access token is a HS256-signed JWT, while the refresh token is an opaque string.


In conclusion, different auth SDKs implemented different default behaviors for storing tokens.

It is important to consider the context around choices made by these SDKs. Just because a few popular SDKs store tokens in localStorage doesn’t automatically mean that doing the same in our custom implementations will give us a secure authentication scheme; we also have to look at how these SDKs help developers protect the tokens from misuse.

If you have more examples to add, feel free to comment!

  1. Please ignore my ramblings.

    Whenever the topic of token storage is tangentially touched on, it seems someone has to proclaim “never store JWTs in localStorage” and derail the conversation. Happens so frequently, and it is fascinating to see the length people will sometimes go to to prove their point. When I pointed out about our defenses against XSS and untrusted assets, I got a reply “but the user may install a malicious software that can read storage. Here I created an extension that reads the localStorage of the website. See? localStorage bad.”


Top comments (0)