Update 5/12/2016: Building a Java application? JJWT is a Java library providing end-to-end JWT creation and verification, developed by our very own Les Hazlewood. Forever free and open-source (Apache License, Version 2.0), JJWT is simple to use and understand. It was designed with a builder-focused fluent interface hiding most of its complexity. We’d love to have you try it out, and let us know what you think! (And, if you’re a Node developer, check out NJWT!)

 

Stormpath has recently worked on token authentication features using JSON Web Tokens (JWT), and we have had many conversations about the security of these tokens and where to store them.

If you are curious about your options, this post is for you. We will cover the basics of JSON Web Tokens (JWT) vs. OAuth, token storage in cookies vs. HTML5 web storage (localStorage or sessionStorage), and basic security information about cross-site scripting (XSS) and cross-site request forgery (CSRF).

Let’s get started…

JSON Web Tokens (JWT): A Crash Course

The most implemented solutions for API authentication and authorization are the OAuth 2.0 and JWT specifications, which are fairly dense. Cliff’s Notes Time! Here’s what you need to know about JWT vs OAuth:

  • JWTs are a great authentication mechanism. They give you a structured and stateless way to declare a user and what they can access. They can be cryptographically signed and encrypted to prevent tampering on the client side.
  • JWTs are a great way to declare information about the token and authentication. You have a ton of freedom to decide what makes sense for your application because you are working with JSON.
  • The concept behind scopes is powerful yet incredibly simple: you have the freedom to design your own access control language because, again, you are working with JSON.

If you encounter a token in the wild, it looks like this:

This is a Base64 encoded string. If you break it apart you’ll actually find three separate sections:

The first section is a header that describes the token. The second section is a payload which contains the juicy bits, and the third section is a signature hash that can be used to verify the integrity of the token (if you have the secret key that was used to sign it).

When we magically decode the second section, the payload, we get this nice JSON object:

This is the payload of your token. It allows you to know the following:

  • Who this person is (sub, short for subject)
  • What this person can access with this token (scope)
  • When the token expires (exp)
  • Who issued the token (iss, short for issuer)

These declarations are called ‘claims’ because the token creator claims a set of assertions that can be used to ‘know’ things about the subject. Because the token is signed with a secret key, you can verify its signature and implicitly trust what is claimed.

Tokens are given to your users after they present some credentials, typically a username and password, but they can also provide API keys, or even tokens from another service. This is important because it is better to pass a token (that can expire, and have limited scope) to your API than a username and password. If the username and password are compromised in a man-in-the-middle attack, it is like giving an attacker keys to the castle.

Stormpath’s API Key Authentication Feature is an example of this. The idea is that you present your hard credentials once, and then get a token to use in place of the hard credentials.

The JSON Web Token (JWT) specification is quickly gaining traction. Recommended highly by Stormpath, it provides structure and security, but with the flexibility to modify it for your application. Here is a longer article on it: Use JWT the Right Way!

Where to Store Your JWTs

So now that you have a good understanding of what a JWT is, the next step is to figure out how to store these tokens. If you are building a web application, you have a couple of options:

  • HTML5 Web Storage (localStorage or sessionStorage)
  • Cookies

To compare these two, let’s say we have a fictitious AngularJS or single page app (SPA) called galaxies.com with a login route (/token) to authenticate users to return a JWT. To access the other APIs endpoints that serve your SPA, the client needs to pass a valid JWT.

The request that the single page app makes would resemble:

Your server’s response will vary based on whether you are using cookies or Web Storage. For comparison, let’s take a look at how you would do both.

JWT localStorage or sessionStorage (Web Storage)

Exchanging a username and password for a JWT to store it in browser storage (sessionStorage or localStorage) is rather simple. The response body would contain the JWT as an access token:

On the client side, you would store the token in HTML5 Web Storage (assuming that we have a success callback):

To pass the access token back to your protected APIs, you would use the HTTP Authorization Header and the Bearer scheme. The request that your SPA would make would resemble:

Exchanging a username and password for a JWT to store it in a cookie is simple as well. The response would use the Set-Cookie HTTP header:

To pass the access token back to your protected APIs on the same domain, the browser would automatically include the cookie value. The request to your protected API would resemble:

So, What’s the difference?

If you compare these approaches, both receive a JWT down to the browser. Both are stateless because all the information your API needs is in the JWT. Both are simple to pass back up to your protected APIs. The difference is in the medium.

JWT sessionStorage and localStorage Security

Web Storage (localStorage/sessionStorage) is accessible through JavaScript on the same domain. This means that any JavaScript running on your site will have access to web storage, and because of this can be vulnerable to cross-site scripting (XSS) attacks. XSS, in a nutshell, is a type of vulnerability where an attacker can inject JavaScript that will run on your page. Basic XSS attacks attempt to inject JavaScript through form inputs, where the attacker puts <script>alert('You are Hacked');</script> into a form to see if it is run by the browser and can be viewed by other users.

To prevent XSS, the common response is to escape and encode all untrusted data. But this is far from the full story. In 2015, modern web apps use JavaScript hosted on CDNs or outside infrastructure. Modern web apps include 3rd party JavaScript libraries for A/B testing, funnel/market analysis, and ads. We use package managers like Bower to import other peoples’ code into our apps.

What if only one of the scripts you use is compromised? Malicious JavaScript can be embedded on the page, and Web Storage is compromised. These types of XSS attacks can get everyone’s Web Storage that visits your site, without their knowledge. This is probably why a bunch of organizations advise not to store anything of value or trust any information in web storage. This includes session identifiers and tokens.

As a storage mechanism, Web Storage does not enforce any secure standards during transfer. Whoever reads Web Storage and uses it must do their due diligence to ensure they always send the JWT over HTTPS and never HTTP.

Cookies, when used with the HttpOnly cookie flag, are not accessible through JavaScript, and are immune to XSS. You can also set the Secure cookie flag to guarantee the cookie is only sent over HTTPS. This is one of the main reasons that cookies have been leveraged in the past to store tokens or session data. Modern developers are hesitant to use cookies because they traditionally required state to be stored on the server, thus breaking RESTful best practices. Cookies as a storage mechanism do not require state to be stored on the server if you are storing a JWT in the cookie. This is because the JWT encapsulates everything the server needs to serve the request.

However, cookies are vulnerable to a different type of attack: cross-site request forgery (CSRF). A CSRF attack is a type of attack that occurs when a malicious web site, email, or blog causes a user’s web browser to perform an unwanted action on a trusted site on which the user is currently authenticated. This is an exploit of how the browser handles cookies. A cookie can only be sent to the domains in which it is allowed. By default, this is the domain that originally set the cookie. The cookie will be sent for a request regardless of whether you are on galaxies.com or hahagonnahackyou.com.

CSRF works by attempting to lure you to hahagonnahackyou.com. That site will have either an img tag or JavaScript to emulate a form post to galaxies.com and attempt to hijack your session, if it is still valid, and modify your account.

For example:

Both would send the cookie for galaxies.com and could potentially cause an unauthorized state change. CSRF can be prevented by using synchronized token patterns. This sounds complicated, but all modern web frameworks have support for this.

For example, AngularJS has a solution to validate that the cookie is accessible by only your domain. Straight from AngularJS docs:

When performing XHR requests, the $http service reads a token from a cookie (by default, XSRF-TOKEN) and sets it as an HTTP header (X-XSRF-TOKEN). Since only JavaScript that runs on your domain can read the cookie, your server can be assured that the XHR came from JavaScript running on your domain.

You can make this CSRF protection stateless by including a xsrfToken JWT claim:

If you are using the Stormpath SDK for AngularJS, you get stateless CSRF protection with no development effort.

Leveraging your web app framework’s CSRF protection makes cookies rock solid for storing a JWT. CSRF can also be partially prevented by checking the HTTP Referer and Origin header from your API. CSRF attacks will have Referer and Origin headers that are unrelated to your application.

Even though they are more secure to store your JWT, cookies can cause some developer headaches, depending on if your applications require cross-domain access to work. Just be aware that cookies have additional properties (Domain/Path) that can be modified to allow you to specify where the cookie is allowed to be sent. Using AJAX, your server side can also notify browsers whether credentials (including Cookies) should be sent with requests with CORS.

Conclusion

JWTs are an awesome authentication mechanism. They give you a structured way to declare users and what they can access. They can be encrypted and signed for to prevent tampering on the client side, but the devil is in the details and where you store them. Stormpath recommends that you store your JWT in cookies for web applications, because of the additional security they provide, and the simplicity of protecting against CSRF with modern web frameworks. HTML5 Web Storage is vulnerable to XSS, has a larger attack surface area, and can impact all application users on a successful attack.

Questions or comments? We would love to hear them! Let me know if you have any questions in the discussion below or at [email protected] / @omgitstom.

Like what you see? to keep up with the latest releases.

  • How about storing the token as a cookie, but only accepting it as an authorization header?

    • I think this defeats the purpose of using an HttpOnly cookie, which is protecting against XSS, so the javascript can’t actually access it.

  • drawmindmap

    “You can make this CSRF protection stateless by including a xsrfToken JWT claim”

    So the xsrfToken is part of JWT, and JWT is stored in HttpOnly cookie, then js can not get it.

    My question is where is xsrfToken in Stormpath SDK?

    I think it should be store in readable session cookie like Angular.js said or web storage, but readable cookie and web storage is under XSS attack.

    So how to get both CSRF and XSS done?

  • This is pretty interesting, but I find the suggestion of storing the JWT as a cookie a bit odd, since it seems we’ve just come full circle and implemented cookie based sessions again albeit using JWT as the mechanism. I suppose this has the advantage of now being able to encode and verify some session state so the server doesn’t have to retrieve it, but this benefit seems pretty limited in the days of memcached.

    Also, if we’re bothering with JWT, I think we can probably assume we intend to expose an API to clients other than our own web browser client. If we are doing that then the argument that using cookies protects against compromised third party scripts is moot, since our non web clients are going to also be vulnerable to this.

    That being said, I do see some other advantages to using cookies. Such as being able to make a plain web request for a resource and be authenticated, such as downloading a PDF or other file directly and not via AJAX. (Though the new File API does allow us to do this on the client now too.) Since we can’t send an Authorization header with this sort of request.

    So I can see some reasons for sending a JWT as a cookie, while also supporting direct API based authentication via an Authorization header. However, I don’t agree with the opinion that we’ve accomplished a whole lot security wise by not using localStorage on the web browser.

    The reality is, if someone actually manages to compromise your 3rd party scripts or CDN I would argue you now have a way bigger problem than just a comprised JWT token.

    • Tom Abbott

      Thanks for the commentary! brought some nice perspective.

      Around full circle back to cookies – I really feel like the HTML5 spec dropped the ball on Web Storage and didn’t keep in consideration the security implications. If they wanted to have web storage replace cookies, they could have. Modern development is striving for stateless and RESTful API, and old-school session identifiers stored in the cookies require state on the server. What is interesting to me, is it seems like people have drawn the conclusion that cookies mean state on server. There is a clear division from the information and the medium though. You could still store a session identifier (information) in sessionStorage (medium) and require state on the server. Web Storage (medium) does not get you any closer to stateless, JWT does (information).

      Around non-browser clients – you are 100% correct. In that case, you worry less about XSS and CSRF, but worry about how the JWT is stored at rest on the client, particularly if you are thinking about mobile. I’ll probably cover this in another blog post though.

      Around using cookies AND the authorization header – nailed it again. I agree, for some APIs supporting both cookies and authorization header will be required.

      Around CDN/script compromises – I remember the jQuery CDN scare last year and the type of implications it brought to light. The valid sessions would probably be targeted first, but there are a lot of javascript exploits that could compromise the whole system.

      • What’s also interesting with JWT is that basically this is what Rails already does with encrypted/signed cookie based sessions, it just doesn’t use JSON. But essentially it’s an identical mechanism. There isn’t really much value at all in using JWT over just using sessions with a Rails based API outside of the fact that JWT is a standard (though I think that’s a pretty good benefit.)

        I might be interesting to implement JWT as an option for handling Rails sessions with support for both cookies and Authorization headers built in.

    • Dan

      > since it seems we’ve just come full circle and implemented cookie based sessions again albeit using JWT as the mechanism

      That’s true, but it also misses the point of JWT: it allows you to decouple your authentication server from any other backend service. The authentication server doesn’t even need to be yours, it could be owned by someone else. As long as you can validate their hash (eg public keys), you can trust that the JWT has been authenticated by some identity provider.

      It “looks like” cookie based sessions because that’s the mechanism in this context to deliver the JWT authentication guarantees. You could just as easily use JWT guarantees with a non-browser mechanism, eg a native app where you don’t need to worry about cookies and XSS and all browser fun. The scope of this article was just using JWT’s in the context of a web browser (which it was a great write-up of, thanks!)

  • Steve OConnor

    Good sensible writeup, thanks.

    Actual usage depends on the application though, so I suggest that there is no hard and fast rule on this one. All new technologies tend to find use cases well outside of their original intent.

    Cookies (as in your recommendation), infers some initial sort of validation from the user prior to issuing the cookie, using a standard web browser.

    Case in point – an app I am using with JWT at the moment …. allows a user to create a game scenario, and invite their friends to connect to the game and play. In this case, I generate a JWT for each new player, and email them an invite to the game, with the token embedded in the URL.

    This is all done in clear text over unencrypted email.

    I have no control over who gets invited, and no control over which IP address or devices they are connecting from. I dont need them to sign up to the game either … just follow the email invite, and they are up and running.

    The Token contains the initial invited email address, but is limited to 1 specific game on the server. This allows invited people to forward the email invite to others to join their “team”. (as the token includes the Team leader’s email addr)

    Once used, the token is stored in localStorage on the player’s device,
    and added to each JSON payload packet once they are playing that particular game instance.

    Using a token (rather than some inline get? parameter in the url) means that the average joe cannot easily forge the URL to try and access a different game.

    The above use case breaks all the security rules of token usage …. but is still a valid use case for me, as it allows access to the game to go viral. This is a desirable side effect from my point of view. More users = more potential income.

    Guess what I am saying is that there are always a tonne of different uses for any given technology …. some of which have little to do with the original intent of that technology.

    Half the fun of programming is taking components that do something well, and using them however you see fit, in order to solve a particular problem. JWT over email was a good fit in this case.

    Enjoy the coding !

  • Vanuan

    > Cookies, when used with the HttpOnly cookie flag, are not accessible through JavaScript, and are immune to XSS
    > reads a [CSRF protection] token from a cookie … only JavaScript that runs on your domain can read the cookie

    Huh?
    So, we can only protect either from XSS or CSRF, not both?

    • Vanuan

      Got it. I assumes that it is impossible to orchestrate both XSS and CSRF attack simultaneously.
      So it relies on two parts: xss-protected token and additional token, also stored in cookie. Wait… How exactly does the second token protect from CSRF since it’s also stored in cookies?

      • Vanuan

        Ok, got it again. The crucial part is that server should rely on both cookies and headers as a method of authentication.
        First part is protected from xss, but susceptible to csrf, second part is protected from csrf, but susceptible to xss.

      • Juan Carlos Martínez

        Correct.

        As some commenter posted above, you could still be hacked.

        CSRF to get the cookies
        XSS to get the xsrf-token

        It would be a laborious hack though.

  • GaryH

    Hi, I really like the idea of using an httponly cookie to store the token and the x-xsrf cookie being reflected in the header.

    The only challenge I have is if I want to use some of the token information on the client side to allow access to some hidden menus, display the logon name, or just to display the logon status.

    I also don’t want to generate a copy of most of the token info an pass it in the x-xsrf cookie (just feels inelegant).

    I’ve been thinking about generating one token but sending it’s header and body in the x-xsrf cookie, and the signature hash in the httponly cookie. I still need to check both when they are reflected back to the server but I need to do that anyway.

    Any thoughts?

  • If you add xsrfToken in jwt itself and store this jwt in cookies, how this would protect from csrf?
    I’m not getting the idea here, can you please clarify. If somebody from evildomain.com can execute POST [email protected]&[email protected] and xsrfToken already included in jwt which stored in cookies, then xsrf wouldn’t work.

    • Tom Abbott

      The idea here is that only Javascript from your domain can read the XSRF token and add it to the HTTP Header. This is validated against the XSRF token that is cryptographically signed in the JWT (cookie). To make a valid request, you need to be on your domain and have access to the cookie.

      • Oh, okay. This makes sense. I didn’t understood that you also have to supply same csrf token in headers.

      • ingben

        Why not simply checking the X-XSRF HTTP Header against the value of the XSRF cookie? If both match, the request is good to go. Still, you remain stateless on the server, but do not have to add the XSRF token to the JWT.

  • iainduncan

    Thanks for this article, like GaryH below, I’m wondering how best to make some of the information in the jwt accessible to the client when I send it in an http_only cookie. Would it be reasonable to send that information (just the user name & log in expiry really) in a second cookie that is not http_only and thus accessible to the client, so long as the second cookie is not used for any auth purposes?

    • Tom Abbott

      The JWT as a protected resource should not be used to store information that you request. I’ve seen some application expose an API that can get JSON that represents the information that your application requires. If you think about Google and their access tokens, you don’t parse the JWT to get the values, you call the API to get the information from the user. Hope this helps!

  • DenisPshenov

    This articles suggest that you shouldn’t use localStorage because you will be susceptible to XSS attacks. Instead it tells you to store your JWT token in HttpOnly cookie and CSRF token in a normal cookie so that you can protect yourself from XSS and CSRF.

    What this article doesn’t tell you is that you are still not protected against XSS because what the attacker can do is inject script that reads your CSRF cookie (which is not HttpOnly) and then make a request to one of your API endpoints using this CSRF token with JWT cookie being sent automatically.

    So in reality you are still susceptible to XSS, it’s just that attacker can’t steal you JWT token for later use, but he can still make requests on your users behalf using XSS.

    It would be nice if author of the article commented on this.

    • Tom Abbott

      Hi Dennis, the whole purpose of this article is to show how to protect the JWT. The attack you describe is making a request from the browser, the JWT itself is not compromised or accessed, the malicious script does not know the value of the JWT. This article is not an end all be all for deterring XSS and really depends on your application and the APIs it is exposing. At a minimum you should still sanitize inputs and use a Content-Security-Policy.

      • I think it’s ok to store access tokens in local storage because they are generally short lived. It is impractical to store access tokens in http only cookies as the client app usually needs to read them and append them to outgoing requests in the form of Authorization headers. Storing in memory only is impractical due to the access token being lost on a refresh, which is usually not the user experience people are after. The short livedness of the access token is what generally prevents attackers from doing serious harm, even if they obtain one.

        Refresh tokens are another story though. I wouldn’t store them anywhere else but a secure https only cookie limited to the token path (e.g. /api/oauth/token), because they are usually long lived and allow an attacker to obtain new access tokens at will if they have one.

      • docker0

        a refresh token only works if the access token has already expired and hasn’t already been used. So the attacker has to find the exact moment when both apply to successfully gain access. In that case, though, they would gain full control over the session.

    • Tomas

      @DenisPshenov:disqus What would you suggest then? What is the best way to protect my application from xss attacs?

  • novacreator

    What about storing the jwt token in a cookie and reading this cookie on each request with javascript and sending with the http headers. Could this be secure?

    • Yeah, that approach makes sense to me. But the thing is, as @DenisPshenov pointed out, if you are reading values out of a cookie using JS, that means you can’t set the Httponly flag on the cookie, so now any JS on your site can read it, thus making it the exact same security-level as storing something in localStorage.

      I’m trying to understand why they recommend adding the xsrfToken to the JWT. Doesn’t storing your JWT in the cookie and then extracting it out and placing the JWT in the HTTP header and authenticating the request based on the HTTP header accomplish the same thing as Angular’s X-XSRF-TOKEN? No other domain could make requests on a user’s behalf if you authenticate based on the JWT in the header, since other domains cannot extract the JWT from the cookie. I don’t understand the purpose of the xsrfToken in the JWT – perhaps its just an additional layer of defense – meaning that attackers would have to have a compromised script on your site and CSRF a user at the time. So they’d have to hit you in both ways to be able to pull of an attack.

      • Juan Carlos Martínez

        Hi Aaron,

        I am also starting in my secure web api investigations and so far this is what I understand:

        1 – The Api will set the token in a cookie for you (let’s call it the jwtcookie). It will be httponly and secure.

        This means javascript will not reach it, so a simple XSS attach will not get it (as it can reach localstorage)

        The client app needs to do nothing for this to work, the browser will include the jwtcookie automatically.

        The server will then look into the request cookies for the jwtcookie, extract the token and do its business.

        The cookie is just storing the token and it is not accessible to javascript.

        2 – This is nice and the XSS risk has been lowered but we need to worry about CSRF now.

        As seen in the sample above, CSRF will lure you into doing a request to another site and that will include your jwtcookie.

        This is bad.

        If we leave the service like that, the malicious site will use the cookie and send requests to it.

        We need to ensure that requests come only from your domain.

        3 – This is where the XSRF-TOKEN cookie comes in.

        When authenticating, the server will also create the xsrf-token cookie for you.

        It will NOT be httponly which means it is accessible to javascript.

        This is accessible only from your domain, which is what we want!

        So joining forces, cookies + javascript will be more secure.

        In the AngularJS example, it will automatically read the xsrf-token cookie and add the contents in the header under x-xsrf-token.

        4 – The server will validate both.

        The jwtcookie will have the session token infomration and the x-xsrf-token will make sure it came from the same domain.

        How do we validate? there are options …

        One simple way is to do a hash/salt of the jwt and make that your xsrf-token.

        On the server you do the same hash/salt when you read the jwtcookie and compate against the xsrf-token. The results should match.

        5 – Summary

        The Bearer token scheme is affected by xss (non validated form input or compromised client libraries). The first one is under our control, the second one is not.

        The token in cookie (httponly + secure) scheme solves the xss issues of the bearer token but is not exposed to CSRF

        The token in cookie (httponly + secure) + xsrf-token (non httponly) scheme solves the xss and csrf issues.

        6 – This is currently my understanding, if anybody has a clearer picture, please reply.

        7 – I want to implement this with c# web api … does anyone know of samples / code to do it?

      • xiefei

        The security level will be the same whether xsrf-token is (also) saved in jwt token or not. The article has claimed that the reason to put it in jwt token is to keep xsrf-token stateless. Without jwt, the server have to store each xsrf-token for future verification purpose, this is stateful. With xsrf-token in jwt, the verification can be simplified as just compare the xsrf-token in jwt with the one in http header.

      • That’s correct! Finally, I think JWTs do NOT protect us from XSS attacks.

  • Awesome piece, thanks for the very well-written and helpful writeup.

  • Marco Martens

    Thanks for the great post.

    I’ve got two questions:

    1. How would you handle tokes on mobile like an android app?

    2. So far I only read posts, where the token was stored into session storage and only accessible via https. What’s wrong with that approach?

    In my opinion the article suggest storing jwt into cookie is the one and only option to do it the right way.

  • Sam

    If store JWT as cookie, isn’t it just a re-implementation of signed cookie?

    • Tom Abbott

      It matters what your definition on a signed cookie is. You could sign a jsession id, but that isn’t very portable and stateless. It definitely is signed data in a cookie, but the idea of standardizing around JWT is to have it stateless.

  • Sam

    If so, isn’t that a re-implementation of signed cookie?

  • bsingr

    The article suggests to store a CSRF-Token in the JWT which is valid during multiple req/res cycles. We can call this session-based CSRF-Token.

    This is a problem when it comes to such attacks like BREACH, see http://security.stackexchange.com/questions/43669/with-breach-attack-is-session-based-csrf-token-still-secure and http://breachattack.com/

    To prevent this, it is suggested to either don’t use session-based CSRF-Token (e.g. instead use crypto-nonce to establish CSRF-Token per req/res) or turn HTTP compression off.

    It’d be nice if the author could comment on this.

    • Tom Abbott

      BREACH is an interesting exploit. Let’s take a look at what a BREACH attack is going after, the secret that is contained in the HTTP body. This exploit uses HTTP compression to guess the secret. A site that uses a global secret and guessable bits to generate a CSRF token to place in the form body are highly susceptible to this attack. Since you are using cookies, the information will be in the header and protected by TLS. Let’s say you were passing the JWT in the body though. The CSRF token is kept in the access token JWT, if you are using refresh token with a extremely finite access token (let’s say 30 second access token) the iat/exp/signature will all be changing fast which could mask them trying to guess the valid JWT. Hopefully this information helps. Feel free to ask any follow ups.

  • Mahendra Kumar

    Is it a good approach to store the token in the client storages like session/cookie.localstorage. What if the token is stolen and the same can be used to modify any access level details.

    I am a .NET developer. In one of my client application we are using the web api for resources. We make the Rest full API calls from our Application(in my case MVC). We store the token in the server so that no one can put an eye upon.

    but our application also makes some requests to the the Rest full apis. If we store the received token at the client browser storage this can get leaked so this option is ruled out. Please let me know how to use angularjs to get the resources and show it in the UI.

  • Yaan Xuin

    How do you support opening of multiple tabs and multiple windows of same broswer without forcing multiple logins from the user, using X-XSRF-TOKEN header approach?

  • If you are doing a phone app or web app, you should NOT store the JWT it at all, only as a variable in memory.

    WHY?

    Because if you have any popularity in your web app, phishing scams or XSS can easily go to a known URL and then do harm because the cookie or local storage will still exist. If your known URL requires a JWT token in memory, then nothing will work upon redirect, rather it will show the splash screen. Also, keeping the expiration low isn’t a bad idea either and you can easily refresh the token while the user is actively logged in as you simply refresh it in the background every x interval.

    In phone apps, if the app was purged from memory, it will require sign in again which is probably what you want anyway.

    This is pretty practical because if you are using oauth2 for sign in, chances are the 3rd party app already has the cookie set on say google or facebook or twitter for example and the sign in will just auto redirect back taking 1 second. As long as you don’t have some replay logic to retry a failed URL from auth not being there, you are good.

    If you have better ideas, I’m all ears.

  • nou

    If I want an automatic logout when the user close the tab/browser, I should store the token in the sessionStorage (WebStorage), as it is cleared once the browser is closed.
    With this use case, is the alternative of cookies the recommanded one?

    • Tom Abbott

      Cookies have a similar mechanism. When no expiration date is set, a cookie is cleared when the user closes the browser. In this case, the API that is receiving the JWT will be able to validate based on the exp claim in the JWT, and the cookie will be deleted once the browser closes and the client (browser) will require authentication again.

  • David Komer

    A few followup questions:

    1. Should the xsrf token value be identical in the jwt (stored in http-only cookie) and token (non-http-only cookie)- or is there any added value to having them different? If different, how can it be validated without a db hit (or in other words, validated by a different server than the original auth)?

    2. This still doesn’t address using jwt tokens for authentication for regular page requests, correct? One would need to build a website to basically operate primarily through ajax calls (say for example showing different navbars for logged in / not logged in)? (or maybe, though bad for SEO, the xsrf token can be automatically appended to all links and checked via GET… but that’s nasty)

    3. When using tokens *both* for native apps and the web- how do you distinguish whether or not both the X-XSRF-TOKEN and xsrfToken need to be there… seems like it’s a moot point for the mobile apps. Would you suggest using a claim (like “aud”) and if the jwt contains a non-website “aud” then skip that check (and in that case, no need to make a larger jwt so skip the xsrfToken claim too)?

  • Booboo

    This is a great article but unfortunately it still doesn’t address what is a growing problem for me (and I assume others) when writing Clients/Services for my current projects… …and that is doing cross domain requests.

    How do I do CORS safely if I have to use a HTTPOnly cookie that contains the JWT token? The token is returned by a service in a cookie (which I cannot change) and tied to the Domain of the service that first issued it.

    Currently it looks like I need to use a non-HTTPOnly cookie and then access it in my angular application in order to do cross domain requests, is this correct? If this is the case then it looks like I am forced into an insecure design.

  • Meno

    I’m confused as to how Stormpath works. Does my front-end web application authenticate with my resource server, which communicates with Stormpath, and therefore my resource server sets the access and refresh token cookies? If my web app is authenticating directly w/ stormpath, which sets the access and refresh token cookies, then how does the access token get sent with each request to my resource server?

    • Tom Abbott

      Stormpath sits behind your resource server. If you are using a Stormpath Integration (like stormpath-express on github) and angular (stormpath-angular), it will automatically expose an oauth/token endpoint for your front end can use.

  • Great article!! I had a question, however. Why would you store a xsrfToken property in your JWT body? Are you comparing it to another cookie being sent?

    • cusx

      You are using it to compare to the X-XSRF-TOKEN http header.

    • Tom Abbott

      Exactly, cusx! and it is signed, so you know it isn’t tampered or added by a 3rd party.

    • After much research and trial and error, I ended up with this solution:

      Upon a successful login, I have PHP create an httponly cookie for the JWT and create an XSRF token to pass back to the client to get/put in the cookies. On each subsequent request, the XSRF token is passed in the request headers. On the server, the PHP JWT stored in the $_COOKIE is decoded. Then the XSRF token stored in the JWT needs to be the same as the XSRF token passed in the request headers.

      The JWT token is only readable by the server to prevent XSS. The XSRF token is readable by the client, but was granted dynamically from the login, preventing session hijacking.

      Pretty sure I’m on the right path. Took a while to get my head around it and figure out how to implement it, but seems to be working so far.

  • Yen Sheng

    How do you pass a JWT token through an API if the token is stored in a httpOnly cookie?

    • The cookies are still passed on each request, they just can’t be read by the client. In Angular, I had to set the $httpProvider.defaults.withCredentials = true in the config.

  • lostdorje

    Great article! Thank you.

    I’m either misunderstanding something or I’m going to need a new solution in my Angular code. One thing I have found great about JWT tokens was accessing them in my Angular code. I could easily grab the roles/permissions out of the token and render (or not) certain parts of the site based on the user’s roles.

    Likewise I was using the tokens for permissioning checking on the server-side as well. Two birds, one stone. I was happy.

    Thanks to this article I understand the XSS problem much better and how setting HTTP_ONLY on the cookie solves it.

    However, I’ll no longer be able to get to the JWT token and won’t be able to permission the UI.

    How can this now be done in the UI?

    • Adam Beck

      I don’t think that would work in your scenario. Putting into an HttpOnly cookie would only be good for making sure the user is authenticated or not. It sounds like a good approach but I still think you are better of storing it in Local Storage/Session Storage and doing your best to mitigate any XSS.

      • Actually a httponly cookie does help prevent against XSS since the client can’t read it, and since the client can’t read it, malicious javascript can’t exploit it.

      • Adam Beck

        But lostdorje wants to use the JWT and extract user roles out of it. Like you said, this can’t be done because it can’t be read with Javascript. And while httponly cookies do prevent xss they don’t protect agains xsrf.

      • lostdorje

        Right. What I ended up doing was creating a new api endpoint /authenticated user, which just returns the JWT token for use in the JS, extracting roles, etc. The endpoint requires the HTTP_ONLY cookie JWT_TOKEN to be set so the user must have authenticated first.

        Regarding XSRF, as described above, the JWT token also holds an XSRF token. Then posts to the server must have the X-XSRF-TOKEN header set and are checked against the XSRF value in the JWT token cookie XSRF field.

        I’m not a security expert, and at some point will certainly want a full security audit, but I believe this achieves all my goals and closes the security holes.

        I don’t think I’m missing anything.

      • Adam Beck

        Regarding the X-XSRF-TOKEN, aren’t you back to having the possibility of an XSS attack?

      • The token stored on the server prevents the XSS since it can’t be read by JavaScript. The XSRF token stored by JavaScript is sent on each request and compared to the XSRF token stored in the JWT payload. If they don’t match, it’s not a legit request. So he’s got both XSS AND XSRF covered.

      • Adam Beck

        Unless an attacker is able to use XSS to get the XSRF token and also get a user to send a request. Which, if there is an XSS vulnerability would be easy to do.

      • But without the JWT token, the request can’t happen, which is the httponly token on the server. It’s a bit confusing and took a bit to get my head around it but it work’s quite well.

      • Adam Beck

        If an attacker gets you to send a request from the vulnerable site it will automatically send the cookie (even if its httponly) along with it.

      • So you’re saying if a person followed a malicious link to say a bank website but it’s actually the hacker’s site?

      • Adam Beck

        No. Say I’m an attacker. I’m able to inject JS into your site because there is an XSS vulnerability. First thing I do is grab your XSRF token. (say from local storage or a non-httponly cookie). Then I can make any GET request I want without any user interaction (because I’ve injected code into the DOM to make an AJAX request). If your GET requests allow for side-effects I can cause harm to users of your site. POSTing would be more difficult, I believe.

      • But you’re only stealing the XSRF token. The authentication requires both the JWT token set on the server AND the XSRF token passed in the request. You don’t have the JWT cookie on your machine making the request. You would have to steal the JWT token that was set by the server, but since its httponly, you can’t access the JWT token because it’s not accessible by JavaScript.

      • Adam Beck

        I’m not the one making the request. I have injected JS code into your site. Every user to your site “sees” my JS code. They run it automatically. They are sending that cookie with them when they run that code. And that code is making a request with the stolen XSRF token it grabs (for each visitor).

      • I guess my case is that the attacker can’t just steal the XSRF token and use it to gain authentication because the XSRF alone is not the only source of authenticating. But, yes, it still doesn’t prevent malicious javascript from running amok on your site. That’s were sanitizing data comes in.

      • Adam Beck

        Right. It’s not. You would also need the cookie. And that cookie gets sent by the browser to your domain because my malicious code is running on the same origin. Both pieces of authentication are getting sent when a visitor visits your attacked site: the XSRF (which was stolen via my XSS inject JS code) and the httponly cookie (thanks to the browser and my code running on your servers)

      • Tom Abbott

        Great discussion going on here, I was getting spammed by Disqus. I’m the author of this post, if you don’t recognize the name.

        When XSS exist on a page, an attacker is privileged to:

        -HTML5 web storage (local and session)
        -Cookies that are not set with httpOnly flag
        -Control of the tab until it is closed and the ability to make unauthorized requests
        You can also start to formulate attacks to get around XSRF protection.

        When an XSRF vulnerability exists, an attacker is privileged to:

        -Making unauthorized requests from a 3rd party domain, if you can lure a user there (or send them there in the presence of XSS).

        You can see that when an XSS vulnerability exists, you are able to make unauthorized requests and an attacker would need to jump through some more hoops to exploit XSRF. This means that when XSS exists (regardless of XSRF protection or not), the attack vector of making unauthorized requests will exist. This is the unfortunate nature of XSS, and why it is very important to protect against it.

        Hopefully, that clears things up for my next point, which is why I recommend using httpOnly secure cookies instead of HTML 5 web storage

        An XSRF attacks or unauthorized requests has less impact and scope than stealing a stateless token that represents the user’s identity and session. Leaking the token means that an attacker will have full control to formulate an attack on behalf of the user, on his time, on his machines.

        In conclusion, in presence of XSS when you:

        store an access token in web storage, the tokens for any user that uses your site during the time of the existence of XSS is compromised. This means an attacker could get thousands of valid access tokens and can possibly do a lot of harm (even more if you store refresh tokens in web storage). The users are also vulnerable to making unauthorized requests from their own browser.
        store an access token in a httpOnly cookie, the tokens for any user are not compromised. But, the users are also vulnerable to making unauthorized requests from their own browser even in the presence of XSRF protection, until the XSS issue is resolved.

        Hope this information helps.

      • Adam Beck

        I agree almost entirely with your comment. It’s a very safe and secure method (and one that I use). I continued this disussion so that others were aware this method is not 100% secure. A XSS vulnerability can destory all safety of this. And while it does prevent a user from having access (via a valid token and corresponding XSRF-Token) for an extended period of time, the attacker can still cause damage if your GET routes have side effects.

        fetch('yourdomaindotcom/sendMoneys?token=istolethiswithxss&recipient=mypersonalid

      • Sounds like you got it. This is exactly what I’m doing as well. But, you want to make sure you’re sanitizing your data obviously.

      • lostdorje

        Right!

      • Well, the JavaScript can’t extract the user roles, but the server can, and it can return the user payload from the token, which sounds like thats what he’s doing.

      • lostdorje

        Per this article, I learned due to XSS, that’s not such a great location for the JWT token. Further cookies are vulnerable to XSS. So put the token in a HTTP-ONLY cookie. Check.

        But actually, my secured /authenticateduser server api endpoint just returns the JWT token itself which the JS decodes. I’m using Angular and I store the JWT token in an Angular service and now I can just use the service and JWT token for role checking as I was originally doing via the browser’s local storage.

        I couldn’t think of any obvious attack vector where 3rd party JS code could easily read data in my AuthenticatedUserService Angular Service. Is this wrong?

      • As far as I know, no, there isn’t a way to read data from the Angular Service. All of my token handling is done on the server so my scenario is a bit different though.

    • I’m using PHP to set/get the the httponly JWT cookie on each request for validation. If you don’t have access to the server-side, then not sure how you would go about it.

  • Hugo

    Thanks for this article, it’s food for thought. I’d point out that using a cookie validated by an XSRF token doesn’t prevent an XSS attack from hijacking the user’s session from within the page itself. Any malicious script running on the page will have access to the XSRF token and any cookie will be automatically sent with any HTTP requests to the server, leaving you at square one.

  • ANkit

    A simple question, Do i need to implement the session as well if I am using tokens??

  • ialex

    Hello @disqus_r3d6yGe9VT:disqus, @DenisPshenov:disqus

  • Josh Kula

    I think storing JWT in the client side depends of the implementation. whether the developer opt for LocalStorage or Cookies to store the jwt.. both localstorage and cookies are read and write containers within the same origin or same host domain. the best way to mitigate the attack remains the application of CORS and CSP maybe including the HSTS (Http strict transport security).

    let me explain myself, with CORS (Cross origin resource sharing) , a developer can define the specific list of domains origin that can query the API (host domain) plus headers constraints.
    this is helpful to avoid CSRF from embedded script within a webpage like the famous request.

    Note: we need to avoid any embedded script in your application to lower the vulnerability.

    Second, with (Content security policy), a developer working with the IT team can define the trust between the type of resource that can be requested and their context of execution(domain).
    for instance, a developer can define JavaScript to only be executed from a CDN not a host domain because with a default same origin, an attacker can exploit this vulnerability to read cookies and LocalStorage using XSS.

    the last one is HSTS, this is useful when you want all requests between your define CORS to use the default SSL encryption to protect data again tampering.

    note: while using HSTS, avoid using any another encryption in the client side, this will impact the performance of the application but you can use hashing.

  • albanx

    why cookies are more secure than localStorage on sending the JWT data? both of them can be read if are not on HTTPS

    • Iazel

      the cookie method expect you to use https and httponly cookie, hence the token can’t be read

  • Joe Narvaez

    Excuse the naive question, but how does https prevent xss with JWTs?

    • Iazel

      What https prevents is a Man in the Middle attack, the kind that reads what you send to your server. JWT nor HTTPS will shield you from XSS, for this you have to ensure that your code and the libraries you use correctly manage all user’ inputs. That’s said, you can prevent the leak of the token even in case of an XSS vulnerability by using the cookie method and ensuring it is HTTPOnly (not readable by javascript)

  • preetb123

    @disqus_r3d6yGe9VT:disqus On successful authentication, the token should be sent in the response body or from the response headers?

    HTTP/1.1 200 OK
    Content-Length →112
    Content-Type →application/json; charset=utf-8
    Server →nginx/1.4.6 (Ubuntu)
    auth_token →RA1wkDY2Ee8wcGDQ8tLU1ULn

    OR

    {
    “user”: {
    “name”: “Test User”
    },
    “auth_token”: “RA1wkDY2Ee8wcGDQ8tLU1ULn”
    }

    Is there any advantages(w.r.t security) sending it though response headers?

  • Ivano Pagano

    Late reply, but nice reading still.
    @ingben:disqus I suppose that the XSRF cookie can be tampered with, instead you can’t forge the jwt token without breaking its integrity.
    If someone can force your site to set the cookie with a XSRF hacked token, then she can use your jwt.

    Don’t know if I’m missing something

  • Ivano Pagano

    I read (almost) all the comments and thinking about the XSRF issue and the X-XSRF token/header solution which is a bit convoluted (without being as complex as OAuth).

    Just wondering if storing the “Origin” header in the JWT at creation will give you the same guarantees.
    You check that all requests with the token comes from the same origin by checking the corresponding custom claim.

    Of course this means that your authentication request (with name/pass or clientid/token) must come from the same domain as your subsequent requests.
    But I guess it’s the same with the X-XSRF solution.

  • yassine

    andromeda is heading straight for us omg ?

  • Michael Yuen

    Brilliant design!
    I am wondering if I have a refresh token and access token kind of design,
    Seems putting the refresh token in cookie doesn’t makes sense, as the cookies are sent in every request.

    How should I prevent the refresh token being sent every time?

    • Mark

      Thats is a very good question. I guess you have to send it everytime since you don’t have access to the cookie itself to grab the refresh token. If you would expose the refresh token within javascript you would not have won anything as the attacker could use the refresh token to gain a new access token.

      • Michael Yuen

        that means it’s an unavoidable trade-off.

      • Mark

        The flows could work as described below:

        Login flow
        – Client sends request with user/pw
        – Server sets refresh token/access token in cookie(httpOnly=true)
        – Server returns only access token and expirydates(access/refresh) in response

        Refresh token flow
        – Client determines if access token is going to be expire
        – Client sends POST/PUT request to refresh the token
        – Server checks cookie if refreshtoken is valid
        – Server sets new access token in cookie and returns access token and expirydate

        Logout flow
        – Client sends request to logout
        – Server unsets cookie

        CSRF protection(I think the access token does a good job as csrf token since its going to change frequently)
        – Client sends on every request the accesstoken in the header
        – Server checks if accesstoken in the cookie equals the one send in the header(double submit)

      • Michael Yuen

        Mark, you’re brilliant! Very detailed design. Some follow up questions.

        Q1. “Server sets refresh token/access token in cookie(httpOnly=true).”, so there will be requests with two tokens in the http cookie header?

        Q2.”Client determines if access token is going to be expire”, how to determine if javascript on client side cannot access cookie due to (httpOnly=true).

      • Mark

        Q1. Yes, you will need to send them both everytime since you can’t control the cookie because its httponly=true
        Q2. The server needs to send the expirydate of the access token on login/refresh so you know when to refresh it.

      • Michael Yuen

        Thanks for clearing my blindspot!

      • Saeed

        Hi Mark,
        Thank you for your informative response. In the login flow, access token is set in response body instead of in jwt token, right? Then client should store access token for further requests to be added in the header. Still storing access token in cookie or session storage is vulnerable to attacks. Could you elaborate on this? thanks.

      • Mark

        Yes you are right.
        It depends on the requirements of your app but you could use a dedicated CSRF token shared on login/refresh and store this on client side/httpOnly cookie. On every request you would check the CSRF token as well(double submit).
        In my sample I used the access token as an CSRF token under the assumption it changes frequently(e.g. every 10 min.). So the attacker has a very limited time frame if the access token gets exposed. But maybe I am a bit to naive here 🙂

  • Manisha Sathe

    Thanks for the great article. I am new to this JWT world. We have UI server running on apache (angularjs) and backend REST web service on tomcat (Spring MVC). We also implemented your suggestions (JWT using HTTPOnly Secure cookie + CSRF token in another normal cookie – Angular reads this cookie and set the header). I have just one quick question. We are thinking of adding native mobile App (Ionic), connecting to same backend REST web service. Mobile app also need to authenticate, but as cookies are not supported well I would like to understand what is normally done in this scenario? Or shall we have 2 separate mechanism – For Web with cookies and For mobile App – saving JWT in local storage and eventually setting JWT inside header ? Your input on this would be greatly appreciated.

  • Julien Rougeron

    Thanks for these infos on the subject !

    Developing an Angular Universal App, and I would add cookies is also the good way to deal with the authentication.

    Correct
    me if I’m wrong, but the cookie (with JWT token in it) will be pass
    along the first GET request to the server. In the case of a Universal
    app, the server will be able to authenticate the user reading the jwt
    token in the cookies, and pre-render the correct page.
    The
    localStorage values not being sent along the HTTP request, the server
    would render a non authenticated page, which will be updated client-side
    by JS reading the localstorage.

    So apart from security, cookies could also be very useful in universal pre-rendering, from what I understood 🙂

  • AJB

    I’m really not following the logic here.

    You’re arguing that storing the JWT in an httpOnly cookie will prevent against XSS attacks. But if your site is vulnerable to XSS attacks, and an attacker somehow embeds a script that will fire against your api, then the cookie (containing the JWT) will automatically be sent along with the request to your API.

    So what’s the point of storing the JWT in a cookie at all?

    If you store the JWT in localStorage and your site is vulnerable to XSS then the attacker could read the JWT from localStorage and send a request to your API.

    If you store the JWT in an httpOnly cookie and your site is vulnerable to XSS then the attacker could send a request to your API and the cookie is automatically sent along with the request.

    So, storing the JWT in an httpOnly cookie seem superfluous to me.

    If anything, adding the extra complexity of the httpOnly cookie simply introduces a new attack vector (XSRF) because now you’re back to using cookies.

    • The httponly flag will prevent the XSS from reading your token and sending the token off to hacker land for later use. But you’re correct, the httponly token is still sent with every XSS request to the API.

      So it comes back to preventing XSS from happening in the first place by filtering and sanitizing data. And if you’re already filtering and sanitizing data is the double-submit httponly feature even worth the hassle?

    • Tom Abbott

      When XSS exist on a page, an attacker is privileged to:

      HTML5 web storage (local and session)
      Cookies that are not set with httpOnly flag
      Control of the tab until it is closed and the ability to make unauthorized requests
      You can also start to formulate attacks to get around XSRF protection.

      When an XSRF vulnerability exists, an attacker is privileged to:

      Making unauthorized requests from a 3rd party domain, if you can lure a user there (or send them there in the presence of XSS).

      You can see that when an XSS vulnerability exists, you are able to make unauthorized requests and an attacker would need to jump through some more hoops to exploit XSRF. This means that when XSS exists (regardless of XSRF protection or not), the attack vector of making unauthorized requests will exist.

      Hopefully, that clears things up for my next point.

      An XSRF attacks or unauthorized requests has less impact and scope than stealing a stateless token that represents the user’s identity and session. Leaking the token means that an attacker will have full control to formulate an attack on behalf of the user, on his time, on his machines.

      In conclusion, in presence of XSS when you:

      store an access token in web storage, the tokens for any user that uses your site during the time of the existence of XSS is compromised. This means an attacker could get thousands of valid access tokens and can possibly do a lot of harm (even more if you store refresh tokens in web storage). The users are also vulnerable to making unauthorized requests from their own browser.
      store an access token in a httpOnly cookie, the tokens for any user are not compromised. But, the users are also vulnerable to making unauthorized requests from their own browser even in the presence of XSRF protection.

  • Sam Jost

    Good Information, but how do I achieve this? I’m using ASP.NET Core as backend, so I would Need to send the jwt to the Client as Cookie and get UseJwtBearerAuthentication() to read the jwt from the Cookie, but I found no example how to achieve this.
    Right now my frontend uses angular2-jwt, which does expect the cookie in localstorage…