Securing Your IoT Devices and Services with JSON Web Tokens
It’s IoT Week at SitePoint! All week we’re publishing articles focused on the intersection of the internet and the physical world, so keep checking the IoT tag for the latest updates.
IoT security is a hot-button issue in today’s world: there are more internet-connected devices than there are people, and the amount of data being shared has exploded over the past few years. However, keeping that data safe is becoming a problem just as quickly— especially with the advent of health-sensitive devices, and devices that could be dangerous if compromised, like vehicles!
I can’t claim to have all the answers, but I do have one trick up my sleeve that should help you in your quest for security — JSON Web Tokens, which I’ll also refer to as JWTs. These small, portable, verifiable tokens help make sure the communications you are sending and receiving from your devices and servers are from a trusted source. They also make great bearer and access tokens.
What’s a JSON Web Token?
For those who haven’t come across these before, JSON Web Tokens are JSON-based tokens used to send verified information across the web. They are base64 encoded before they are sent, so they tend to look like this:
What you are seeing above is the JWT debugger at JWT.io, a site where you can learn a lot more about JWTs than we’ll have room to go over in this article. On the left is the encoded, completed JWT. It includes:
- The header, base64 encoded, concatenated with a ‘.’
- The payload, base64 encoded, with another ‘.’
- The signed key
On the right is the decoded header and payload. They consist of claims (which is just a fancy name for JSON key-value pairs). Some claims are declared by the standard —
"alg" is for the signing algorithm for the key and
"sub" stands for subscriber. Other claims you make yourself, such as
The key consists of a signed hash of the header, concatenated with a
".", then the payload, all base64 encoded. It is signed with a secret that is to be held by both parties, and can be symmetrical (a string) or asymmetrical (an RSA public/private key pair).
These claims come together to describe the token itself and anything else you’d like to keep such as user information and relevant session data. Just be sure to keep this data limited — one of the big benefits of JWTs is they are very small if you don’t overstuff them!
You send JWTs by putting them in the Authorization HTTP header with the format:
Authorization: bearer <token>
If you can’t modify HTTP headers, many services will also accept the JWT as a body parameter, or even a query parameter. Those methods aren’t recommended if you can use HTTP headers.
What Are The Benefits of JWTs?
The IoT world is a world of small devices, and developers strive to make the HTTP calls these devices make as small as possible. JWTs help with this by having very little overhead. They use the minimalistic JSON scheme and base64 encoding to achieve this. Just make sure you don’t add too many claims of your own, or else the benefit of size will overridden by your usage of them! Keep the claims to a minimum to keep your app functioning.
Why not cookies? This also hearkens to the HTTP request need. Instead of your server having to use the cookie to go find other information about the user’s session, it is all inside the JWT from the start. This means there are no extra database or external service calls to make. Again, this depends on how you use them, so think carefully about what claims you need, and which you don’t.
Another benefit of JWTs is that they are universal — JSON parsers exist for nearly every platform, and the ability to access base64 encoding/decoding along with hsa256 signing and verification is becoming more and more of a given. Also, JWTs are backed by a web standard, so you can be confident knowing you are using tech that can easily integrate with other web standards-compliant services, including many OAuth2 providers and all providers of the OpenID Connect standard.
Even if your IoT device cannot decode the token, it can be handed to the device as an access token for your servers and services. As long as your device can store a string given to it, JWTs can be used as a stored credential by your IoT devices. Just be extra sure to secure these tokens and keep a close eye on them, as bearer tokens can be dangerous if leaked!
One of the many challenges of today’s web architecture is validating yourself across services scattered across multiple domains — even a single hobbyist or company might have services running on different PaaS providers! JWTs make this cross-domain negotiation easier — as long as all parties share the same secret to verify the key, then the JWT doesn’t care about domain, subdomain, port, etc.
What About Encryption?
Using JWTs In IoT Architecture
Now, we get to the good part — the how. We’ll take a look at this from the perspective of your IoT device and then your IoT servers.
Using JWTs on IoT Devices
If you simply want to receive a JWT as a bearer token, and not use the contained information, all you have to do is store the JWT you receive from your server on the device, and send it with every authenticated request.
If you want to use the payload, or have your device issue JWTs of its own, your device will need to be capable of:
- JSON parsing/stringification
- base64 encoding/decoding
- HS256 signature verification
It will also need to store the shared secret that the server will use to sign/verify the JWTs.
Once you receive a token, you then follow these steps:
- Verify the signature of the key with the secret stored on the device.
- If the signature is valid, use base64 decoding to get the stringified JSON payload.
- Parse the payload into an object.
And there you have it! For Arduino fans, there are some libraries out there for base64 encoding/decoding, HS256 verification, and JSON object handling. For platforms like Raspberry Pi that run Linux, you can use many different scripting languages (Python, Ruby, Node.js) to handle JWTs, and the JWT.io website outlines several SDKs available for your use.
Using JWTs on IoT Servers
As I mentioned in the device section, you can use the SDKs mentioned on the JWT.io website to control how you handle JWT verification on your server.
For instance, if you use Node.js and Express, there is the
express-jwt middleware available that will prevent users or devices from accessing routes without a verified JWT.
Now that we’ve covered using JWTs in practice, let’s talk about some rules of thumb to keep in mind while using JWTs in your IoT architecture.
Some General Advice with JWTs
These are bits and pieces of learning I’ve picked up over my time using JWTs, and some of them are a bit of common sense. But they’re good to keep in mind when implementing JWTs in your architecture.
Always Verify The Signature
When your server receives a request with a token, always verify that signature, or you lose the main value of using a JWT in the first place — knowing the sender is who they say they are!
Use (and Enforce) The Expiry Field
In the standards, the
iat field is for the time the token was issued at, and the
exp field is the timestamp the token expires at. It is highly recommended that you use and enforce these two fields — especially if you have sensitive information. That way, eventually if a token does get out, it will expire.
id Field Can Be Very Handy
Waiting for a compromised token to expire is one thing, but being able to actively revoke a token is also helpful. The JTI (JSON Token ID) claim can help with this — you can revoke access to particular IDs instead of changing the secret and revoking all tokens at once! Just make sure your JTIs are highly collision-resistant, as with any GUID.
Thanks for sticking with me and learning about how you can secure your IoT devices with JSON Web Tokens!