2

For a project I’m working on currently I am developing an API using Node/Express/Mongo and separately developing a website using the same tools. Ideally I want to host these on separate servers so they can be scaled as required.

For authentication I am using jsonwebtoken which I’ve set up and I’m generally pleased with how it’s working.

BUT

On the website I want to be able to restrict (using Express) certain routes to authenticated users and I’m struggling a little with the best way to implement this. The token is currently being saved in LocalStorage.

I think I could pass the token through a get parameter to any routes I want to protect and then check this token on the website server (obviously this means including the jwt secret here too but I don’t see a huge problem with that).

So my questions are

  1. Would this work?
  2. Would it mean (no pun intended) I end up with ugly URLs
  3. Would I just be better hosting both on the same server as I could then save the generated token on the server side?
  4. Is there a better solution?

I should say I don’t want to use Angular - I’m aware this would solve some of my problems but it would create more for me!

DevFox
  • 554
  • 2
  • 11

1 Answers1

4

First off, I'll answer your questions directly:

  1. Will this work? Yes, it will work. But there are many downsides (see below for more discussion).
  2. Not necessarily. I don't really consider ugly urls to include the querystring. But regardless, all authentication information (tokens, etc.) should be included in the HTTP Authorization HEADER itself -- and never in the URL (or querystring).
  3. This doesn't matter so much in your case, because as long as your JWT-generating code has the same secret key that your web server does, you can verify the token's authenticity.
  4. Yes! Read below.

So, now that we got those questions out of the way, let me explain why the approach you're taking isn't the best idea currently (you're not too far off from a good solution though!):

Firstly, storing any authentication tokens in Local Storage is a bad idea currently, because of XSS (Cross Site Scripting attacks). Local Storage doesn't offer any form of domain limitation, so your users can be tricked into giving their tokens up quite easily.

Here's a good article which explains more about why this is a bad idea in easy-to-understand form: http://michael-coates.blogspot.com/2010/07/html5-local-storage-and-xss.html

What you should be doing instead: storing your JWT in a client-side cookie that is signed and encrypted. In the Node world, there's an excellent mozilla session library which handles this for you automatically: https://github.com/mozilla/node-client-sessions

Next up, you never want to pass authentication tokens (JWTs) via querystrings. There are several reasons why:

  • Most web servers will log all URL requests (including querystrings), meaning that if anyone gets a hold of these logs they can authenticate as your users.
  • Users see this information in the querystring, and it looks ugly.

Instead, you should be using the HTTP Authorization header (it's a standard), to supply your credentials to the server. This has numerous benefits:

  • This information is not typically logged by web servers (no messy audit trail).
  • This information can be parsed by lots of standard libraries.
  • This information is not seen by end-users casually browsing a site, and doesn't affect your URL patterns.

Assuming you're using OAuth 2 bearer tokens, you might craft your HTTP Authorization header as follows (assuming you're representing it as a JSON blob):

{"Authorization": "Bearer myaccesstokenhere"}

Now, lastly, if you're looking for a good implementation of the above practices, I actually wrote and maintain one of the more popular auth libraries in Node: stormpath-express.

It handles all of the use cases above in a clean, well audited way, and also provides some convenient middlewares for handling authentication automatically.

Here's a link to the middleware implementations (you might find these concepts useful): https://github.com/stormpath/stormpath-express/blob/master/lib/authentication.js

The apiAuthenticationRequired middleware, itself, is pretty nice, as it will reject a user's request if they're not authenticating properly via API authentication (either HTTP Basic Auth or OAuth2 with Bearer tokens + JWTs).

Hopefully this helps!

rdegges
  • 32,786
  • 20
  • 85
  • 109
  • 2
    Firstly, thanks for taking the time to post such a detailed response. I did take a look at Stormpath though I was approaching it from a PHP standpoint (so cURL) at the time...and I'm not a big fan of cURL. I'm interested that you say storing a jwt in Local Storage is a bad idea - [I had the impression](https://auth0.com/blog/2014/01/27/ten-things-you-should-know-about-tokens-and-cookies/#token-storage) this was ok? – DevFox Feb 06 '15 at 18:20
  • 1
    No, that article actually explains the opposite -- it's best to use cookies to store tokens -- never local storage. There are several known vectors of attack that way. It is a common misconception. Also: the Stormpath stuff works directly through express.js (or node), so you can use it for either one if you're interested. It does all of this stuff and more (and is free). – rdegges Feb 06 '15 at 18:26
  • Storing in cookies isn't a problem but I'm still a little confused as to why it is necessary and particularly why you say they should be encrypted as well. I'm not doubting you in anyway, I'm just trying to get my head around it all. I've been following a book produced by the team at Scotch.io where the token is stored in plain text in Local Storage on the client side. As I understood it, all any malicious person could do with a 'stolen' token is pretend to be a particular user for the duration of the token. While this is obviously not ideal, is there a more serious risk that I am unaware of? – DevFox Feb 06 '15 at 22:50
  • 1
    That's the main risk: that your token is exposed to a third party. With LocalStorage you can always access the stuff stored inside via javascript. So if someone is able to run javascript on your site or theirs, and is able to access that localstorage token, that javascript code can then do anything your user can do: change their password, bill them, change the account email, anything at all. This happens often via XSS. That blog post I linked to in my answer shows a good example of how this happens =) But yes, that is the main risk. This doesn't happen with cookies as you can set httpOnly mode – rdegges Feb 06 '15 at 23:13
  • Would this work…User logs in using form at SITE. Form submitted to SITE server, SITE server validates creds, generates token and stores this client side as a signed and encrypted httponly cookie. For forms etc on SITE that I want to submit directly to API through AJAX, would it be safe to pass the token value through server side as plain text to my view which could then be stored as a (hidden) input on the form. Then I could access this through javascript? Also am I correct that the token generated on the SITE would still be valid for the API as I’m using the same ‘secret’. – DevFox Feb 06 '15 at 23:49
  • You might wanna read this: http://stackoverflow.com/questions/18280827/using-oauth2-in-html5-web-app It covers your question in a bit more detail than I can fit into this comment box ^^ – rdegges Feb 07 '15 at 00:08