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:

The jwt.io debugger showing a JSON Web Token

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 "admin".

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?

One of the first things I hear when I explain JWTs is “the data’s encoded, but I need it to be encrypted, otherwise my data’s out there for all to see!” Worry not — there is JSON Web Encryption, handled by RFC 7517, that allows you to encrypt your JSON Web Tokens and still participate in standards compliance! There are even plenty of libraries out there that support it. I’ve also seen it go under the name JOSE (Javascript Object Signing and 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

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.

How the 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.

Conclusion

Thanks for sticking with me and learning about how you can secure your IoT devices with JSON Web Tokens!