With the use of single-page apps and API-only back end, JSON web tokens (JWTs) have become a popular way of adding authentication capabilities to our apps.
In this article, we’ll look at how to verify JSON web tokens with Express-JWT.
Installation
express-jwt
is available as a Node package. To install it, we run:
npm install express-jwt
Usage
We can use the jwt
function that’s included with the express-jwt
package to verify a token.
jwt
is a middleware function, so we don’t have to create our own middleware to verify the token.
For example, we can use the jwt
function as follows:
const express = require('express');
const jsonwebtoken = require('jsonwebtoken');
const jwt = require('express-jwt');
const app = express();
const secret = 'secret';
app.post('/auth', (req, res) => {
const token = jsonwebtoken.sign({ foo: 'bar' }, secret);
res.send(token);
})
app.get('/protected', jwt({ secret }), (req, res) => {
res.send('protected');
})
app.listen(3000, () => console.log('server started'));
In the code above, we called jsonwebtoken.sign
to issue a token in the auth
route.
Then we can call the protected
route by putting Bearer
and then our token in the Authorization request header.
An example Authorization header would be:
Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJpYXQiOjE1Nzk0NzczMDd9.QW7FOvyJQ36dir0199nJTv07VhlNo9\_cItGTkdyJeK8
If the token isn’t valid or isn’t present, then we would get an error.
We can also check other fields like audience
or issuer
as follows:
const express = require('express');
const jsonwebtoken = require('jsonwebtoken');
const jwt = require('express-jwt');
const app = express();
const secret = 'secret';
const audience = 'http://myapi/protected';
const issuer = 'http://issuer';
app.post('/auth', (req, res) => {
const token = jsonwebtoken.sign({ foo: 'bar' }, secret, { audience, issuer });
res.send(token);
})
app.get('/protected', jwt({ secret, audience, issuer }), (req, res) => {
res.send('protected');
})
app.listen(3000, () => console.log('server started'));
In the code above, we added audience
and issuer
to the object in the 3rd argument of the sign
method call, which holds the options that we want to add to the token issued.
Then in the protected
route, we added the jwt
middleware with the audience
and issuer
in the options object that we passed into jwt
.
If the token has a secret
, audience
, and issuer
that match what the code has, then the protected
route returns the protected
response. Otherwise, we get an error.
We can verify a token that’s generated with a Base64 encoded secret as follows:
const express = require('express');
const jsonwebtoken = require('jsonwebtoken');
const jwt = require('express-jwt');
const app = express();
const secret = 'secret';
app.post('/auth', (req, res) => {
const token = jsonwebtoken.sign({ foo: 'bar' }, new Buffer(secret, 'base64'));
res.send(token);
})
app.get('/protected', jwt({ secret: new Buffer(secret, 'base64') }), (req, res) => {
res.send('protected');
})
app.listen(3000, () => console.log('server started'));
In the code above, we have the new Buffer(secret, ‘base64’)
passed to the second argument of the sign
method, which generates a token from a Base64 encoded secret.
Then in the protected
route handler, we can call the jwt
middleware function with the same secret to verify the token.
To verify a token generated with an RSA private key, we can write the following:
const express = require('express');
const jsonwebtoken = require('jsonwebtoken');
const jwt = require('express-jwt');
const fs = require('fs');
const app = express();
const publicKey = fs.readFileSync('public.pub');
app.post('/auth', (req, res) => {
const privateKey = fs.readFileSync('private.key');
const token = jsonwebtoken.sign({ foo: 'bar' }, privateKey, { algorithm: 'RS256' });
res.send(token);
})
app.get('/protected', jwt({ secret: publicKey }), (req, res) => {
res.send('protected');
})
app.listen(3000, () => console.log('server started'));
The token is generated in the auth
route by reading the private key from a file on the file system and then using that to sign the token with the sign
method.
Then we can use the public key that corresponds to the private key that was used to generate the token to verify the token by writing:
jwt({ secret: publicKey })
To access the decoded token, we can use the req.user
property as follows:
const express = require('express');
const jsonwebtoken = require('jsonwebtoken');
const jwt = require('express-jwt');
const app = express();
const secret = 'secret';app.post('/auth', (req, res) => {
const token = jsonwebtoken.sign({ foo: 'bar' }, secret);
res.send(token);
})app.get('/protected', jwt({ secret }), (req, res) => {
res.send(req.user);
})app.listen(3000, () => console.log('server started'));
In the protected
route, we returned req.user
as the response. Then we should get something like:
{
"foo": "bar",
"iat": 1579478314
}
in the response content.
We can change what property the decoded token is attached to by setting the requestProperty
property as follows:
app.get('/protected', jwt({ secret, requestProperty: 'auth' }), (req, res) => {
res.send(req.auth);
})
Then we get the same response as the previous example.
Conclusion
We can use the express-jwt
middleware to verify our JSON web tokens.
It takes a secret and other token options like audience
and issuer
and then sets the decoded token to the Express request object if verification is successful.
If verification isn’t successful, then an error is returned.
It supports both symmetric and asymmetric crypto algorithms.