How important is it to think about what information we store and pass in our JSON web tokens? Very! The information we store in tokens can have a lot of impact on our application’s performance and security.
First, let’s think about security. Information in a JSON web token is not encrypted, I repeat not encrypted. It is simply encoded using a secret to create a signature. The signature is what we use to determine if a token has been tampered with or not. All that to say information passed in a token can be read by anyone with access to that token, which could potentially be anyone with access to the session like in a browser. We considering what information should be stored in a token for a user think about the vulnerabilities that could exist both for the system and the user. Definitely don’t pass sensitive information like addresses, social security numbers, or credit card information. That information doesn’t need to be passed with every request to the api and absolutely not given its sensitivity.
Other information that might be less obvious but still present security risks could be information specific to the system the user is accessing. Like security group names, ip addresses, and server names. All of that information can start to expose information about your system architecture that could give a hacker information they need to target your system more directly.
Security is supreme, but the information you store in your JWT and how you store it can also make a big different on performance. Take for example we need to know the user’s department to ensure they are authorized appropriately. The difference between “department”: “sales” and “dept”: “sales” is 8 bytes. Not a lot, but some. Now multiple that against all of the claims in your JWT and that can add up, especially considering that each authenticated request sends the JWT along for the ride, over the network, to your servers, that are charged for bandwidth. You get the point.
Teams I’ve worked with have come up with clever uses for JWTs and the claims we pass. For example our project was heavily reliant on security groups, like Active Directory groups. Each user within the organization might be assigned to 100+ security groups either directly or through inheritance of other groups. That’s alot of information to store and parse and manage for each user. Our application however might only care about 5-10 of those security groups for a given user. To solve for the complexity that came with so many groups and to gain a little performance boost we leveraged the JWT to store and manage the groups for each user. Here’s an example:
This does a few great things for us. First, we’re only tracking the security groups for the user that our application cares about, we ‘throw’ away the rest of the groups for our purposes. Second, we ‘pre-fetch’ the security groups for the user, which means we no longer need to perform a query to get that information before fulfilling a request from our user.
If we take this one step further and consider security and performance we can modify our JWT to something like this:
Here I’ve turned our string values into integers to represent the same information. This reduces our overall token weight, exposes nothing sensitive about our security group naming conventions and is possibly more performant because we can not verify authorization against an integer instead of a string value.
JSON Web Tokens and token-based authentication is a powerful tool in our decoupled architectures. It’s important to use them wisely.