Securing your API doesn’t have to be difficult, but it does usually have to be done. Today we’re going to learn about JWTs, or JSON Web Tokens, one of the fastest, simplest ways to make sure your data doesn’t fall into the wrong hands.
There are three types of APIs:
1) Ones that need security, and have it.
2) Ones that don’t, and don’t.
3) Ones that are going to cause a big problem for someone someday.
At the core, a JWT is just a bunch of text, structured in a specific way. Providing that text along with your request is a simple way of authenticating your request, proving that you have the right to that resource.
RFC 7519 (https://tools.ietf.org/html/rfc7519) describes it more formally as “A string representing a set of claims as a JSON object that is encoded in a JWS or JWE, enabling the claims to be digitally signed or MACed and/or encrypted.” What that means is:
– Your token contains a list of things that you are allowed to do.
– Measures have been put in place to keep the token data from being corrupted in transit and prevent recipients from editing their own permissions before sending it back.
JWT Structure
First, there is a header section that declares the string of text to be a JWT, and specifies the algorithm with which it was encoded, such as:
{
“typ”:”JWT”,
“alg”:”HS256″
}
Once that’s taken care of, the heart of the JWT is the Claim. There are no mandatory Claims for a JWT, but certain ones are more common than others.
A sample Claims Set for a JWT provided to a fantasy hockey API might be:
{
“iss”:”Joe’s Fantasy League”,
“sub”:”JerryTheJock”,
“canCreateNewTeams”:true,
“exp”:1556901517
}
In this example:
– “iss” means Issuer, the entity that issued the token.
– “sub” means Subject, the entity the token was issued to.
– “canCreateNewTeams” defines whether or not the presenter of this token has the right to create new teams.
– “exp” means Expiry, the timestamp at which the token ceases to be valid.
JWT Creation Algorithm
Alright, we have our header and our claims, time to get in the weeds. If you’re not exceptionally interested in technical minutiae, feel free to skip to the next section, but it can be helpful to know how things are working behind the scenes, it might help you debug when things go wrong.
First, we base64url-encode our header, and get “eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9”.
Base64url encoding is the same as base64, but with the + and / characters, which have special meaning in URLs and could lead to data corruption if we passed this token in a query string, swapped for – and _.
Then, we base64url-encode our claims and get
“eyJpc3MiOiJKb2UncyBGYW50YXN5IExlYWd1ZSIsInN1YiI6IkplcnJ5VGhlSm9jayIsImNhbkNyZWF0ZU5ld1RlYW1zIjp0cnVlLCJleHAiOjE1NjkwMTUxN30”.
Next, we run both parts through the HMAC SHA-256 algorithm, which combines them with a key known only to the API server (in this case let’s make it “supersecret”) to create a hash that can be verified before the token is used, to make sure neither the header nor the claims have been altered since the token was issued. That hash is then passed through base64url encoding and returns “YLX3X-bOiU9-9VJVa2wjelmc__03ATXzM7-3E_IzlOM”.
Almost done! We have all three parts of a standard JWT, we just need to concatenate them with characters between them to produce… *drum roll*…
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJKb2UncyBGYW50YXN5IExlYWd1ZSIsInN1YiI6IkplcnJ5VGhlSm9jayIsImNhbkNyZWF0ZU5ld1RlYW1zIjp0cnVlLCJleHAiOjE1NjkwMTUxN30.YLX3X-bOiU9-9VJVa2wjelmc__03ATXzM7-3E_IzlOM
There it is! Feel free to plug it into the debugger at https://jwt.io/ to verify it works. Notice that it reads “Invalid Signature” until you provide the right key (“supersecret”). Decoding happens largely the same way, just in reverse.
JWT Implementations
The theory is all well and good, but as the old saying goes, “It doesn’t work until it works in production.” There are a wide variety of JWT implementations available at https://jwt.io/, feel free to pick the one for your language that suits your use case best.
Conclusion
Before we end, one important note: while encoding schemes like base64url make it easier to transmit data, and hash-based method authentication (HMAC) prevents you from altering the contents without the key, NEITHER prevent third parties from reading the contents. If you will be passing sensitive details in your JWTs, you will need to use encryption (many implementations support RSA, for instance, so only the intended recipient of the JWT can read it).
If you’ve heeded that precaution, JWTs are a quick, simple way to make sure that the people accessing your API only have access to what they need. Once you’re up and running, you have access to flexibility, scale, and security. So why not give them a shot on your next project?
For more in-depth help with your security, please contact us.
- Protecting Your API With JWTs - May 8, 2019