
Don't use JSON web tokens for sessions - joepie91_
http://cryto.net/~joepie91/blog/2016/06/13/stop-using-jwt-for-sessions/
======
merb

        You cannot invalidate JWT tokens
    

This is simple not true. You ALWAYS will sign your tokens with a well known
secret, you could eventually even add some salt from a database to it.

    
    
        They are less secure
    

Compared to what? Actually JWT will have the same secureness like Bearer
Tokens or Cookies, wherever you store it, its not `less` secure. Horrible
article points here.

    
    
        They are less secure
    

They take the same amount of storage than signed cookies, wuhu I use JWT so
often and I NEVER exceeded the cookie limit, but I wouldn't store them there
anyway.

JWT is as secure as any other solution and this article proves it since he
isn't well informed, he just throws a bunch of stuff out and tries to be "an
expert". Btw. every other solution is really dangerous as well, especially
Cookies could be a total mess of security problems. The same could actually
happen with Bearer Tokens.

My toughts are use the thing your most happy with and the thing you understand
and the thing you can implement with code that is totally clear and especially
code that is really really easy to understand. And actually JWT will mostly
win this battle.

I've seen a lot of people just using Session Cookies from their Framework, but
eventually have no idea about their risks, they have lots of CSRF all over the
place, or using a too small ID or eventually the ID is not really random.
Eventually this could happen with JWT too, tough. As seen by this guy, that he
generates the JWT without any well known secure string. that could be changed.

~~~
lynndylanhurley

        You cannot invalidate JWT tokens
            
    
        This is simple not true. You ALWAYS will sign your tokens with a well known secret, you could eventually even add some salt from a database to it.
    

I think one of the benefits of some (most?) JWT implementations is that it
doesn't hit the database on every request - the token is only validated
against a global secret.

So you can't invalidate a single user's session without invalidating all
users' sessions.

~~~
low_key
I keep a counter in the JWT to at least mostly get around this issue. When
processing a request, the counter is checked for the user, which isn't a big
deal since all of the requests already require looking up the user. A counter
increment invalidates all of that user's existing tokens.

If a user changes their password, their roles change, etc, then the counter
gets incremented so all tokens issued up to that point won't be valid anymore.

~~~
ForHackernews
Can you explain this a little bit more? You keep a counter on the user object
in the DB? What is the JWT buying you if you still have to hit the DB on every
request?

~~~
mstade
Presumably you can keep counters like these on the server edges, and just push
new values out to servers whenever things change, as opposed to query a DB
every time. This wouldn't invalidate _individual_ tokens however, but _all_
tokens that have that counter value. It'd also mean there's a window where
tokens can still be used while servers are being updated with the new
value(s).

These are just some random and half-baked thoughts, I have no idea what OP
does, but there are options to limit hitting backing DBs anyway.

------
chrisfosterelli
I disagree with his argument that JSON web tokens are "less secure". He even
quotes this:

> The only way to retrieve data out of local storage is by using JavaScript,
> which means any attacker supplied JavaScript that passes the Content
> Security Policy can access and exfiltrate it.

In my opinion, it is MUCH easier to get a CSRF vulnerability than it is to
bypass the Content Security Policy. Unless you can get around the CSP and same
origin requirement, this makes web tokens far more secure.

He also states that if you store your web token in a cookie you are still
vulnerable to CSRF. This is only true if you are using cookie headers to send
the token (which is less common), not if you only use it for storage/retrieval
of the token.

Lastly, he argues JSON web tokens are not easier to use, but then points out
you need a _dedicated Redis session store server_ to scale session
authentications. Managing sessions in mobile apps and command line apps is a
_huge_ pain compared to JWTs. How is that easier to use?

~~~
SCHiM
I've tested many web applications, and around 80% of all applications I've
tested contained an XSS of some sort or another, that number drops to around
40% if you only look at stored XSS & XSS in a get request. And to less than
10% when only looking at stored XSS.

Unless you've used cookies with the HttpOnly flag XSS trivially escalates to
session stealing. Do NOT store sessions in anything other than cookies with
the HttpOnly (and really, SecureFlag) flag set.

Using javascript to manage your sessions only the client side in any way is
NOT secure.

~~~
jupenur
> Unless you've used cookies with the HttpOnly flag XSS trivially escalates to
> session stealing

Then again you could just use CSP and mitigate almost 100% of those XSS cases.
Yes, even most of the stored ones. And with JWT + JavaScript you don't have to
worry about all the oddities in the way cookies work, which is a huge plus.

~~~
mwpmaybe
CSP isn't a silver bullet.

~~~
seangrogg
Nor is HttpOnly, really.

~~~
mwpmaybe
I never said it was.

------
EdSharkey
So, if I'm reading the advice right, then ...

    
    
      * Using JWT for authorization, particularly for one-time use == GOOD
      * Using JWT to represent long-lived persistent session state == BAD
    

and, always transmit your tokens in all directions over HTTPS.

This seems like useful advice given all the reasons put forward. Do I
understand correctly or did I miss anything?

~~~
CiPHPerCoder
That's it in a nutshell. A lot of developers also misuse JWT in strange ways,
and the meat of this article was responding to those weird/unsafe use-cases.

~~~
dabernathy89
Haven't used JWTs myself, but whenever I read an article or tutorial about
them, it's always in the context of replacing session cookies.

------
Negative1
This article is deeply troubling from a factual standpoint and I hope people
do more research when considering JWT.

Points; 1) His terms are confusing and just plain wrong. Backwards even. For
example, he calls storing an id in the token and session data server-side as
stateful. That is incorrect; there is no state stored on the client, it is all
server-side. That is by definition a stateless session token. 2) A lot of his
claims of why people recommend JWT are unsubstantiated and frankly, I've never
heard them before (like JWT is better for mobile... what)? Maybe I would feel
better if he provided references but a lot of those points are just plain
misinformed (or imo, made up). 3) "You will not need stateless sessions" is
like saying O(n) performance is usually good enough. Well ok, until it isn't.
Don't assume some worst case performance on your site won't occur. Build
defensively, knowing where you might have a bottleneck (DB I/O for instance).
It's not just 'future proofing". It's good engineering, damnit. 4) It's hard?
Give me a break. 5) It's inflexible? You can store an entire JSON object in a
JWT. That is incredible flexibility. 6) It's not that secure (whereas cookies
in his opinion are)? This is just blatantly false.

Ok, I'm tired of debunking this article. Plain and simple, this article is not
just misinformed but dangerously wrong. I appreciate Sven trying to share his
insight with the community of developers but most of what he says is wrong.

I use JWT for stateless session management backed by some clever database
optimizations (at least I like to think so). If you want to know more ask, but
please, do not use this article to guide your decision on whether to use JWT
(or a similar secure token scheme).

------
vladgur
Ill chime in with my $0.02

* Inability to invalidate stateless JWT tokens can be more or less be remedied with a short expiration time of the token and a token refresh flow. If a token is only valid for 5 minutes, and you can only refresh the token during that 5 minute window, it greatly reduces the attack vector. If that risk is too high, you should easily implement state with the same Redis setup that author mentions

* a classic CSRF example where youre logged into your app in one tab and you open a malicious link in another tab is not a threat if you, like the author suggests, use cookies for storage, but not for authentication. If you pass a token around in an "Authentication" header and have the server IGNORE the cookie which will inadvertently be sent, the request made in another tab via a malicious website is not going to be authenticated.

There are definite Usability and security pros to using Session cookies for
storage:

* Unlike Session Storage, the cookies are visible by your application if you have two instances of it running in different tabs/windows.

* Unlike Local Storage, session cookies get wiped out when the user closes their browser

~~~
rahkiin
If you give the tokens an expiration time of 5 minutes, the application either
needs to auto-request a token every 4-5 minutes automatically using a
JavaScript timer, or your session times out way too quickly. If you close the
tab, you will be logged out within 5 minutes. That may not be desired in many
applications.

~~~
mstade
You don't have to use a timer, you can also do it when you're about to use the
token, or after the token has been rejected if you're so inclined. I.e. before
you make a request you check the validity of the token and if it's not valid
you refresh it; or if you don't do this validation you'd have to deal with the
server rejecting your token, doing the refresh, and then trying the original
request again.

------
luhn
This articles doesn't acknowledge where JWTs really shine: Authentication
across a cloud of services, esp. a microservice architecture. JWTs allow a
session to be shared across all of the services without any shared state.

~~~
ZoFreX
Your architecture being microservices doesn't change the problems with using
JWTs (or any "session" system based on signing things): you can't revoke them.

I am pretty confident being unable to revoke tokens will start to be a problem
with any sufficiently large websites: you don't just need to scale in terms of
traffic, but also in terms of people doing bad things.

If you're at this sort of scale, adding in another service that validates
sessions is not a lot of work. Either your microservices that need
authentication could have a library added to talk to this service, or you
could put everything that needs auth behind something that validates the
requests as they come in. Vulcand looks like it makes this easy (I haven't
used it personally, but I've worked on a system that works similarly using an
F5 device).

Sooner or later, you _will_ regret not being able to revoke sessions.

~~~
numbsafari
You can (and should) use a revocation list. This is really no different than
doing invalidation/revocation of stored sessions because you have the same job
of sending the session/token ID out to all dependencies. But, instead of
keeping a giant memory store of all sessions in sync across clusters, you only
have to keep a short lived list of revoked tokens. Less noise, less memory,
same difference.

~~~
ZoFreX
Say an account gets hijacked, I want to invalidate all the sessions. How do I
do it? I have no list of all the sessions that are currently out there for
them.

Also: I am thoroughly unconvinced that keeping a short list of data synced
across clusters is in any way easier than keeping a long list of data synced
across clusters. It has the same performance requirements and the same
distributability requirements. Why is this easier?

~~~
wtbob
> Say an account gets hijacked, I want to invalidate all the sessions. How do
> I do it? I have no list of all the sessions that are currently out there for
> them.

The revocation list could include entries of the form (revoke-all-tokens-
before USER TIMESTAMP).

You can also use stateless tokens _and_ store them in a database until they
each expire, and then just list all outstanding tokens for the user in your
revocation list. Nothing says you can't use a stateless token and store it.

> Also: I am thoroughly unconvinced that keeping a short list of data synced
> across clusters is in any way easier than keeping a long list of data synced
> across clusters. It has the same performance requirements and the same
> distributability requirements. Why is this easier?

You have to execute your consensus protocol once for each datum synced across
the cluster. It's cheaper to run that protocol once each for a short list of
items than it is to run it once each for a long list of items. 'Hey everybody,
please invalidate the following item, confirm!' once in a blue moon is cheaper
than 'hey everybody, someone logged in, confirm!' over and over again.

------
kevinastone
I think this assumes that people are switching from server-backed sessions to
JWT. I'd expect instead that most people (and frameworks now-a-days) use
signed cookies instead. Switching to JWT just standardizes that format a bit
to allow non-web clients (like mobile apps) to use a similar session.

I think Armin Ronacher's blog post[0] is a good overview on the benefits of
using signed client storage for session state.

[0]: [http://lucumr.pocoo.org/2013/11/17/my-favorite-
database/](http://lucumr.pocoo.org/2013/11/17/my-favorite-database/)

~~~
CiPHPerCoder
JWT is often used as an implementation of signed cookies.

Also, don't use signed cookies unless you have a crypto expert on staff.

~~~
spriggan3
> Also, don't use signed cookies unless you have a crypto expert on staff.

As opposed to what ? re-implementing cookies from scratch with JWT ? JWT is a
dangerous system because it's even harder to get things right. Cookies and
their flaws have been documented for decades, no need to be a crypto expert to
sign cookies.

~~~
CiPHPerCoder
> no need to be a crypto expert to sign cookies

You literally just said the equivalent of "no need to be a crypto expert to
_implement cryptographic signatures_."

Please don't do that without a crypto expert on staff. They'll be able to
avoid side channels that non-experts will never even imagine. To wit:
[http://blog.ircmaxell.com/2014/11/its-all-about-
time.html](http://blog.ircmaxell.com/2014/11/its-all-about-time.html)

It's just a bad idea all around.

------
homakov
>You are essentially powerless, and cannot 'kill' a session without building
complex (and stateful!) infrastructure to explicitly detect and reject them,
defeating the entire point of using stateless JWT tokens to begin with.

just autoincrement nonce=123 and revoke it any time. Nothing complex about it.

>it can also mean somebody has a token with a role of admin, even though
you've just revoked their admin role.

nobody stores user mode in session, that's what DB for.

>but without the battle-tested implementations.

"I don't know what's wrong but I'm kinda afraid to try".

Best argument so far is that it's indeed longer.

Bottom line: Use JWT for sessions, they are awesome! In Rails we're using
similar mechanism for years already.

~~~
kelson
> just autoincrement nonce=123 and revoke it any time.

Does that revoke _all_ tokens (shared "nonce") or update the token on next
authentication? Would this "nonce" be stored in the database?

> nobody stores user mode in session

That's optimistic: [https://github.com/akagadovskiy/ng-admin-jwt-
auth/blob/maste...](https://github.com/akagadovskiy/ng-admin-jwt-
auth/blob/master/js/authService.js)

> > but without the battle-tested implementations. > "I don't know what's
> wrong but I'm kinda afraid to try".

Battle-tested implementations have dealt with (at least some of) these threats
previously. New approaches often miss the lessons of past efforts, leaving
themselves vulnerable to old attacks.

~~~
homakov
> Would this "nonce" in the database?

Only in revoked list=1,2,5,7 etc. Unlike storing all sessions, you only store
_revoked_ integers which takes way less space and achieves same revocation you
wanted.

> That's optimistic

Nobody _should_ store

> leaving themselves vulnerable to old attacks

Every new line of code is probably a vulnerability. That's life. BTW JWT
indeed had some super stupid bug with alg=NONE before, and I would simply
throw away "header" from JWT

------
pfooti
What I do: I use tokens (rather than cookies), but I don't use JWT, for some
of the reasons listed in the post, such as "can't expire" and "data goes
stale". Instead, after authenticating a user, I issue a long piece of random
(256 bits of random packed into a base64 string) to the user. I use the same
string as a redis key whose value is the actual user ID of the authenticated
user.

That way the front end can pass the token to the back end, I can authenticate
and authorize using the redis data (I could store more data in redis, but
instead I hit postgres for any other data about the user, such as admin roles,
when needed during the authorization process).

It's true that this doesn't make you invincible to CSRF or XSS - any attacker
who goes through the trouble and gets access to the token via MITM (although I
only use HTTPS, that's not a guarantee) or by injecting javascript in the
webapp itself (through user-editable content from a malicious user), that
attacker suddenly has full access to the user's account. Still, it's a pretty
reasonable way to deal with session problems.

I also set expiry timeouts on these tokens and can delete them manually if a
user wants to end all sessions (say on password change). Deleting by value
match isn't super-straightforward in redis, but it's also possible with a bit
of LUA.

~~~
monknomo
I thought you could include a tamper-proof expiration time in the payload of a
JWT token? It also seems like data-staleness could be addressed, perhaps by
including a hash of relevant data and invalidating/reissuing a token when the
hash changes?

~~~
pfooti
You can include a tamper-proof expiration time in JWT, but you cannot early-
expire or extend that JWT easily (you could always pass back a new, extended
one transparently).

But in my system, I just keep expiring the redis key for 25 hours from now
each time I touch it, so users' authentications expire after 25 hours (after
which point they have to go back through username/password or OAUTH, etc). You
can easily change 25 hours to 4 days or a month or whatever.

------
jondubois
JWT makes access control super easy/efficient in some cases because you can
setup middleware functions to block/allow specific connections/requests just
by looking at access rights stored in the JWT token (no need to do database
lookups in many cases).

I disagree about using cookies instead of localStorage. Cookies with the
HttpOnly flag enabled (as suggested in the article) don't work well in some
environments such as hybrid HTML5/native apps (using WebViews) because of
cross-origin restrictions - For an app which runs inside a WebView, the cookie
will not be sent to the server if your script files are served from the mobile
devices' file system - So your server will never get the JWT token in this
case. With localStorage (or a Cookie WITHOUT HttpOnly), you can manually read
the JWT using JavaScript and send it through - I know this opens you up to XSS
attacks but it's a small price to pay.

Most frontend developers accept the fact that if you have malicious third-
party code running inside your app's frontend, that's pretty bad news in any
case. The fact that the malicious code can access a user's JWT token isn't the
worst thing that could happen - At that point, the malicious frontend code
could theoretically do anything it wants with your account by hijacking your
UI.

The simple solution to mitigate XSS attacks is to serve all your frontend
scripts from your own trusted CDNs - When it comes to vulnerabilities, there
is always a tradeoff between CSRF and XSS - Personally, I find XSS threats
much easier to manage than CSRF (it's a smaller attack surface).

Also, you CAN invalidate JWT tokens - You can change the auth key from the
server-side (thereby invalidating the signature of previously issued tokens).
Or you can send JWTs with really short expiries (e.g. every 10 minutes) and
then renew them on an interval (e.g. every 9 minutes) so that the JWT doesn't
expire while the user is still active.

There are a lot of different ways to use JWTs safely. It is not right for
someone to say that a technology is bad unless they are aware of all the
possible use cases for it.

------
neya
I am writing my own framework in Scala and I found a similar good article on
this topic:

[https://stormpath.com/blog/where-to-store-your-jwts-
cookies-...](https://stormpath.com/blog/where-to-store-your-jwts-cookies-vs-
html5-web-storage)

But then, I'm now even more confused as the others here. How exactly am I
supposed to secure my REST API now?

~~~
CiPHPerCoder
Use sessions for client->server and OAuth2 for server->server.

~~~
neya
Thanks!

------
hackerboos
You should probably be using refresh tokens
([https://auth0.com/blog/2015/10/07/refresh-tokens-what-are-
th...](https://auth0.com/blog/2015/10/07/refresh-tokens-what-are-they-and-
when-to-use-them/)) to invalidate sessions on a change-password event for
example.

------
vonklaus
there was an article on here which I found more in depth than this, about why
tokens are a good way to do auth.

Im on mobile, but it was ~6 days ago if someone digs it up. However, I guess I
don't understand what the actual argument is.

Vue js sets the header to auth bearer and pulls from local storage. I have a
token and I verify the id in the payload, the subject which is usetname,
expiration and the issuer.

If we assume this goes over SSL/https what is the attack vector. The other
article (and this) basically say someone can run a script and get the token
_however_ it is pointed out that if soneone can run arbitrary code on your
site or users machine, then you already lost anyway.

What am I missing?

------
biznickman

      Somewhat related to this issue, and yet another potential security issue. Like in a cache, the data in a stateless token will eventually 'go stale', and no longer reflect the latest version of the data in your database.
    
      This can mean that a token contains some outdated information like an old website URL that somebody changed in their profile - but more seriously, it can also mean somebody has a token with a role of admin, even though you've just revoked their admin role.
    

Umm, if you are storing the roles of a user in a JWT token, I think you are
doing things wrong. The point of the JWT token is not to store ALL information
of a user. It's simply a way of identifying the user (their ID) and
potentially offering an expiration on the token.

Personally, I use tokens to make authenticated API calls but the API still
verifies that the user has the required roles to take the specified action.
You can then request user data when they login at the same time the token is
issued to reduce request volume and then cache any user data locally (should
you not want to ping the API server for user data on every request).

Locally they may be displayed as an admin while the cache says so but on the
API server, there's no way for them to make such requests if the role has been
revoked.

The greatest flaw that this article assumes is that everybody loads their JWT
tokens with all sorts of personal info. This is a horrible practice. While
theoretically JWT tokens support this, it's by no means a best practice. In
essence, he's arguing against an anti-pattern which is already a known anti-
pattern.

~~~
alanh
Please, for quotes, use a > and/or asterisks, but not a leading space. That
triggers formatting that doesn’t wrap.

> _This is much nicer_

------
Kiro
How else would you do it if your backend is a REST API and you want to keep it
RESTful? JWT seemed like a good solution until I read this.

~~~
rahkiin
You would do it by adding a Redis server that stores stateful sessions
(mentioned in the article).

I however disagree with most of the points made in the article, and use
stateless JWT myself.

~~~
Kiro
Wouldn't that violate the RESTfulness? I thought stateless was one of the
criterias.

~~~
betenoire
It depends on how you define your terms. If you think of the RESTful API and
the Authentication mechanism as two separate systems, you can have your cake
and eat it too.

We use stateful JWT to "fail fast". That is, we can quickly reject invalid
authentication, but we still look up the hash in the database before we
actually use it. Our systems that do API and Auth are separate enough that the
stateful/stateless distinction isn't useful.

------
grardb
I'm working on a personal project and use JWT for sessions. The main reason I
did this is that my understanding is that it makes it much easier to implement
sessions on mobile apps. Is this true? If so, should I continue using them? If
not, why do I think that, and how can I future-proof my API with mobile apps
in mind?

~~~
floatboth
Doesn't matter. JWT _can_ be read on the client, but it's not necessary. From
a typical client's point of view, the auth token is just a string. Doesn't
matter if it's a JWT or a random string. The difference is on the server side
— checking a signature vs. looking up in a database.

------
andrewstuart2
I'm not quite sure the author of the article has a solid grasp of JWT, or
identity federation in general given that he compares JWT to cookies (it's
more like SAML than anything else). I'd highly recommend giving the RFC [1] a
once-over to see what the spec is _really_ about.

> The correct comparisons are "sessions vs. JWT" and "cookies vs. Local
> Storage".

This is somewhat true, but flawed. The better comparison is "SAML vs JWT," or
"CAS vs JWT." JWT is a claim assertion standard (most often used for ID
claims), and should not be compared with sessions in any way. A JWT (signed by
a trusted authority) is a valid way to start a session, or to hold and
transmit data for sessionless communication.

> They really aren't [easier to use].

Maybe not compared to cookies, but they definitely are easier than SAML2,
which they ought to replace.

> I have yet to see somebody actually explain how JWT is more flexible.

They have flexible claims which require no DTD; SAML does not. Cookies support
this too, but they really shouldn't be part of the discussion.

> Server-side expiration is preferable, in fact - it allows your application
> to clean up session data that it doesn't need anymore

The best part of signed tokens (if you don't mess with revocation) is that you
don't remember _any_ data. You perform an identity lookup, authenticate the
user, generate and sign the token, and send it off. No need to keep any data
around at all, much less handle the complexity of cleaning it up.

> It doesn't, really. There are roughly two ways to store a JWT:

The way JWT solves CSRF is not by the way it's stored; it's by the way it's
transmitted in an Authorization header, which can't be done cross-domain and
won't be included by the browser (as cookies would). If you're not using JS,
you shouldn't be looking at JWT at all; it's useless without it.

> Users don't just block cookies, they typically block all means of
> persistence.

Unless they're blocking JS (which would render the whole article moot anyway),
then there's memory persistence for as long as the browser hasn't refreshed.
This is more than enough persistence to realize the benefits of JWT (talking
to multiple backends, SPA experience, etc.) Yeah, it's gone when you refresh
or navigate away, but some might call that a feature. Just re-authenticate
with the JWT provider and keep going.

> JWT tokens are not exactly small.

They're as small as a secure cookie: metadata header + data + signature.
That's it. And they don't need to be communicated as part of the URL (though
it's deliberately safe to do so), and should not be communicated via cookie
(eliminates CSRF benefit).

> They are less secure

Not if they're signed and validated against trusted issuers. Which they should
be. Heck, they'll even be encryptable (in a standardized way) soon. [2] Then
even the browser they're sent to can't see what they contain unless it has the
private key.

> You cannot invalidate JWT tokens

Yes, you can. Use revocation and check with the authority. Just because it's
not specified doesn't mean you can't use long-standard methods (see CRL [3])
to achieve your design requirement.

> Implementations are less battle-tested or non-existent

As with any new technology, implementations are also new. Just like I don't
have 5 years of experience with Angular 2. And a quick glance at jwt.io will
show you that there are _plenty_ of implementations available for a huge swath
of languages.

Seriously, read the spec, know your use cases (JWT is not a session
replacement, though it could function similarly), and learn the crypto
primitives that make this secure (JWT provides verifiable integrity via
signatures, not confidentiality (yet) and leaves that to other layers (until
JWE)).

[1] [https://tools.ietf.org/html/rfc7519](https://tools.ietf.org/html/rfc7519)

[2] [https://tools.ietf.org/html/draft-ietf-jose-json-web-
encrypt...](https://tools.ietf.org/html/draft-ietf-jose-json-web-
encryption-40)

[3]
[https://www.ietf.org/rfc/rfc5280.txt](https://www.ietf.org/rfc/rfc5280.txt)

~~~
zeveb
> The way JWT solves CSRF is not by the way it's stored; it's by the way it's
> transmitted in an Authorization header, which can't be done cross-domain and
> won't be included by the browser (as cookies would). If you're not using JS,
> you shouldn't be looking at JWT at all; it's useless without it.

This isn't quite true: JWTs may also be transmitted as an access_token URL or
form parameter. As such, they are not useless without JavaScript (which is
good).

> > JWT tokens are not exactly small.

> They're as small as a secure cookie: metadata header + data + signature.
> That's it.

They're in a sadly verbose format, which by its nature tends to lead to
double-Base64-encoding values. There're a lot of double-quotes and commas,
which isn't wonderful. It's not a colossally-wrong format like XML, but it's
not great. And it's not terribly readable, despite being somewhat verbose.

------
meowface
JWTs do have plenty of valid uses.

I definitely agree with this point, though:

>If you are concerned about somebody intercepting your [anything], you should
just be using TLS instead

It's weird to see a lot of devs try to reinvent the wheel and do some kind of
half-assed transport encryption when they could just use TLS.

------
cortesoft
This part:

"In practice, however, it's fairly trivial to replace the session mechanism at
a later point, with the only cost being logging out every user once, when you
make the transition."

Is not true in terms of needing to log everyone out once. It is pretty easy to
write transition code, to accept the old style session and return the new
style. You might not be able to transition everyone (if they don't use the
session in the time you have your conversion code running), but you will get
MOST people, and certainly most active users.

------
ubercore
So, I've been approaching JWT as a "proof of login" essentially, to handle
authentication across web, mobile apps. The only payload I use is relevant to
identifying the user logged in. Session data would be handled by server-side
code, though it's still early days for me so I haven't had a use for it yet.

After reading this, I'm wondering if I'm misusing JWT, and should replace it
for the use-case of authenticating API calls are coming from an identified
user in a client agnostic way?

~~~
joepie91_
From the sounds of it, you're essentially using stateful JWT tokens. In that
case, I'd recommend using a battle-tested session implementation for your
stack of choice instead, if there is one - this rules out implementation
errors or overlooked security issues on your end. Security can get pretty
tricky.

The exact token scheme you use shouldn't matter for the client. As long as the
client supports cookies in some way, it'll just treat it as a dumb blob of
text - only the server needs to care about _how_ to interpret the session
token.

~~~
ubercore
I'm using actionhero for the backend. To be clear, I'm not concerned about
_sessions_ so much as I'm concerned about authenticating all requests. I guess
it's just still not clear to me based on the article and your feedback what
the flaw is checking a valid JWT in the Authorization header to identify the
user making the request? Other than the relative inability to invalidate
sessions (ie, only hacky methods for achieving this)

------
tszming
While several points in the article are arguable but I agree not using "JWT
for managing user sessions in their web applications". If you need to add
extra / custom / unproven mechanisms to invalidate JWT tokens and this defeat
the purpose of the simplicity of using Stateless JWT - people are using sticky
sessions or session servers to solve the scalability problem of user sessions
in web apps pretty well and most frameworks bundled battle-tested libraries to
do so long time ago.

------
uNki
my approach: after authentication i'm generating a JWT and send it to the
client that stores it in LocalStorage. On the server side I'm using a
memcached database that stores a key-value-pair (JWT and some config stuff
that shall not be visible on the client side..) for 30 minutes and then
deletes it. The JWT is sent with every client request in the Authorization
header. A function checks if there is any key-value-pair in the memcached
database that matched the JWT (key) and if that JWT is valid. After that it
continues or denies the request. The client requests a new JWT after 29
minutes. If the client is offline and doesn't request that new JWT, the old
JWT is killed after 30 minutes, anyway. I can't see any other attack vector
than XSS - which I'm trying to avoid as hard as I can. But lets face it: IF
you have a XSS problem, then you'll have it anyway, with JWT or without. If
someone has full access to the JavaScript of your website, he/she can capture
any authentication data you are going to send over the wire, unless you use
cookies (where you'll have the CSRF problem..).

SO, I think it's pretty safe if you get your XSS protection right.

Opinions? Thank you :)

------
cel1ne
Postgrest ([http://postgrest.com/](http://postgrest.com/)) uses JWT to switch
between database roles.

------
arekkas
Except for local storage the information in this post is useless and partially
false.

------
fabian2k
The one thing that I found scary when reading up on JWTs is that there is no
way to revoke them. Of course you could check them against a list of revoked
tokens on your server, but then your lose the stateless aspect. So the only
remaining option to revoke a JWT is the nuclear option, invalidating all JWTs
at once.

This seemed like a rather large limitation to me. Related to this, the ability
to encode further information in the token, e.g. access rights suffer from the
same flaw. If I use the tokens themselves to grant different privileges on a
site, I can't revoke those privileges.

I've never used them in practice, this is all just from reading about JWTs.
How do people deal with those aspects in practice?

~~~
bjt
JWTs _can_ be revoked if you sign them with application_key +
some_user_revocation_string.

This is how password reset tokens work in Django, for example. They're signed
with the app's secret key + the user's existing password hash. Once the user
uses the token to change the password, the token is no longer valid.

~~~
Normal_gaussian
However every service now needs access to the list of hashed passwords.

~~~
bjt
Or access to a service that has access to the hashes/revocation strings. Which
puts you in a similar situation to non-JWT scenarios where every service has
to phone home to check a token's validity.

I'm not saying all tokens should be made revocable in this way. I'm saying
that people claiming "you can't invalidate a JWT" are overstating their case.
If you really need to do invalidation, this is one option.

------
bricss
So, we should use mint vaseline for session?

------
arisAlexis
1\. Mobile sessions are not realiable

2\. You dont need to run redis (with service discovery!)

I fail to see cons.

------
mythz
This article seems opinionated without much substance and I disagree with many
of the points listed. It also doesn't address using a JWT Token in a Cookie
for Web Apps as recommended at:

[https://stormpath.com/blog/where-to-store-your-jwts-
cookies-...](https://stormpath.com/blog/where-to-store-your-jwts-cookies-vs-
html5-web-storage)

And ignores usage of refresh tokens: [https://auth0.com/docs/refresh-
token](https://auth0.com/docs/refresh-token)

    
    
        Easier to use
    

JWT's are simpler when your System is composed of multiple Services as only a
single Service needs to issue JWT's and provide Auth Services, all other
isolated Services only needs to know how to validate a token and doesn't need
other Session State or Auth configured yet are still able to provide protected
Services.

    
    
        More flexible
    

JWT's allow for externalized, centralized Auth where the issuing of the Token
can be decoupled from validating it. It lets you easily launch new Services
offering Protected API's out-of-the-box without needing to configure any Auth
or persistent Session state.

    
    
        Data goes stale
    

Services that care about stale data embedded in JWT's should hit the DB using
the UserId embedded in JWT's, this is more "live" then accessing it from a
Session which is stale from the moment the Session or JWT is created.

    
    
        More secure
    

It's not less secure, and one instance where it can be more Secure if you use
RSA as the centralized Auth Service can sign JWT's with its private keys and
Services validating tokens with only a public key. So JWT's can be
cryptographically verified it's been issued from a central authority with
access to the Private Key. Whereas authenticity of Session data is not
verified and can be tampered with anyone with access to the session data
store. The recommendation is to use Redis which offers weak security since
it's not supposed to be accessed externally so uses a simple password which is
sent plain-text over the wire.

    
    
        Built-in expiration functionality
    

"This is nonsense, and not a useful feature." Unhelpful Opinionated assertion
slinging. Embedded expiration could be a simple constant or implemented from a
Custom policy based on the User. Since this is decided by the Issuer this
logic only needs to exist in one place.

    
    
        Works for users that block cookies 
    

"Unlikely. Users don't just block cookies, they typically block all means of
persistence." Not sure where the article gets its fact checking from, but this
is another opinionated assertion not backed by any sources. Cookies are
blocked due to privacy issues, whereas Local Storage is used a lot more for
providing rich Web App functionality. Disabling Cookies definitely does not
also imply disabling Local Storage.

    
    
        They take up more space
    

The space trade-off is due to enabling a more performant, scalable and
flexible stateless architecture.

    
    
        You cannot invalidate JWT tokens
    

Another strong assertion that is false. You can include any mechanism you like
to invalidate tokens, e.g. you could embed a unique JWT Id
([https://tools.ietf.org/html/rfc7519#section-4.1.7](https://tools.ietf.org/html/rfc7519#section-4.1.7))
to check against a blacklist loaded in App Servers memory. Your JWT
implementation could have an option to "Invalidate all JWT Tokens issued
before certain date" which is similar to flushing a Session storage, i.e. all
JWT/Sessions created get invalidated. The simplicity and statelessness of
JWT's makes it easy to apply custom generic logic.

~~~
homakov
What's refresh token for?

------
bricss
Facepalm

