
Token-Based Authentication with Node - mjhea0
http://mherman.org/blog/2016/10/28/token-based-authentication-with-node#.WGpZXDsOZx9.hackernews
======
zbjornson
We naively started with JWT for auth, and gleefully ripped it out after
several months because of all of its cons.

1\. Overall, no net benefit. We still had to query a k/v store on every action
to check that the token wasn't revoked.

2\. Less secure because there's no way to make it act like an HTTP-only cookie
(no access from JS).

3\. No way to revoke all of one user's tokens because there is no list of
those tokens. We want to limit (or be aware of) the number of active logins
and let the user sign out from all locations (as you can in Gmail). If the
token is only stored on the client, there's no way to do this. You could store
a list of all granted tokens and only use it for these revocations, but that's
yet another level of complexity. (When we dropped JWT, the diff was -1200+95
LOC because we had to handle a lot of scenarios like this.)

4\. Adding tokens to client-side requests is a pain. The common example for
e.g. Angular is to use an HTTP interceptor to add a header. More code, but it
works... Except for img and a (anchor/link) elements where you can't add a
header. So you put the token in the URL query instead, and now you're
vulnerable to session leaking if a user shares a URL with someone else. And
you have to manually update those embedded tokens when they expire, as many
JWT folks recommend you make the expiry short.

Good riddance.

~~~
TomMarius
One benefit over simple token formats (e.g. using UUIDs as tokens) is that you
are able to quickly invalidate the token, because you don't need to hit the
database at all.

Second benefit is, at least for me, standardization.

Edit: fixed typo

~~~
ezekg
How do you invalidate a JWT without hitting the database though? The JWT is
already signed with its claims, so there's no way your application can know
it's revoked unless there's a list of revoked tokens, which defeats the whole
purpose of using JWT. Or am I missing something?

~~~
TomMarius
No, no, you got me wrong. The point is in faster _invalidation_ , not
validation. That means you are immediately able to tell an invalid token from
a not-yet-determined one (but not from a valid one). Then you have to hit the
database, but the number of hits is - in some cases drastically - reduced.

~~~
zbjornson
It sounds like you mean if you change the signature used to sign the tokens,
then existing tokens will fail validation without hitting the db? If so,
that's not too practical because _all_ of your users are suddenly signed out.
What myself and the two other posters I think encountered is that you have to
store revoked/invalidated tokens in a blacklist, and then check that a token
in a request is not in that blacklist. (That was my first point, at least.)

~~~
TomMarius
No, I simply meant that instead of checking if a token is valid, you can first
check if a token is obviously invalid (e.g. expired, wrong claims, wrong
audience...), and immediately return if so, thus reducing the load on your
application servers and databases; and only then query the database to check
if the token has been revoked.

------
jordache
A good security strategy is to implement custom security layer as a last
resort. Doing so will have a much higher chance of introducing bugs that will
allow attacker into your environment.

~~~
quasse
Yeah, in this case I'd tend to agree that using a good framework like Passport
and then the JWT[1] strategy is probably a good move.

It's never a bad idea to understand the basic structure of how a framework
might be doing the work for you behind the scenes though.

[1] [https://www.npmjs.com/package/passport-
jwt](https://www.npmjs.com/package/passport-jwt)

------
ezekg
This isn't at all directed at this post in particular – but I'm curious,
what's with the huge movement towards JWT? I get their use-case, but it seems
like most implementations shoe-horn JWT's to act exactly like access tokens
stored within a database. Revoking a JWT doesn't make any sense to me.

~~~
awjr
I have to agree. A JWT contains within it 'claims' that are the authorization
for allowed behaviour against the API. Authentication happens before the JWT
is issued.

I think the problem is that it's not about issuing just one JWT, you need a
'refresh' token and a 'security' token. The security token expires quickly,
but a new security token can be issues using the refresh token which has a
long expiry.

You can even make the refresh token single use with the action of refreshing
the security token returning you a new refresh token. This, however, needs to
be handled carefully within the UI as two requests using the same refresh
token would invalidate the 'session'.

The reasoning is that the api can trust the claims within the security token,
but has no need to access external sources to validate the token. The refresh
token can have security policies applied to it as well as 'user logged out'
checks against the refresh token. This keeps the API requests extremely fast
with only an intermittent (once a minute) need to get a new security token.

~~~
eridius
Of course, if your application hits the API less than once a minute, you've
now doubled the number of requests it needs to make, because it will need to
refresh the token before every call.

