Hacker News new | past | comments | ask | show | jobs | submit login
How to Use JSON Web Tokens (github.com/dwyl)
260 points by ristem on Jan 2, 2019 | hide | past | favorite | 128 comments



JWTs are useful, but there are a few things that are not immediately obvious.

1) They are signed not encrypted. Anything you put in there is public readable, unless you encrypt your token after you generate it

2) you can accept a range of encryption types, don't. Stick to one type and disallow any token that doesn't conform (this protects against people making their own tokens with 'None' as the signing algorithm)

I am surprised at how naive the JWT spec is. Why in this day an age is encryption a default for the _payload_? Also, why on earth is 'None' allowed as a signing algorithm? Thats just a cookie..


There are also a number of easy-to-make mistakes or gaps which can be introduced with the use of JWTs.

https://twitter.com/ejcx_/status/1063846166029197312 provides a great list of test cases covering the commonly reoccurring flaws.

The number and seriousness of these errors and how easy it is to make them does raise questions about how sensible it is to use JWT, unless you're really sure about what you're doing.


There are a number of easy-to-make mistakes with all security software. That doesn't mean it's not worth using; it just means that we should build the tooling we need in the open as shared software, so that the wisdom of crowds prevails.

Almost exactly the same set of problems exists with signed x509 certificates, but I doubt anybody would tell you not to use them. They'd just say "make sure you don't implement your own validation, unless you absolutely have to, which you don't, and even then only with lots and lots of review/audits." The wisdom with JWT should be the same, IMO.


In the context of security analysis, this is a vacuous statement. There's almost always something you can do to screw a security construction up. An important goal of security engineering --- and the overriding goal of modern cryptography engineering, in particular --- is to minimize the set of things that can go wrong. This is why we generally feel safer deploying Rust and Go code than C code, why we use Curve25519 instead of the NIST P-curves, and why crypto engineers generally recoil from JOSE and JWT, a set of standards that seem to have gone out of their way to maximize what can go wrong.

As a telling example, compare JWT to Macaroons, a standard built effectively on one extraordinarily simple cryptographic primitive that is simultaneously safer and does more than JWT.

From the vantage point of cryptographic security engineering, JWT is a cargo cult. Most projects would be better off avoiding it entirely.


To be honest, and with all due respect, avoiding JWT outright feels a lot like a cargo cult to me. I have yet to see a solid argument against JWT itself, aside from the criticisms you just gave of "it doesn't minimize the set of things that can go wrong." In reality, that statement is like saying "x509 doesn't minimize the set of things that can go wrong."

The criticism is leveled at JWT as if the JWT spec attempts to be anything but "a compact, URL-safe means of representing claims to be transferred between two parties," to quote the spec. I think JWT is better understood as what it intends to be, a simple standard for easily-understood claim sets, that more finely detailed, granular, and secure standards can be built atop.

Admittedly, I'm reading about macaroons for the first time, but from what I can tell they're a higher level concern than something like a JWT. I'm not sure I would actually try it, because it wouldn't be very efficient, but I'd wager you could implement macaroons securely, using JWT as the container for the claims (including claimed constraints) and HMAC signatures.

Maybe I'm totally off base, and if so I'd love to take the time to understand how, but I don't see how JWT as the tiny spec it is, or JWS/JWE, again rather small specs, have done anything to maximize what can go wrong, as much as they are deliberately reducing their surface area to be composable, and to allow other standards to compose them into more secure, minimally faulty specs.


I'm not sure how you can "cargo cult" not casually adopting some random piece of technology. The Pacific cargo cults transformed incidental interactions with modernity into religious venerations; aboriginal islanders got free supplies from visiting GIs, believed the experience to have been supernatural, and built wooden airplane replicas as idols in hopes of summoning those benefits anew. The comparison to JWT is pretty clear: people add these coconut phones to their applications in hopes of gaining some ineffable "cryptographic security". Meanwhile: the cryptography engineers look on in baffled wonderment.

I've written many, many times on HN about problems with JWT and I'm by no means the foremost critic of the standards. Here's a starting point:

https://news.ycombinator.com/item?id=14292223

I don't know anyone competent who believes the JWT/JOSE specs to be "tiny"; for instance, they incorporate X.509.

Here's a piece we wrote last year that goes into the tradeoffs between different inter-service auth mechanisms (including Macaroons), and discusses the various attributes you might, in the abstract, get from them:

https://latacora.micro.blog/2018/06/12/a-childs-garden.html

The problems JWT attempts to solve are harder to solve outside the inter-service auth context.

You are, respectfully, totally off base.


I'm disappointed. From your reputation and from having heard you speak on podcasts, I expected a bit more enlightening and friendly conversation than condescension and subtle insults.

Regarding cargo cults around an opinion, consider this scenario:

1. Be a successful public figure in some domain.

2. Share opinion related to said domain.

3. People elevate opinion itself because of relation to successful individual without adequately examining and understanding the facts.

I'm not saying you're wrong, but I am saying I'm not satisfied with the arguments I've seen. The JWT spec (specifically, the RFC) simply leaves many decisions up to people building on top of it. Given its flexibility, I fail to see how any of your arguments preclude it from being used as part of a stricter standard that is more "misuse resistant."

Regarding blind buzzword acceptance, though, that's a human problem, not a technology problem. If something is useful, and intuitive enough that it gains popularity, I can guarantee that many people will find a way to misuse it while stamping the buzzword on their resume.


I believe the point being made is that flexibility is itself a misfeature that enables misuse. While you are absolutely correct that JWTs could be part of a stricter standard less enabling of misuse, they do not themselves constitute such. And for many purposes, other more specialized and suitable standards (such as Macaroons) already exist.


What podcasts have you heard me on? I think I've guested on one in my entire life? (Podcasters: invite me!) You might have me confused with Marco Arment.

I don't think you've written anything else here that I haven't already responded to with the links I've provided or things I've written in this thread, and don't see much point in repeating myself.


Shoot. I've gone and mixed you up with Patrick McKenzie. If I remember correctly, he must have talked about your interactions a lot on that particular podcast. My mistake.


Saying "all security software has flaws" advantages the software with the most flaws and disadvantages the software with the fewest number of flaws. There are many, many better solutions for the problem JWT solves, there are not many better solutions for X509, which is why people keep using X509.

It is significantly more difficult to misuse e.g. golang.org/x/crypto/nacl/secretbox than JWT.


I never said "all security software has flaws," since that has a substantially different meaning than my comment.

While I'm not arguing with your statement regarding ease of misuse, you should also consider the trade-offs. It's also significantly easier to misuse a pocket knife than a butter knife for the same reason. Butter knives are designed for a small set of problems and deliberately have duller edges to avoid some of the potential downsides of pocket knives. That doesn't make pocket knives useless, it just means that you might need to be trained on safely using a pocket knife, whereas I'm totally comfortable handing a butter knife to my four-year-old. If you're going to be trusted with security, you're really going to need either a) a sharper knife, or b) to understand which knives you're okay handing to your coworkers, or c) to be able to train your coworkers on proper knife safety so they can also use the more flexible tools, but still safely.


Well the good news is I've written about this exact subject at length!

I have seen JWT implementations at five or six different companies now, tokens have never been used for more than one use case. For each specific use case you'd actually want to use it with there is a better solution that doesn't involve JWT, like secretbox or HMAC-SHA256.

https://kev.inburke.com/kevin/things-to-use-instead-of-jwt/


You might be happy to see the PASETO spec, which (for v2) uses XChaCha20-Poly1305 for encryption, Ed25519 for signatures, separates the two logically, and doesn't allow for runtime ciphersuite negotiation. (v1 achieves a similar result with AES-CTR+HMAC-SHA384-EtM and RSASSA-PSS.)

https://github.com/paragonie/paseto/tree/master/docs/01-Prot...

It's similar to the advice given above, but also caters to that itch that some project managers have to only implement industry standards (which PASETO is slowly becoming).


I don't think X509 or public key crypto is as scary as it looks, once you understand what you're actually dealing with and how the openssl related libraries work.

There is definitely a UX issue though, and—without intending to be disrespectful—junior devs coming into programming through Javascript, or building basic microservices, are going to see a lot written about JWT and how easy it can be to work with, and suddenly JWT is the solution.

The API for JWT in most cases is encode/decode, and you provide the payload, the options, and the key. The API for libraries linked with OpenSSL is typically a lot more verbose, so you have to understand what you need to work with, or how you might need to extract a fingerprint, convert to DER, or whatever.

Beyond that, a lot of us in the web world might associate X509 with SOAP and XML, and plenty of people will avoid XML at all costs by virtue of it being XML. There's no reason why you couldn't use X509 in a JSON payload.


I'd like to hear more about why X.509 and public key aren't scary, when the prevailing attitude in the crypto engineering community is that they're terrifying sources of surprising game-over vulnerabilities. How many people do you think there are in the world that can reliably and safely evaluate an arbitrary X.509 document in a de novo implementation?


You aren’t required to be competent to put out a spec. Just join a committee.

Did you ever look at the XML digital signature spec? You could drive a freight train through the holes in that one. One guy did an entire conference presentation on the ones he found (took me about a year to find nearly all of the same ones and a few more).


You can have unsigned, signed, or encrypted JWTs. You're correct that many JWT libraries only do signed tokens by default, but there's a whole spec devoted to encryption: https://tools.ietf.org/html/rfc7516 (whether or not your library of choice implements it is a separate question)


This is one of the things I truly appreciate about JWT. They made it a) easy and b) possible to do signing, encryption, or both. If you've ever taken a shot at learning the specs behind SAML, the simplicity of JWT is hugely refreshing.


I wholeheartedly agree. I've had the opportunity to use both implementing a single sign-on solution with an ADFS server, and it is quite interesting to see how OpenID Connect and JWT basically do what SAML and the ADFS SSO authentication flow do; just with a much, much smaller payload and a way more accessible standard.

Also, finding information and documentation on JWT and related technologies on-line is a lot easier.


Thank you for comparing it to SAML. I feel like anytime JWT is mentioned on HN people jump to discard it as rubbish, but really it's useful for people who actually need to exchange claims.


To be clear, cookies are an HTTP header field that can carry any text data you want. You can pass plain text, JWTs or any other encrypted payload (which many web frameworks do automatically).

JWTs aren't comparable to cookies, they're just a standard way to sign data.


His or her point was that if you don't sign and/or encrypt, there's no benefit over a standard cookie.


not sure if that was the point or not, but it's wrong. even if you did sign/encrypt, that's not a benefit over a standard cookie. you can easily sign or encrypt a 'standard cookie' as well.

the benefit is the portability that comes from a standardized and widely used data structure.


You say that as if cookies haven't been a standardized and widely used data structure (key-value store) for decades.


No, they say it as if cookies don’t have a built in authentication or encryption method (when the client is untrusted).


My point was that allowing 'None' was/is a flaw. If you want to shuttle bits of data about in an unsigned/unencrypted/insecure way, that's what raw cookies are for.

Now, as cookies are buckets to dump data, there is of course nothing to stop you encrypting, signing and doing all sorts of things to cookies.


> 1) They are signed not encrypted. Anything you put in there is public readable, unless you encrypt your token after you generate it

Not a JWT expert but isn't this the point of a JWT or am I missing something. Sharing data between servers & clients while being able to make sure the data wasn't changed.

> 2) you can accept a range of encryption types, don't. Stick to one type and disallow any token that doesn't conform (this protects against people making their own tokens with 'None' as the signing algorithm)

People do this?? Why?


> Sharing data between servers & clients while being able to make sure the data wasn't changed.

I think the main use is sharing data between the server and itself. The client shouldn’t depend on the internal structure of the token. The token should just be issued by the server to the client, and the client passes it along to subsequent requests to the server.


Both good points!


Re 1), yes, it is the point, but it's not necessarily clear to everyone who looks at JWT as a solution to whatever problem they have. At a glance, a JWT looks like a binary blob. And there are cryptographic algorithms involved. So it's not a surprising leap for a newbie to assume JWTs are encrypted blobs. Introductory JWT texts rarely make this clear.

Re 2), JWT libraries often make it easy to ask "is this token valid?" And I don't think it's unreasonable to think that "validity" means "signed by the shared secret I set in this library's configuration". But it usually doesn't. It usually means "this token is internally consistent". And since alg=None is a an option most people would probably assume would not exist, much less be counted as "valid", then it's not surprising that this happens.

Basically, JWT's rendered format ensures it will be misunderstood and misused, so long as the available libraries don't enforce reasonable expectations. And from what I've seen, the library situation for JWT is pretty ugly, making a confusing standard even more confusing, instead of less so.


Libraries did that. Most now guard against this by forcing the developer to explicitly enable the 'None' algorithm. Normally you don't need it, and certainly never in production.

But yeah, if your server accepts JWT's, reject anything that doesn't use an algorithm from your whitelist, which usually contains just one entry.


Most libraries do guard against this. But the point of a "standard" like JOSE/JWT is that you don't have to depend on a library; you should be able to consult the spec and build your own library. And, of course, alg:None is yet another pitfall that JOSE pointlessly opts you in to; it's yet another thing you need to know to safely implement JWT (it's far from the trickiest thing you need to know!)


As mentioned in the article you might want the token to be read by the users. Such as issuing a token with a expiry date that you want the user to regenerate. Although If anything the JWT libraries should have encryption enabled by default.


It can also be helpful if:

- your system is distributed

- you don't want to be keeping a decryption key secure and in-sync across many (and potentially less-trusted) nodes

- the JWT contains attributes useful to the system (e.g. role, user ID, etc.)

You'll probably still be keeping track of a public key of whatever's signing it (to verify authenticity), but that isn't a secret. And then you can still securely trust


> your system is distributed

if you don't have a shared data store, or its not fast enough, then you're doing the wrong thing with the wrong tools

> you don't want to be keeping a decryption key secure and in-sync across many (and potentially less-trusted) nodes

keeping shared secrets, which are very high read:write ratio, and change daily or less, should be childs play. If its not, then your security protocols are wrong. Key rotation must be simple and quick if you want your system to scale. When you get to 100 people, you'll be leaking keys weekly.

KMS, Vault and a few others are your friend here. There are off the shelf systems for this.

> the JWT contains attributes useful to the system (e.g. role, user ID, etc.)

having these public can be alright, assuming that you've properly mapped, scrubbed and checked for leakage. However, you shouldn't be reliant on user supplied stuff for this. You simply cannot trust the user.

If you need jwt for caching data, then you have a much bigger architectural problem. The stuff you are storing in JWT needs to be easily and quickly accessed. If its not, you either have a DB or a messaging system issue.

Now, if you are encrypting the whole token, then its less of an issue. But, using it to store anything other than a UUID and a issue time, you are asking for trouble.


> Why in this day an age is encryption not a default for the _payload_?

Why would it be? Why not encrypt the disk and use SSL?

Doing encryption right can be enormously difficult; why not use the transport/storage technologies that are ubiquitous?


You're right. Doing encryption correctly can be incredibly difficult and complex. Enough so that people might miss important subtleties of the technologies at hand.

For instance, you may want the encryption of data-in-transit to be removed by the application, rather than by whatever is responsible for TLS termination. You may not want your load balancer to be capable of reading the most sensitive data of your request.


IDK what the details are there, but if you trust your TLS termination point with most data, it seems like you'd trust it with the JWT payload too.


I understand why a person might opt to think in that way! It's an obvious approach when people fully trust every part of their systems.

It's perhaps possible some might differ, especially in a context where limiting trust and misuse-resistance are concerns. Giving people the choice of encrypting or signing or both could seen by some as potentially less than maximally misuse-resistant.


> unless you encrypt your token after you generate it

Generally it's better to avoid unauthenticated encryption. That is, encrypt-than-sign, not the other way around.


This is a good Javascript-centric writeup. This caught my eye thought:

> Since JSON Web Tokens (JWT) are not signed using asymmetric encryption ...

You don't have to, but can of course sign your JWTs with asymmetric keys, and many libraries support this. Third party token issuers (firebase, google, auth0) require asymmetric, since they're clearly not going to share a secret with you.

Asymmetric also provides two-way token verification: The issuer signs the token with a private key, and receivers of the token can then verify that the token is legitimate using the issuers "well-known" public key.


I've dealt with and used JWTs in a few different applications, and all of them have used assymetric keys, and used as tokens passed between different systems. Keeping the private key only on the issuing system is more secure (or even essential, depending on what you're doing).

If you're authenticating on the same system, you could get away with symmetric, but then the use of JWTs may no longer make sense vs just using a random key stored persistently on the server (eg, for session cookie, "remember me" or "forgot password" token) -- I actually can't think of a case where using JWTs makes sense if you have access to persistent storage. By storing the random value you can also revoke it server side, which you can't do normally do with JWTs.


At first JWTs look cool because you can log in users without managing session data on the server.

Then you think about how a user can actively log out.

Then you add session management to your server but call it 'token invalidation'.


This is a problem you have with any federated token-based identity solution. Distributed logout is a hard problem which can basically be reduced to cache invalidation (insert N/N-1 hard things in CS joke here).


This is a little like saying "this is a problem you have with ANY identity solution that looks like JWT". Yes, that's true. The reason people complain about JWT is that (a) it's the most popular solution of this shape, and (b) people use it without understanding why they're using it or whether the tradeoffs work for their application. They usually do not.

Witness everyone saying that the important feature of JWT is that it's standard and interoperable, as if that was a mandatory feature of most token-based authentication schemes; in fact, the "portability" of JWT is a security liability for --- I'll hazard --- the overwhelming majority of applications.


Would you say then that confidentiality is always preferable to availability? I'm not quite sure how you'd achieve any sort of high availability over time without interoperability at some level. Presumably, if it has any place, that interoperability would belong at the lowest level of a protocol stack, with each successive level tuning acceptable parameters for their application.


I don't understand this question. I don't think it's very common in real-world applications to deliberately trade confidentiality for extra availability, though negligently and subtextually making that trade is endemic to our industry.


I just mean availability in the sense of client support across time as protocol versions increase, like TLS version negotiation and how it enables the gradual rather than immediate dropping of server support for clients on older versions of a spec. Or for example, allowing 2048 bit keys for a time to allow migration to stronger keys.

Without negotiation, you'd have to stop serving clients that haven't upgraded at the cutover time.


This page doesn’t have any discussion of strategies for expiring JWT, one of the biggest security issues with this auth mechanism. Even the code sample doesn’t include an expiration.


The JWT has a built-in field called exp, which is the time the token is expired. This is built in.

However if you need to 'expire' a JWT token early, there isn't a good way to do it. If your token has a JTI, then you could add a blacklist for that JTI (say in redis, with a TTL until the token's exp time). But that is left to the implementor.


My issue here is that expiring JWTs involve adding state! The whole point of JWTs is stateless authentication, so I’ve never understood the advantage over sessions unless revoking tokens is never an option.


Invalidation of any sort, including token revocation, is fundamentally a stateful operation. Either you are deleting session state or statefully blacklisting something that's a packet of self-contained state (e.g. JWT by id). Heck, even expiration just reduces the revocation into the universally shared state that is time.

My point is, you always have state. If you care about that state being anything but _the current time_ (e.g. just letting tokens expire and not worrying about revocation), you need shared storage.


If you always have state, what's the point of making tradeoffs to get closer to "statelessness"?

I see clearly why some small subset of applications benefits from carefully minimizing shared state among components. It is not at all clear to me why pseudo-statelessness is a good default.


I'm not sure you're actually asking for my opinion, or just making a point, but IMO, the "statelessness" most people describe with respect to web services simply means that a single request already has as much as possible of the information required (outside of current time, securely fetching/validating public keys, etc) to process the request.

The point is that it's easier for distributed systems as a whole when clients hold onto their client-specific state, rather than a minimal token that the server, likely being load balanced for availability, must exchange for that state with yet another service in yet another stateful/authenticated request/response manner.


My subtext is that gains from moving state from the server to the client are often swamped by the first serverside database round trip that has to be done to service requests. So, you see ActiveRecord Rails applications using JWT, and it's like: the benefits of "statelessness" are not rationally why this got deployed.


When are you expiring tokens ahead of their natural expiration date? When someone logs out?

Isn’t that state? If you add state to something stateless you are generally on your own.

[edit: also I disagree with the notion that something with an expiration date is stateless. It has two states. It’s just that the look like idenpotence]


Perhaps revoking is the better term here. At least that's the use case I had in mind. If you want the ability to revoke a token, you have to have some list of black listed tokens somewhere.


When someone's account is compromised, is another situation.


> When someone's account is compromised, is another situation.

Why is that scenario relevant if tokens are supposed to be used once per request and short-lived?

Once a token is used, it's supposed to be expired and no longer in use. Both the expiry timestamp and the nonce fields already handle those use cases.


Suppose to be once per request and short-lived. But that's not specified in the thread above.

Previous person mentioned logout, so I assumed we were talking about session tokens--which I understand its a misuse of JWTs--and is why he/she's mentioning it.

But if we're talking about just one time auth tokens, then yeah, you don't need expiry ahead of the expiry time, and it's plain it's a non-issue.


> My issue here is that expiring JWTs involve adding state!

I don't agree. The expiration timestamp is not a state, nor is a nonce/token id. Moreover the specs enable servers to arbitrarily reject tokens, which means servers can arbitrarily request token refreshes. This means that any argument regarding how a nonce is a state is entirely irrelevant and without any practical interest.


Why would you arbitrarily reject a token refresh? The question here is which token to reject. That's where the state comes in. If a token is compromised, you have to know which one. Hence, stateful.


> Why would you arbitrarily reject a token refresh?

You've misread what I've said. The server can trigger token refreshes by rejecting the request. According to the JWT workflow, that triggers the client to request a new token and retry the request.

> The question here is which token to reject.

That isn't much of a question, because servers are free to reject any token arbitrarily. They can, however, ignore specific tokens that cease to be valid, such as expired tokens or tokens which have already been used. None of those scenarios involves any change to the token's state.


I'm failing to see how this is complicated. Imagine the following:

1) A token gets compromised.

2) You know which token. You need to revoke access.

3) You introduce state by storing said token on disk / in memory somewhere.

Key takeaways:

1) The authentication system (not the token) is now stateful. 2) You now have to check this data store to properly allow authentication. 3) A core benefit of JWT (stateless auth) is gone.


> 1) A token gets compromised.

Tokens are single-use and short-lived. Once a token is used it's revoked.

> 2) You know which token. You need to revoke access. > 3) You introduce state by storing said token on disk / in memory somewhere.

You don't. You simply reject the token and let the client refresh its token. That's it. There is no state. Compliant clients already expect tokens to be rejected for no apparent reason. They are access tokens.

Why exactly are you assuming that an access token is not single-use or even short-lived, particularly in bearer token protocols specifically designed so that tokens are ephemeral and single-use?

> 1) The authentication system (not the token) is now stateful.

Even if you shoehorn your definition of statefulness, that's entirely irrelevant. The whole point of an authentication system is, following your line of reasoning, to implement a stateful system. Thus, not only is that line of reasoning absurd, it also completely misses the point of implementing an authentication system, not to mention it ignores a whole class of attacks. And for what, exactly?


There's so much conceptual / factual confusion in this post I just don't know where to start. Agree to disagree I guess.


One way to look at it is, presumably you will have far fewer revocations than active sessions, so why optimize for that case?

Instead of an "active sessions" table you could just maintain a list of revoked sessions and check each incoming request against that list. You can make revocations expire shortly after the JWT was set to expire.


The page mentions the ‘exp’ field, but doesn’t use it in its example. I was suggesting the author point out the fact that, if someone gets a hold of a JWT without an expiration, then your system is in quite a bit of trouble.


It is up to your implementation if you consider JWTs without an exp field to be valid.

Our implementation requires a number of fields that are optional in the spec.


So that's what JTIs are for!! I disabled [generating] them in our app, I couldn't figure out what purpose a unique-identifier-per-jwt would have, when you could just use the jwt itself to uniquely identify itself.


You can set a ttl in the JWT and you should. But I think you are talking about using jwts as session cookies, which is indeed not something you should be doing without having a reliable way to invalidate them if you care about reliable signout and token invalidation. For that ttls are not a great solution.

We don't currently use them for sessions, but I've been planning to. When we do, we'll have a mechanism for invalidating tokens, just like we currently do for our oauth tokens. One way would be to simply embed that in the jwt as a field and check that on each request, just like we do already with oauth. The biggest risk with either oauth or jwt tokens is somebody intercepting them and using them. This risk is about the same for both but it does need consideration.

We are using jwts internally for authorizing messages on our queues and internal API calls. Those jwts have very short ttls and don't leave our infrastructure. They typically include assertions on scope, userids, etc. I've been considering to make JWTs the native format on our queues; i.e. embed the message in the JWT rather than a jwt in the message. This would make message tampering harder for any man in the middle attacks. We already uses nonces in some of our messages so we'd be able to prevent replay attacks this way as well.

The main benefit of using jwts is that verifying them is trivial and can be done without network interaction. Very nice in a microservice type architecture. Jwts are issued on our API server are after verifying the oauth token (not jwt currently). We don't leak these tokens outside our infrastructure currently and we don't have public endpoints that would accept them in any case. None of this is new but not that common in modern REST/graphql type setups nevertheless. JWTs are probably easy enough to retrofit in most APIs that it might be worthwhile exploring this for many.

If you are interested, we open sourced our Java code for creating/verifying JWTs. Check here for an example and more code: https://github.com/Inbot/inbot-utils/blob/master/src/test/ja...


I recently started using JWT and had the same problem, I ended up keep the expiration very low and having the client constantly refresh when they need it, and just forget it when they don't


This is a very popular conclusion when considering AuthN and invalidation. Keep the state at the provider and just prevent issuance of new tokens (whether signed certs, JWTs, etc) if/when the user requests access be revoked.

What you're really doing is externalizing your state to one already universally shared, and which we already have a lot of tools to manage: the current time.


It's a reasonable conclusion too, when revoking tokens because of a hack/leakage. In these situations human reaction times are involved, which will be at least minutes and maybe hours or days.

Having tokens with an expiry of e.g 10 minutes, but with no ability to revoke, is a totally reasonable trade-off in these circumstances.


I think storing JWTs might make sense for some advanced scenarios where you have multiple services with varying security requirements but when you store JWTs, you lose a lot of the benefits of having a stateless token which doesn't require a database lookup.

A possible alternative is to just make the JWT expiry very short; like one hour; then you don't really need to explicitly invalidate the token.

With a real time bidirectional transport like WebSockets, you can make the JWT expiry even shorter; like 10 minutes and you can auto refresh it by pushing a replacement token to clients every 8 minutes or so. If the expiry is so short, you don't need the ability to invalidate tokens.

Getting your laptop stolen while you are logged into a service which relies on JWT is like getting your credit card stolen; it will probably take at least 10 minutes for you call your bank to disable it.


An hour could be much much too long, depending on what service you are protecting. It's long enough that even assuming that token theft is a non-stealthy operation, and the user reacts immediately, the attacker has a lot of time to execute his attack. For things like Facebook, this could include slowly scaping all user data and spreading the infection vector to other users.

As for websockets: session integrity is handled by TLS, and invalidation can be handled by closing the TCP connection. Authentication needs to happen only once, on connect.


Storing JWTs in a store or DB is difficult because you need to manage them and that means accounting for all possible edge cases. You can't always detect when a WebSocket/TCP connection has closed from the back end. For example, if your WebSocket server crashes suddenly, all active JWTs that you keep in your external data store will be orphaned and they won't get cleaned up until you run a separate cron job (which adds a lot of complexity).

Storing JWTs in a hashmap in memory is also not ideal if you have multiple processes/servers because it doesn't account for WebSocket lost connection and reconnection edge cases; the client could reconnect to a different server/process than before.


Last year I helped several different companies switch off of JWT onto JSON encrypted with secretbox, which was much more appropriate for their use case(s). No risk of accidentally using an insecure algorithm or sending secure data unencrypted to the client.

Local storage is not secure.


One of the biggest advantages of JWT is that is saves up on database reads which can be significant when you have million+ logged in users.

I think that is probably thinking of time when you had to do everything yourself (host your own mysql server, create indexes, cache, etc). Now you can easily save your sessions using stuff like DynamoDb.. it costs almost nothing and read times are blazing fast even when there are millions of rows. Doesn't make a lot of sense to use JWT after this.


> Now you can easily save your sessions...

True.

> ...using stuff like DynamoDb..

Well, yeah, if you want to be tied to AWS and use a difficult to manage technology which is only useful in a few niche cases, DynamoDB is absolutely the right choice </sarcasm>. Otherwise Redis, Memcache or even Postgres would be a better choice. After all, session management is only a (small) part of data persistence problem.


Yes of course. That was not my point DynamoDb was just something off the top of my head. You can easily use redis or even any nosql db for that. My point was about the main advantages of JWT being fast with millions of users isn't really that big deal anymore.


Cool, sorry if I jumped the gun... I recently had to deal with some SW using DynamoDB for no special reason, so I'm a bit touchy about it. :)


A small Go library we wrote to centrally manage distributed session tokens such as JWT inspired by CAS: https://github.com/endiangroup/compandauth. Main highlight is central revocation, locking and unlocking of distributed sessions

The core concepts can be translated into any language that supports integers, happy to reference any alternative implementations.


There are other ways to pass claims -- like using bearer tokens in the HTTP header, or using OAuth 2. (All with TLS, of course)


Yes, JWTs don't bring anything new to the table. In fact, most articles promoting their use don't even explain why you should use them. This is cargo cult programming at its utmost.


There are many ways to do many things. That doesn't make it cargo cult programming.

Encoding your claims as a JWT is useful because there are many libraries that work with this, it's a known format (and one that's not tied to any particular transport), and is really good for creating stateless authentication systems using asymmetric keys.

If you're interested in the differences between JWTs and something like OAuth (which really are two different things entirely) then you can visit https://google.com and type in "JWT vs Oauth2". Answers will appear on your screen.


JWT is just a standard for bearer tokens (including those used by OAuth 2).


I originally thought so myself. But RFC 7519 (https://tools.ietf.org/html/rfc7519) is different from RFC 6750 (https://tools.ietf.org/html/rfc6750) -- and the two don't mention each other's implementation.


RFC 6750 describes the format of Bearer tokens: https://tools.ietf.org/html/rfc6750#section-2.1 # it happens than JWTs fit the format, so they can be used.

The spec is vague enough here that you can stuff almost any string you want into the header, as long as it has sufficient entropy that it is near impossible to brute force. Of course, JWTs introduce their own concerns, as discussed in other comments.


I used to just follow whatever people said in oAuth and oAuth 2. No longer. Once I started questioning why we need all these tokens, when we will anyway have to look up access information in some database, I got pretty much no satisfying answers:

https://security.stackexchange.com/questions/161734/why-does...

The token may as well just be an AUTENTICATION token, such as the app’s id with timestamp signed with the shared secret. (Or even better, an asymmetric private key, where the shared secret is replaced by TWO keypairs, one from app-to-platform and one from platform-to-app.)

Then you use this app id to look things up in an Access Control List (ACL).

Then stuff becomes easy. Forget all the oAuth crap. The app is just another user with an ID in your system. Users may grant access to other users, for different streams of data. The access can have various read/write/admin levels etc. It can be changed anytime. Finally, users can have LABELS (or Roles) which determine in one fell swoop what an app can do. That is similar to “scopes” in oAuth.

I don’t just talk about it — this is how we handle it in our platform:

https://qbix.com/platform/guide/access


JWTs are radioactive. Proceed with caution.


They're a complicated solution to a problem that you almost certainly don't have. Storing session data in a private datastore using a long random session identifier as the key is simpler, more secure, and more flexible than JWT.


That's the conclusion I've come to. I wished someone would have saved me a few brain cells and told me that when I first heard about the damn things.


This meme is getting out of hand. Yes, JWTs may be inappropriate compared to putting a session id in a cookie, but there are many uses for JWTs outside of web app session handling. There are a couple serious implementation pitfalls to be aware of, but the bottom line is that JWT is a convenient and standardized way to construct a secure bearer token.

Despite the pitfalls, most folks that need a bearer token format (not just a web session) are probably better off using JWTs than rolling their owns solution.


The number of projects that truly "need a bearer token format" is roughly the same as the number of projects that truly "need a blockchain".


That is not remotely true.


I welcome the challenge


I keep hearing this. Is there a good writeup available?


Most of the "discussion" on this topic spins out of this blog post: https://paragonie.com/blog/2017/03/jwt-json-web-tokens-is-ba.... Which unfortunately is:

1. A bit unnecessarily abrasive and hysterical in its style, and

2. Comes from a PHP consulting firm, promoting their own alternative proposal (which hardly anyone else seems to discuss or use). So I think #1 above is really about drawing eyeballs and selling services, more so than providing clear information for a newcomer to follow.

JWT does have its issues, though. They basically break down into two points:

1. Because of its distributed nature, there's no built-in way to invalidate a JWT prior to its natural expiration. You have to roll your own approach for this, typically some sort of whitelist or blacklist mechanism (which defeats some of JWT's advantages).

2. By default, the spec and its major library implementations allow JWT's to specify a number of different signing algorithms (including "None"!). This is dangerously nonobvious for newbies. Best practice is to configure your code to only allow a limited number of algorithms (i.e. one).


> Comes from a PHP consulting firm, promoting their own alternative proposal (which hardly anyone else seems to discuss or use). So I think #1 above is really about drawing eyeballs and selling services, more so than providing clear information for a newcomer to follow.

There was a recent (November 2018) talk at London Gophers about JWT Alternatives (slides here: https://speakerdeck.com/hako/exploring-alternatives-to-json-...).

Keep in mind that PASETO didn't exist until the middle of 2018, so the main reason "hardly anyone else" seems to use it is precisely because it takes time for standards to be adopted.

If you take a look at https://paseto.io, you'll see that there are implementations of PASETO (our proposed alternative) in multiple programming languages by other companies and individuals. All of these implementations are open source and under very permissive licenses (MIT or ISC).

Additionally, a great deal of time and effort went into the PASETO documentation, so that developers can understand not only how to implement it themselves, but also why it was designed the way it is. https://github.com/paragonie/paseto/tree/master/docs

Given all of the above, is it really fair to write PASETO off as an attempt to sell services?

Claiming that the original article is meant to sell services doesn't make sense either: If developers keep using unsafe tools, they will continue to be less secure and I'll have an easier time selling "make your products/services more secure" services to developers. The best thing to do, to meet such an incentive, is to say nothing publicly and let the easy money keep rolling in.

So one of two things is happening:

1. You don't correctly understand our intentions.

2. We're really bad at understanding our own incentives, and it's a miracle we've been in business for 4 years.


I mean, your homepage is pretty damn lacking and you even put something like this without putting any sources 'This has led to many security experts declaring boldly, "Don't use JWT!"'. This just looks like a poor attempt at making something 'better'.


> I mean, your homepage is pretty damn lacking

Do you honestly believe cybersecurity decisions should come down to how snazzy a homepage is, rather than a company's reputation?

> and you even put something like this without putting any sources

That article being discussed in this thread in particular quotes:

1. The opinions of other security experts

2. RFC 7515, section 4.1.1

3. The auth0 article about RS256/HS256 confusion

4. RFC 7518

5. The Adobe attack on ECDH-ES

What additional kind of sources do you need? The arguments should be sufficiently supported by the material available.

> This just looks like a poor attempt at making something 'better'.

By what metrics could we make this attempt less "poor"? What specific changes do you need to see?


Blog post: https://paragonie.com/blog/2017/03/jwt-json-web-tokens-is-ba...

DEFCON CPV talk: https://paragonie.com/files/talks/NoWayJoseCPV2018.pdf + https://youtu.be/RijGNytjbOI

Alternative design that isn't radioactive: https://paseto.io

Apologies if this wasn't more readily available or commonly known. I'm worse at marketing than I am at engineering.


[bookmarks]

Thanks a lot! This is exactly what I needed.


The parent comment isn't very helpful, but from what I understand people dislike JWTs because it makes it hard to invalidate a session without some sort of work-around. For example, you can use 2 tokens, one short lived, and one long lived to get around the invalidation problem, but then you will need to occasionally validate that both tokens are still valid, and that state needs to be stored, and now you're storing some state, which is semi-contradictory to the purpose of a stateless-token. Here's a more detailed write-up from another poster -- https://news.ycombinator.com/item?id=12332119


The way I understand it the only sane use for JWTs is for short-lived delegation of authorisation.

E.g. a user wants to talk to service A but access to that service requires certain privileges. Instead of authenticating with service A, the user authenticates with service B (e.g. using a long-lived conventional session mechanism that requires DB lookup), which issues a token the user can then pass to service B (which trusts service A the info is valid and needs no lookup to process the token). JWT standardises a format for that token.

Most uses of JWT in the wild however seem to be for authenticating the user of a (web) app with the backend of that same app, so the token is passed from the backend to itself (via the user). This use case is better suited for conventional session tokens.


At work we use JWT strictly within our own infrastructure, and opaque tokens for requests coming into our API gateway. This gives us a single point to check tokens are still valid, after which a JWT gets passed back to the backing service. The actual service internally can trust that the token it received is still good to use, in many cases not needing to do any further queries to get user details as their encoded in the token.


Isn't that basically oauth?


Yes. In a web setting (the most common use case for JWT), they are typically issued during an oauth dance.


On using JWT's for sessions (which I think most folks assume would be a primary use case) I found this:

http://cryto.net/~joepie91/blog/2016/06/13/stop-using-jwt-fo...

Also: it's very easy to abuse JWT tokens by storing them inappropriately... https://stackoverflow.com/a/27301616/19020


It's a combination of the other comments response about having to still manage state for invalidation and the issue with the none algorithm. JWTs specify the algorithm their signature was encoded with in the alg field of the header. There was a decent portion of JWT libraries that by default honored the alg : none. This would allow the algorithm field to be changed to none even though the JWT had a signature and the libraries would successfully validate the JWT.


tptacek posted some good commentary on this a while back - https://news.ycombinator.com/item?id=14292223


This is the best explanation I've seen. I think many commenters mean to say something similar but don't give enough context. Here's my phrasing of what I take away from tptacek's comment:

JWT is designed to be customized for a variety of use cases, which means programmers using JWT are rolling their own security scheme, including choosing cryptography from a practically unrestricted field of options. This is known to be a recipe for disaster. A good standard should provide an expert-validated scheme for a specific use case that gives end programmers assurance that if they comply with the standard, the scheme will fulfill its intended use case. This means standardizing separate use cases separately; therefore, JWT is at best a technology that experts could use (but probably wouldn't) to devise specific standard solutions for specific use cases which would then be appropriate for end programmers to use.


JWTs can be read by every script you add to your site, making XSS attacks easier. A cookie with the HttpOnly flag prevents this. I also found cookies easier to use, since the browser handles them and you don't need to attach headers to each request.

Any other important concerns or which way is recommended currently?


> JWTs can be read by every script you add to your site, making XSS attacks easier. A cookie with the HttpOnly flag prevents this.

You're confusing JWTs (a standardized token / means of representing claims) and JavaScript localStorage (a storage which can be read by scripts, partitioned by origin). The two are completely orthogonal; you could store a JWT in a cookie, if you wanted to.

> JWTs [… make] XSS attacks easier. I also found cookies easier to use, since the browser handles them and you don't need to attach headers to each request.

The browser handling them automatically means you need to think about CSRF, which I think largely negates the benefits.

If your site is vulnerable to XSS, a cookie won't save you; the XSS attacker just makes the necessary authenticated request using an AJAX.

My current favorite writeup on this is https://portswigger.net/blog/web-storage-the-lesser-evil-for...


CSRF is mitigated by using the samesite cookie flag. XSS is mitigated by httponly, except where XSS makes legitimate requests to domains specified by the cookie.

This article describes some of the most vulnerable ways to use a JWT in 2019, but please let's stop talking about none algorithms.


samesite doesn't appear to work in Safari, IE or Edge sadly.

EDIT: apparently it's a bit more complicated than that: IE11 on windows 7 doesn't support it, and Safari < iOS12 doesn't support it. Still seems like a significant-enough chunk that you can't rely on it.

https://caniuse.com/#search=samesite


Considering the alternative is local storage, and I can include traditional csrf tokens, it still feels like a partially supported samesite flag with httponly is a solid defense against xss and csrf and doesn't lead to a road of dangerous tech debt.


> you could store a JWT in a cookie, if you wanted to.

Huh? If it's an HTTPOnly cookie, how would you then insert the JWT token into the auth header?


If you’re using a cookie to store the JWT, you don’t really need to check the auth header.


if you're wrapping the JWT in a cookie, then it's effectively a session cookie. In that case, the client side difference between JWT and session cookies are effectively moot.


> Note: Yes, both these methods are synchronous. But, given that neither of these methods require any I/O orNetwork requests, its pretty safe to compute them synchronously.

Found this amusing. Are node devs so used to async that disclaimers like this are necessary?


yes, Node is single threaded so any one thread that blocks the event loop for a significant amount of time becomes a significant performance bottleneck. Generally functions like bcrypt require an asynchronous API.


Is it safe to put jwt in local storage?


Maybe in 2019 we'll stop using JSON/JS for everything


Your wish has been granted. 2019 is the year of YAML as a serialization format and the return of CoffeeScript.

Disclaimer: I am a genie.


Can we go back further and have Django/Rails as the new hotness with Pjax/Turbolinks for the extra cool kids?




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: