Auth0 likes to espouse the benefits of JWTs for authentication:
- “JWT is used at Internet scale. This highlights the ease of client-side processing of the JSON Web token on multiple platforms, especially mobile.” – Auth0 docs
- “JWTs are a good way of securely transmitting information between parties, because as they can be signed, for example using a public/private key pair, you can be sure that the sender is who they say they are.” – Auth0 training
JWTs aren’t great for security though… they’re great for the bottom line. When you’re doing 42 million logins per day, reducing “round trips” increases profit: fewer servers, less bandwidth, less operational care and feeding.
The recent Auth0 vulnerability found by ethical hackers lays bare the specious benefits of using JWTs as access tokens and the hypocrisy of multi-tenant authentication platforms.
To make matters worse, Auth0 wasn’t doing a good job managing keys (same keys for dev and prod), and wasn’t thinking through what information should be signed (garbage in = garbage out). The fact that many customers were mixed in one big shared system magnified the impact of this irresponsible carelessness.
JWTs vs SAML assertions & OpenID Connect id_tokens
So why are JWTs bad? Fundamentally, non-encrypted JSON objects (signature or not!) are easy for hackers to tamper with. Here’s an example of an Auth0 JWT:
{
"user_id": "59d60fef8025c603ce735e02",
"email": "nahuel+victima@cintainfinita.com.ar",
"email_verified": true,
"iat": 1507203410,
"exp": 1507203470,
"aud": "urn:auth0:atacante:Username-Password-Authentication",
"iss": "urn:auth0"
}
When you look at this, it begs the question “What if I put in a different user_id?” And… is there any way I can get that signed?
In security, the rule of thumb is to hide as much of the security infrastructure as possible. Non-encrypted SAML assertions or OpenID Connect id_tokens have the same problem. But they aren’t supposed to be used as access tokens.
SAML and OpenID Connect identity assertions tell the client who authenticated and when. Access tokens (a short lived meaningless string) are used to control the extent of access–normally what API can be called. The API needs to either understand the access token (look it up in a database), or “introspect” the token (see RFC 7662 token response). Returning a JSON object in this way makes it impossible for hackers to modify on the client side.
JWTs might make it easier to support “Internet scale” authentication, but most organizations aren’t doing millions of authentications per day. Stronger security is more important than minimizing round trips.
Learn more about JWTs in our blog: JWT is not an authentication protocol.
Client software–hard to update!
Another really interesting aspect of this vulnerability is how long it took to get customers to update their applications: six months!
The server-side vulnerability was fixed in four hours. The problem was that application developers also needed to update their code.
Auth0 publishes a huge amount of client software on Github. Each library had to be updated to address the vulnerability, and then customers needed to update their applications to use those new libraries. Not a simple process.
This is one of the main reasons Gluu publishes unix-package based client software that can be updated with a normal Linux software update process, like apt or yum. When vulnerabilities are discovered, the client software packages can simply be updated–no changing, regression testing, or re-QAing applications necessary.
SaaS vs DIY
SaaS identity services and JWTs both serve a purpose in the ecosystem. But many people insist owning and operating an IAM system is too difficult for the masses, and should be left to “expert” cloud providers. This doesn’t address the fundamental misalignment of organizations that need security, with SaaS providers that reduce costs to maximize capital returns.
Net-net, if you want good security, do it yourself!