How to Use JSON Web Tokens
github.com
github.com
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..
Also, finding information and documentation on JWT and related technologies on-line is a lot easier.
- 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
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.
JWTs aren't comparable to cookies, they're just a standard way to sign data.
the benefit is the portability that comes from a standardized and widely used data structure.
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.
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?
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.
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.
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.
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.
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.
It is significantly more difficult to misuse e.g. golang.org/x/crypto/nacl/secretbox than JWT.
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.
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://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).
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.
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.
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'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.
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 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.
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).
Generally it's better to avoid unauthenticated encryption. That is, encrypt-than-sign, not the other way around.
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?
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.
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.
> 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.
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.
Then you think about how a user can actively log out.
Then you add session management to your server but call it 'token invalidation'.
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.
Without negotiation, you'd have to stop serving clients that haven't upgraded at the cutover time.
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.
Our implementation requires a number of fields that are optional in the spec.
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]
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.
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.
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.
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.
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.
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.
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?
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.
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.
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.
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.
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.
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...
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.
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 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.
Local storage is not secure.
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.
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.
The core concepts can be translated into any language that supports integers, happy to reference any alternative implementations.
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.
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.
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:
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.
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
Any other important concerns or which way is recommended currently?
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...
This article describes some of the most vulnerable ways to use a JWT in 2019, but please let's stop talking about none algorithms.
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.
Huh? If it's an HTTPOnly cookie, how would you then insert the JWT token into the auth header?
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.
Thanks a lot! This is exactly what I needed.
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).
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.
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?
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.
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.
Found this amusing. Are node devs so used to async that disclaimers like this are necessary?
Disclaimer: I am a genie.