Trust your data with JWT!

Sometimes you want to store data on a user’s browser or phone that you generated on the backend. Later, you might send this data back to the server to restore state. You might store a game save state in the browser, so when the user comes back they can pick up where they left off. But if you store this in a readable format, a malicious user could alter the payload they send back to the server and get a higher score than they should have.

With Json Web Tokens (JWT), we can add a signature to all of our data that guarantees its accurate! Let’s see how we can generate one in Node, and test that our code is working.
A word of warning: JWT’s can also be used to encrypt data, but this article is just focusing on how to sign it. Signing guarantees the data is legit, but does not protect the data from someone reading it. We’ll see later how this works.
Creating a JWT in Node
We’re going to use the JsonWebToken Node library from Auth0. We’ll also use the dotenv library to make it easier to manage environment variables. Let’s take a look at the code below:
First, we import three libraries. JWT is the library doing the bulk of the work, this is where we’ll pass in a payload and a key and get back the JWT. We’re using dotenv to pass in the environment variable for our private key. I can’t stress this enough: do not include your private key in your source code. Your private key should go in a root level file named .env and look like the below file:
JWTKey=REALLYLONGANDSECRETKEY
This key is what ensures the signature is valid, if you lose control of the key, you can no longer trust anything signed with it. By using a .env file along with the dotenv library, we can get access to this environment variable by calling:
process.env.JWTKey
Then we can add the .env file to our gitignore and ensure it’s never checked into our code base.
Moving on, you can see that we generate a payload of items we want to store in our JWT. As this could be something the browser sends to the server a lot, its best to keep it small. Here we just have a few simple fields:
const payload = {
email,
name,
score,
lives,
};
This generates a JSON object and stores it in the payload variable. Next we setup our Signing options:
const signOptions = {
issuer: 'issuer',
audience: 'audience',
algorithm: 'HS256',
};
Issuer and audience can be changed based on your needs. These are called “claims” in JWT. If you’re curious, more information can be found here: https://tools.ietf.org/html/rfc7519#section-4.1
We also specify that we’ll be using the “HMAC with SHA-256” or HS256 algorithm for signing.
Next we actually sign our data in a try catch:
try {
return jwt.sign(payload, privateKey, signOptions);
} catch (e) {
console.error(e);
return null;
}
The rest of the code is just to run the function on some data and write the information to a jwt.
jwt_content = signData('me@jdmccormack.com', 'JD McCormack', 9001, 3);
fileContent = fs.writeFile('jwt.txt', jwt_content, err => {
if (err) throw err;
});
If we run the program now we’ll get this output:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im1lQGpkbWNjb3JtYWNrLmNvbSIsIm5hbWUiOiJKRCBNY0Nvcm1hY2siLCJzY29yZSI6OTAwMSwibGl2ZXMiOjMsImlhdCI6MTU3NjY3ODQ0NCwiYXVkIjoiYXVkaWVuY2UiLCJpc3MiOiJpc3N1ZXIifQ.yVfQmvAH1G1g9GQpSWA2_HPQ44O-hjxGkQr2CiMSOLo
Great! A long string of meaningless text. So how do we check that what we did is working? We can use the helpful JWT debugger at: https://jwt.io/
If we copy and paste that in, it should look like the following:

We can see the proper data! But we get a giant warning about an invalid signature. This is good! We haven’t provided the signature yet. This allows us to read the data no matter what, but only trust the data if its signed properly. Simply put your private key in the section marked your-256-bit-secret
in the “verify signature” block. The color should change and you should see a block that says:

With the private key in place, we’re able to verify the authenticity of the signature and trust the data. A word of warning, the jwt.io site is likely safe, but once you post a private key there it’s probably a good idea to switch to using a new key for future work. You can never be too careful!