If you’re confused about token-based authentication: this post is for you. We will cover access tokens, how they differ from session cookies (more on that in this post, and why
they make sense for single page applications (SPAs). This article is primarily written for those with a SPA that is backed by a REST API.

We’ll pay special attention to best practices for handling JWTs and security: successful token authentication system requires you to know the security details and possible tradeoffs.

Thankfully, we’ve wrapped up all the best-practice decisions into some libraries you can use: Stormpath Angularjs SDK to solve your Angularjs authentication challenges, and it’s back-end pair, the Express-Stormpath.

Single Page Applications: The Authentication Problem

Single page apps make a lot of sense for customer-centric applications that handle a lot of user data. SPAs are often tied to a RESTful API for a good reason: when your data makes sense, your experience makes sense. We just rebuilt our console – an Angularjs-based Single Page App – and spent a lot of time modeling out the REST API (the actual data model/structures).

With the user model mapped out, it’s much easier to build a UI for your API because the common things like list views, search boxes, sorting, etc – they just fall in place alongside your data model. Fronting a REST API with a single page app gives the assurance of sane data and the freedom to make your UI look and feel sexy. #winning

But it poses an authentication problem: how do you open up your API access in a secure way?

Since we are championing tokens, we should visit their alternative: cookie-based sessions.

Most websites use a strategy that stores a cookie in the browser. After you login this cookie contains an ID that links you to a session maintained somewhere in the server. This session knows who you are when you make a request using that cookie.

There is nothing wrong with this practice as long as you use HTTPS only cookies that cannot be read by Javascript or non-secure transports.  You should also implement a CSRF mitigation strategy.

But if you’re building a SPA, it still leaves access control as a question mark: how do you let your SPA know who this user is and what they can access?

JSON Web Tokens (JWT): A Crash Course

The best known solutions to authentication and authorization problems for APIs are the OAuth 2.0 spec, and tangentially the JWT specification, which are fairly dense. Cliff’s Notes Time! Here’s what you need to know:

  • Json Web Tokens (JWTs) are a great authentication mechanism. They give you a structured way to declare who a user is and what they can access. They can be encrypted and signed for verification.
  • The notion of scopes is powerful and yet incredibly simple: you have tons of freedom to design your own access control language.
  • Refresh tokens are horribly confusing and don’t really solve any security problems if you need high security. We’ll elaborate on this later.

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:

What you see is a header which describes the token, a payload which contains the juicy bits, and 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).

We’re going to magically decode the middle part, the payload, and we get this nice JSON object:

This is the payload of your token, technically called the JWS Payload. It allows you to know the following:

  • Who this person is and the URI to their user resource (sub)
  • What this person can access with this token (scope)
  • When the token expires. Your API should be using this when it verifies the token.

These declarations are called claims and they are 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 it’s signature and implictly trust what is claimed. This provides some interesting optimizations for your backend architecture, but there are some tradeoffs and we discuss them in a later section.

Tokens are given to your users after they present some hard credentials, typically a username and password but they could also provide API keys or even tokens from another service. Stormpath’s API Key Authentication Feature is an example of this. The idea is that you present your hard credentials once and then you get a token that you use in place of the hard credentials.

The JSON Web Token (JWT) specification is gaining traction quickly. It provides structure and security, but with the flexibility to modify it for your application. We highly recommend it and have a much longer article on them: Use JWT the Right Way!

Why JWTs Are Great for Single Page Applications

SPAs tend to have many faces: the logged in view, the logged out view, or the restricted view. It’s all about access control. Your users are all getting the same app but they may not have the same levels of access. You’ll find yourself building access control logic for your front end and your back end.

Because tokens contain all this information, they are very portable: they can be used by your UI and your backend to make decisions. You can share them with partner services as a means of building Single Sign On services that delegate users to the correct application.

There are some details that matter if you want to achieve this nirvana while maintaing security in the browser. We’ll get to that in the “Tokens Love Cookies” section.

How to Use JWTs Securely

If your tokens get stolen, all bets are off. Since we’re talking about SPAs we’re talking about web browsers, and we all know how many holes there are when it comes to securing data in a web brower.

But these problems have solutions, and this is what you must do:

  • Sign your tokens with a strong key that is available ONLY to the authentication service. Every time you use a token to authenticate a user, your server MUST verify that the token was signed with your secret key.

  • You should encrypt your tokens if you have to put sensitive, non-opaque information in them. This is called JSON Web Encryption or JWE

  • You should NEVER transmit tokens over a non-HTTPS connection. Man in the middle attacks are real.

  • You should store JWTs in secure, HTTPS-only cookies. This prevents Cross-Site Scripting XSS attacks. We’ll cover this more in the section below, “Tokens Love Cookies”

But there is one catch: you have to decide how long your tokens are valid for and how you will revoke them if you need to.

Token Expiration & Revocation

The stateless benefit of simply checking the signature is great, but it does come with a problem: it means that the access token is essentially valid forever. How do you revoke the access token if you need to?

Your next level of defense is token expiration. You should set this to a value that makes sense for your application. If you’re a bank, that might be 15 minutes. If you are a social or mobile app, you might want the token to be valid forever. But what if you do need to take it away at some point?

The OAuth solution to this problem is a two-token approach, where a short-lived access token with a longer-lived refresh token is used to get more access tokens. Im my opinion, the two-token system is a very convoluted solution that feels like it was trying to address architecture optimizations and not to make security easy. For more detail I really suggest this stack overflow answer.

The real answer to token revokation is that you need to check more than just the signature and the expiration.

In the Stormpath product we provide a “status” field on all our account objects. This lets you verify that the subject of the token (the account) is not disabled.

Another option is to maintain a record of all the tokens you give out. You add a unique value to the jti field of the token and then retain that in your database, in such a way that they are linked to the users they were granted to. You can then add a layer in your system which allows you to declare a token invalid, and you check all incoming tokens against this blacklist.

Yes, with that last suggestion we have lost the holy grail of a stateless authentication check – but sometimes security requires tradeoffs.

I see a lot of discussions where cookies are pitted against access tokens. While we’ve all been burned by systems that store a session ID in a cookie, and that cookie is not secured and thus gets stolen. That sucks, but its not a reason to use tokens. Its a reason to avoid non-secure, non-https cookies.

Storing access tokens in HTTPS-only cookies is the best thing you can do. Never store access tokens in local storage, that storage area is very vulnerable to XSS attacks. Storing them in secure cookies achieves the following:

  • You don’t expose the token to the Javascript environment in the browser, which is vulnerable to XSS attacks

  • You don’t transmit the token over non-HTTPS connections, which are prone to man-in-the-middle attacks.

But, as always, there are tradeoffs – and there are two we care about:

The security tradeoff is that secure cookies are still vulnerable to CSRF Attacks and you need to implement a CSRF token strategy to combat this issue. This is quite trivial and our SDKs do this for you out of the box.

The application tradeoff is the loss of visibility into the token. All that great information about the subject and the claims is now hidden from your single page app. There are two ways to work around this:

Use the token to fetch the data your SPA needs

This is my preferred approach. You create a token that gives access to an endpoint such as /user/current. This endpoint should respond with the information you need to build the SPA for the user. When your SPA bootstraps, you attempt to access this endpoint. If you get back a successful response you continue with the bootstrap. If you do not, you know that the user needs to authenticate.

Use out-of-band information

Take advantage of the response body when you are responding to a credential exchange. At the same time you write the access token to a secure cookie you can also provide some information in the response body as well. My suggestion is this: put the payload of the JWT in the response body. This allows your JS application to get that information while not exposing the signature of the token.

It does, however, mean that you should not store sensitive information in the access token payload because you’re probably going to want to cache it in the browser for future reloads of the SPA.

Secure All The Things!

So many tradeoffs, so little time! My intention for this article is to give you the options for using tokens happily and securely in your single page app, so your team can make the best decisions.

Please leave your comments below and check out our new Stormpath Angular SDK and Express-Stormpath – they demonstrate how we put this into practice so it’s easy for you to take advantage of this new paradigm.

-Robert out

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

 

  • I think this is an important topic and I’m fascinated by all the interesting things you can do with JWTs. But I find it a little odd that you bring up REST but then don’t discuss the issue of combining cookies with a RESTful API. Specifically, most discussions of REST API Authentication that I’ve read stress the fact that a REST API should remain stateless and that all information should be part of the request. Practically speaking, this means adding an “Authorization” header or including tokens in the URL (e.g., in query strings).

    Any example of a discussion that pretty much completely overlaps the topics you are presenting here but specifically calls out cookies as something to avoid would be: https://auth0.com/blog/2014/01/07/angularjs-authentication-with-cookies-vs-token/

    Comments?

    • Robert

      Hi Michael,

      You’re totally right: passing the token in the Authorization header is an option, but if you’re doing that from a browser you have to expose the token to the Javascript environment. In this article we take the opinion that you should avoid doing that because XSS attacks are real. As always: you can dial these tradeoffs to fit your architecture and security requirements.

      • Renan

        Hi, Robert.

        How does the StormPath AngularJS SDK have access the token then? It cannot access it via the HTTPS only cookies, since it is not accessible to javascript, and you say that storing it in the local storage is bad practice, since it is accessible to javascript. So I’m a little confused on how you’d implement it.

        Thanks!

      • Robert

        Hi Renan,

        Sorry if this is confusing! It’s an awkward tradeoff to explain. One solution is to provide a limited version of the access token by passing it in the response body, and letting Angular read that response body (you still want to keep the cookie secure, with the full token in it). I describe it in the section “Use out of band information”. Let me know if I can clarify further! I will be updating our example application, to, and will include some examples of how to do this.

      • Renan

        Hmmm, I guess I missed that part! Thanks for the pointer!

  • Jones

    Very interesting summary of tokens and cookies.

    What I would like to hear more about is the adjustments one would have to do when developing a mobile app, specifically with cordova/phonegap/ionic + angular – because that’s what I’m using 😛 .

    Where should the token be stored, for how long, and general best practices.

    Another comment: in the express docs, in the API Authentication section, the recommendation is to actually use basic http auth, which was quite confusing to me as oauth is obviously better.

    “Typically, if you’re building a REST API, and aren’t sure which form of authentication to offer – it’s a much better idea to simply use basic authentication (covered in the previous section). If you’d still like to use OAuth, continue reading!”

    (https://docs.stormpath.com/nodejs/express/product.html#api-authentication)

    I’m off to test out the angular sdk, cheers!

  • coja1

    Will you guys be putting together a tutorial on how to use the Angular SDK?

    Am relatively new to Angular, SP, node, express, etc — I’d love to see a tutorial covering authentication and protecting routes on an Angular front end as well as how to authenticate to any back-end services that the front end may be consuming.

  • mattcrider

    Is it possible to use JWTs with the Rails SDK? Thanks!

    • Brent_Jensen

      Hey Matt! The JWT functionality discussed here isn’t available in the Rails gem; we’ve built it into our Angular.js, Node.js and Java libraries (and coming soon to Python) so far.

      Stormpath-rails is community supported for the most part, but if you have any questions about how we implemented token-based auth in our other SDKs, we’d be more than happy to chat. Just send an email over to [email protected] and we’ll setup a call!

  • Marcel

    Interesting approach, storing JWT in a cookie. Do you consider the risk of XSS higher than CSRF? How would you deal with an API living on a different origin?

    • Robert

      I consider them equal risks which have to be mitigated. Cross-origin domains make for a real headache as you’ll have to work with CORS policies. I recommend staying on the same domain if possible. Here is a good article about CORS: https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS

      • Marcel

        I’m well aware of how CORS works. I was asking since the stormpath solution uses cookies which cannot be used cross-domain. Most of the industry uses short-lived bearer tokens, which can be used cross-domain and from non-browser apps.

      • Robert

        That’s correct, JWT tokens can be used in the Authorization header as a Bearer token. If you need to support CORS across domains you may find that strategy to be more flexible, though you will have to expose the token to the JS environment. The approach of this article is to minimize that risk, but it’s a tradeoff that can be made.

      • jellysandwich

        What about withCredentials? This seems to allow cross domain cookies so long as both the server allow it

        http://www.html5rocks.com/en/tutorials/cors/#toc-withcredentials

        Server: Access-Control-Allow-Credentials: true
        Client: $httpProvider.defaults.withCredentials = true;

  • boris

    Hi, so I made an app that works similar to this, this great article helped me too. Tokens are saved to a cookie locally and server has session set to 30min which refreshes always when user push a request. But what is the best way do “refresh” of this at front end? I was thinking of resetting the cookie expiration or similar what doesn’t seem very clever to me. What would be the best way?

    • Robert

      Full disclosure: the “proper oauth” way of doing this would be to issue a refresh token to the client, and the client would use the refresh token to ask for more access tokens. We have not implemented this in our libraries/examples yet, but will at some point.

      Disclosures aside: what you are trying to do is a good alternative to the “proper oauth” way. Here is how I would do it: I would continue reading the access token data to see if the token is expired or about to expire. If it is about to expire, I would issue a new token and save it in the same cookie. I would then set the expiration time of the cookie to the new access token expiration time. This should all be done by your server, you want to continue using the HTTP(S) only flag on your cookies so that the JS environment in the browser cannot steal them.

  • BeniRose

    I seem to be missing something. How do you sign something from the browser when there is no way to store secrets in the browser? I keep looking for this answer everywhere and no one seems to be addressing it. Pls help!

    • Robert

      The signing and verifying happens only on the server. The browser only stores the signed token. The browser supplies the signed token on every request, and the server verifies it.

      • BeniRose

        OK, that makes sense. How does the server verify the client if the client can’t sign it with client specific information (nonce or info about the request it’s making)?

      • mrclay

        HTTPS. The browser indeed uses “client-specific info” in the SSL handshake.

  • Ye Wang

    @disqus_tc1xoybU44:disqus under the section of Before Tokens, the Cookie Session, you said “There is nothing wrong with this practice as long as you use HTTPS only cookies that cannot be read by Javascript or non-secure transports.”

    It’s technically incorrect and a little confusing. I think you meant to say “There is nothing wrong with this practice as long as you use HttpOnly cookie transimitted via HTTPS, which cannot be read by JavaScript or non-secure transports. [1]

    [1] https://en.wikipedia.org/wiki/HTTP_cookie#HttpOnly_cookie

  • Emil Alexandrescu

    Hi Robert, what is contained in third part of refresh token?

    • Robert

      Can you clarify what you mean by “third part”?

      • Emil Alexandrescu

        @Robert I appreciate your reply. You explained the refresh token will be made of three parts – “This is a Base64 encoded string. If you break it apart you’ll actually find three separate sections.” First part – signature hash, middle part – JSON object. I am curious about last part of the refresh token. Thanks!

      • Robert

        Oh! The third part is the digital signature 🙂 it’s what you use, with the secret key, to verify that the token was signed with the secret key.

      • Emil Alexandrescu

        Thanks for clarification @disqus_tc1xoybU44:disqus. Now it makes sense 🙂

  • iainduncan

    I’ve been working on this myself, and would value feedback. What about using a second, non-http-only cookie that gets issued in tandem with the auth cookie to provide the out-of-band user info, instead of in the response body? I’m thinking of this method so that that info stays in lockstep with the auth token as the server can sync up expiry and revocation, but this second cookie can be accessed from the SPA to get the info. Would love to hear if I’m forgetting something though.

    • Robert

      The tradeoff in this situation is that you’re exposing user data for a long period of time, in the browser. So make sure that you’re preventing XSS attacks on your domain.

  • What an awesome article. I’ve been reading a lot of pieces on this topic lately, and this was the breakthrough post that finally brought it all together and made it click for me. Thanks for taking the time to write all this in one place. ^_^

    • Robert

      I’m glad you found this useful! There is definitely a lot of information to cover in this area, so I did my best to consolidate it and make sense of it all 🙂

  • Elena Neroslavskaya

    Many benefits of the token based authentication are gone if we store JWTs in cookies. It’s almost no different to session cookie in such case. Does not solve multi domain problem. And complicates expiration scenario.

    • CrossCourt2

      Unless I am missing something that was my impression as well.

  • Darwin

    Is it possible to store a JWT as a secure, HTTP-only cookie and present it as a bearer token without using Angular.JS?