
Use JWT the Right Way - 0xmohit
https://stormpath.com/blog/jwt-the-right-way
======
jwtadvice
This is a pretty low bar on JWT advice.

Here are some more:

* Make sure that you use JSON.parse to handle incoming JWT bodies if you are writing custom JS code. Using any eval() derivative function opens up XSS

* If you include any strings from a user into the body of your JWT, for example as part of a claim, you must output encode and input validate that data to make sure the result is a valid JSON object in which only the claim expected was modified (think of inputs such as "my address', exp:'never', username: 'admin").

* Your server side code must actually check the claims inside your JWTs. This is really an awfully common thing not to do.

* If using access tokens (or other such tokens), know that there are two tokens, an id_token and an access_token. Endpoints may expect both, so that they can use the id_token to obtain a principle and access_token for credentials. It is important that the server code checks that these tokens belong together (at_hash for access_tokens, st_hash for security_tokens). Otherwise the theft of a user id_token implies a malicious user can auth with it even if their access_token is for a different user.

* Look for open redirects in your JWT-application, fiercely enforce CORS, etc policies. Know that session fixation attacks plague OpenID Connect, OAuth, etc.

~~~
omgitstom
Always happy to get feedback. Again, this article was written back in 2014,
and will be updated.

In regards to your advice about id_tokens and access_tokens. Usually, what
I've seen in most attacks is that if a malicious user can get one, they can
get both.

A lot of your points though are valid outside of using JWTs. Open redirects
vulnerabilities should be plugged and sanitizing user input should be looked
at regardless of what you are using in a web application.

~~~
jwtadvice
Agreed everywhere.

Users tend to be looser with their id_tokens (for example posting on forums,
stackexchange, etc) than with access_tokens because they understand the
access_tokens are credentials whereas the id_tokens are (technically) not.

Definitely open redirects and the session fixation problems are not JWTs
specifically - it's just that they tend to plague applications that use JWTs
for transport. I admit it's kind of like telling people that talking on the
phone while driving is a bad way to use your seatbelt. It's true - but maybe
not scoped enough.

------
Kiro
> These tokens are usually signed to protect against manipulation (not
> encrypted) so the data in the claims can be easily decoded and read

Is this really true? I mean, if you can decode the token you must have access
to the secret anyway?

From [https://github.com/auth0/node-
jsonwebtoken](https://github.com/auth0/node-jsonwebtoken)

    
    
        var token = jwt.sign({ foo: 'bar' }, 'shhhhh');
        var decoded = jwt.verify(token, 'shhhhh');
        console.log(decoded.foo) // bar

~~~
nbarbettini
Encoding != encryption. This article isn't discussing JWE (JSON Web
Encryption), but rather JWS (JSON Web Signature).

These tokens are base64-encoded and signed. They can be decoded easily, but
not forged or altered without knowledge of the secret key.

------
ejcx
Just to be a little bit pedantic about the article.

    
    
        Do not contain any sensitive data in a JWT.
    

If there's nothing sensitive in the JWT then why might we encrypt it?
Sometimes the whole purpose of a JWT is to pass some sensitive auth
information whether as a session cookie or an authentication token that a
service uses.

    
    
        If you worried about replay attacks, include a nonce (jti claim), expiration time (exp claim), and creation time (iat claim) in the claims
    

This isn't always the case... One of the reasons JWT is so powerful is the
asymmetric key operations built in to the spec. If some JWT generation and
signing body signs a JWT and someone else steals the JWT, all consumer
services of the signing service are vulnerable to a replay attack. The JWT is
valid for use at ALL consumer services.

If you have symmetric keys and are encrypting/signing a JWT to communicate,
and you want to prevent replay attacks with a JTI and EXP, you've lost the
stateless property of JWT in order to do it correctly, and you haven't solved
the problem of using the JWTs at OTHER services. It only works for 1 to 1
communication.

If you're preventing replay attacks inside of a JWT you've chose the wrong
battle and you've decided to design a cryptographic protocol on top of JWTs.
Don't pick this fight. Just go home.

    
    
        The secret signing key should only be accessible by the issuer and the consumer
    

This won't be the case for asymmetric keys. Services that create JWTs and sign
them for other services to verify should not share the private key with other
services. This is basic crypto but if someone reads this ONLY this article
they may not know.

~~~
omgitstom
Thanks, Evan. these are all good points, I'm surprised to see this on HN since
it is an old article I wrote.

In regards to the replay attacks, if you are using JWTs in a 3 party setup,
and they are validating JWTs locally (not sending them back to a validation
endpoint), the jti claim won't be enough.

Thanks again for clearing that up! Considering this blog post may still have a
use, I'll update it soon.

~~~
ejcx
Heheheh, no problem. I recognized it was your article, Tom. Sorry to be
pedantic. Jose is really just way too complicated. Go Dukes!

~~~
omgitstom
Definitely not pedantic! Believe it or not, JOSE was still a draft when this
blog post was released into the wild.

------
m4tthumphrey
I love the idea of JWT but I don't understand how you would use them to store
a lot of information, as the token it self would balloon in size. For example
using a JWT to authenticate an API request. The JWT would store a user ID and
a list of permissions. What if a user has 100 permissions? The token is going
to get huge....? Unless I'm completely misunderstanding how to use them.

~~~
aleem
JWT should not be looked at as a session replacement. For example, you cannot
invalidate a JWT token before it's TTL. If you really wanted, you'd need to
manage a blacklist of tokens on the server and compare every token against
that list which would defeat the purpose of JWT's scalability benefits.

You can, however, come up with other strategies like switching up 100
permissions for 10 permission groups and similar ground-up designs which are
JWT-friendly.

~~~
15155
> If you really wanted, you'd need to manage a blacklist of tokens on the
> server and compare every token against that list which would defeat the
> purpose of JWT's scalability benefits.

The blacklist approach does presumably incur network latency, however, the
amount of overhead/space for the blacklist is going to be substantially
smaller than the total set of JWTs.

Also: the blacklist only needs to be maintained until a blacklisted token
naturally expires, further enabling performance.

Any number of stores or structures would be suitable for the maintaining the
blacklist: Memcached, Redis, even a bloom filter (especially if tokens aren't
regularly blacklisted) will suffice.

Granted, there are tradeoffs, and at this point, traditional sessions probably
make more sense, but it s at least possible.

It's much easier to scale recall from a (likely) small blacklist of token IDs
+ TTLs than all sessions, everywhere.

