Express, Passport and JSON Web Token (jwt) Authentication for Beginners

This post is going to be about creating an authentication with JSON Web Tokens for your project, presumably an API that’s going to be used by Angular, Vue.js or similar frontend frameworks. We’re going to send the jwt with every request, meaning that we don’t rely on sessions, but simply put the token on every request we make to the API. This way you don’t have to worry about cookies, but you can save it in localStorage or other places on the frontend.

In essence this tutorial will go through:

  • creating a /login route to acquire a token
  • creating a /secret route, that only is available to logged in users with a JSON web token

If you’re curious about the final result and don’t want the step by step guide, check out the final jwt express gist.

What you’ll need:

  • Postman or a similar tool to test the requests
  • Node, npm and a text editor

First of all we need to set up our express project, so we go ahead and create a directory and an index.js file.

Next, we’re going to install the dependencies for an express based API and the passport.js strategies for JSON web tokens.

npm init -y
npm install --save express body-parser passport passport-jwt jsonwebtoken lodash

First, let’s create a simple page with express with the index.js file:

// file: index.js

var express = require("express");
var app = express();

app.get("/", function(req, res) {
  res.json({message: "Express is up!"});

app.listen(3000, function() {
  console.log("Express running");

You can node start the express server with node index.js, but for development I recommend nodemon, installed by npm -g install nodemon to make sure that your server restarts when ever you change the file.

The result you should see in your browser now should be similar to the image below:


Example Authentication with passport.js and JSON web tokens

In order to get the next iteration of our code working, we’ll need to add a couple of more packages to our index.js file:

// file: index.js
var _ = require("lodash");
var express = require("express");
var bodyParser = require("body-parser");
var jwt = require('jsonwebtoken');

var passport = require("passport");
var passportJWT = require("passport-jwt");

var ExtractJwt = passportJWT.ExtractJwt;
var JwtStrategy = passportJWT.Strategy;

_ or lodash will just be for a small utility function, everything passport related will be used in functions for user login and token validation.

Next up is our fake users array, usually you’d get your users from the database, but we’ll just use a plain JavaScript array:

var users = [
    id: 1,
    name: 'jonathanmh',
    password: '%2yx4'
    id: 2,
    name: 'test',
    password: 'test'

The Passport JWT strategy

passport.js works with the concept of strategies. They basically are a middleware function that a requests runs through before getting to the actual route. If your defined authentication strategy fails, which means that the callback will be called with an error that is not null or false as the second argument, the route will not be called, but a 401 Unauthorized response will be sent.

Here the strategy we’re going to use for the web token authentication:

var jwtOptions = {}
jwtOptions.jwtFromRequest = ExtractJwt.fromAuthHeader();
jwtOptions.secretOrKey = 'tasmanianDevil';

var strategy = new JwtStrategy(jwtOptions, function(jwt_payload, next) {
  console.log('payload received', jwt_payload);
  // usually this would be a database call:
  var user = users[_.findIndex(users, {id:})];
  if (user) {
    next(null, user);
  } else {
    next(null, false);


Our strategy is configured to read the JWT from the Authorization http headers of each request. Instead of ExtractJwt.fromAuthHeader() you can define an number of other extraction methods or even write your own. See the passport-jwt repository for the full list.

The secretOrKey is the secret that our tokens will be signed with. Choose this wisely or use a private key.

Inside our strategy we console.log the received payload for debugging purposes, try to find a user with a matching id field in our array and return either no error and the user object or false if the user was not found.

Express.js and the JSON Web Token login route

Let’s continue to update our express app with the body parser and the login route:

var app = express();

// parse application/x-www-form-urlencoded
// for easier testing with Postman or plain HTML forms
  extended: true

// parse application/json

app.get("/", function(req, res) {
  res.json({message: "Express is up!"});

This part almost stays the same, we need to initialize passport with express and enable the bodyParser (urlencoded for usual forms and json for requests with type: application/json, common for APIs)."/login", function(req, res) {
  if( && req.body.password){
    var name =;
    var password = req.body.password;
  // usually this would be a database call:
  var user = users[_.findIndex(users, {name: name})];
  if( ! user ){
    res.status(401).json({message:"no such user found"});

  if(user.password === req.body.password) {
    // from now on we'll identify the user by the id and the id is the only personalized value that goes into our token
    var payload = {id:};
    var token = jwt.sign(payload, jwtOptions.secretOrKey);
    res.json({message: "ok", token: token});
  } else {
    res.status(401).json({message:"passwords did not match"});

The login route checks if both name and password have been posted, if so, we look for the corresponding user in our fake users array.

If no user has been found, we signal that to the user in question.

Now if a user has been found and the password is correct, we set the payload for the JWT to {id:} we use the jsonwebtoken package to create the token and respond with it.

Note: Put simple identifiers in your token, no sensitive data like passwords.

We can now test if our login functionality works as expected with Postman. Set the HTTP method to POST and the URL to http://localhost:3000. The type is x-www-form-urlencoded (you can also post RAW json if you want to).

Here we see a wrong password response for our login attempt:


A correct username and password combination should yield the following result:


Accessing The passport-jwt Protected API Route

So far, so good. We have created a login function that works and we get a token. Now we need to use that token to be able to access some kind of secret information.

app.get("/secret", passport.authenticate('jwt', { session: false }), function(req, res){
  res.json("Success! You can not see this without a token");

app.listen(3000, function() {
  console.log("Express running");

We see our /secret route and that we have a second function defined before we finally pass req and res on. The passport.authenticate part means that we pass the request through our previously defined authentication strategy and run it. If it’s successful, we respond with the secret message, else the request will be unauthorized (401).

To test if this works, first log in and copy the token, then open a new Postman tab and change the settings to:

  • method: GET
  • URL: http://localhost:3000/secret
  • inside Headers: add Authorization and add JWT + token

Note: It’s important the Auth header starts with JWT and a whitespace followed by the token, else passport-jwt will not extract it.


Express and Debugging Passport or Middleware

In the process I of course forgot to prepend JWT so I created a temporary route for debugging my request that would console.log the received headers:

  function(req, res, next){
  }, function(req, res){

Terminal output:

[nodemon] restarting due to changes...
[nodemon] starting `node index.js`
Express running
JWT eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwiaWF0IjoxNDc3MTM0NzM4fQ.Ky3iKYcguIstYPDbMbIbDR5s7e_UF0PI1gal6VX5eyI

See the full files on github:

In the next post we’ll have a look at how we can use the issued web token with JavaScript inside the browser and have protected API access.

If you liked this post, feel free to subscribe on feedly, follow on twitter or check out some of my other posts. If you think I could have explained or done something better or more beginner friendly, please let me know in the comments!

31 thoughts on “Express, Passport and JSON Web Token (jwt) Authentication for Beginners”

  1. Great Article. Worked perfectly for me and saved me some time. I did notice there was on typo

    “In the process I of course forgot to prepend JWT so I created a temporary route for debugging my request that would console.log the received headers:”

    JWT should be JTW.

  2. this is such a big help for people trying to understand jwt auth. Honestly, this is the first simple explanation of this I’ve seen.

    BTW: for anyone trying to use the localStorage, this needs to be done in client script. So add
    if (responseObject.token) {
    localStorage.setItem(‘token’, responseObject.token); //THIS IS THE ADDED LINE TO ADD ITEM
    tokenElement.innerHTML = responseObject.token;

    To retrieve simply use var token = localStorage.getItem(‘token’);
    in your ‘getSecret’ function(make sure to add a check if token is null or not before sending xhr object.

    1. Thank you so much! Happy to hear that!

      Yes we should check the existence of things before trying to insert them, you’re absolutely right. People will hopefully figure that out before deploying to production πŸ˜‰

  3. Just adding to the people who said thanks for this. It was easy to adapt your examples to using postgres and bcrypt.

  4. Thanks. I search through internet several days looking for any article to teach me how to use passport authenticate. Finally, i found what i need in this article. It’s very helpful and clear to me. Thank you for your efforts on this article. Now i got the idea.

  5. Fantastic Article! Please write an article explaining jwt authentication with vue js, Maybe like a part 2 to this artcle! 😁

  6. I have couple of questions:
    1) Wouldn’t that be good to be consistent and also send the JWT to the client over a header? Or use body for both getting and submitting it. But not mix the two methods.
    2) Yes, the JWT can contain the payload that can be read at the client-side, unless the JWT is encrypted. But a more straightforward way to get the data to the client is to send it in the body. Wouldn’t it be a better practice to keep the JWT always encrypted?

    1. Absolutely valid points and thank you for asking:

      1) To me, that’s a matter of taste. If you prefer to have auth in the header, put it there, but it’s irrelevant to both workflow and technology on client and server.
      2) Without the secret, the payload of the JWT should not be readable to client, but; If you put any sensitive information in there it can be cracked. It’s a good idea to keep track of sessions that are affiliated with a user and to set sane timeouts. For attacks and algorithms for JWT I recommend:

      1. Thank you for your answer. And, I failed to mention, your tutorial is also very good.
        It’s just easy to overlook, the fact that the second part of JWT is just a Base64-encoded payload, plain in sight. I’d not call it cracking. I think it should be mentioned in bold letters, so that novices (like me) beware of false security. This is why I mentioned the need for payload encryption – so that it is readable only by the server. I the client needs any info, it can always ask the server and get it in the response body and, if needed, save in local storage. Better be safe than sorry, and thus the JWT could contain also sensitive data.

  7. Just curious, what is the purpose of using passport for local authentication if you are not using the session middleware? Can’t you just decode the token with jsonwebtoken?

  8. Hi Jonathan,

    The standard jwt-strategy does a database validation, every time a secret endpoint is used. How can this be stateless? As JWT pattern should be…

    I got this doubt inside of me and I have to take it out πŸ™‚
    Thanks for the post is quite clear.

  9. Thanks Jonathan! I was wondering how this all translates to the following use case:
    1) Web portal uses Passport JWT for authentication.
    2) A web app, completely seperate from the web portal, wants to authenticate users using the Passport JWT authentication system of the web portal.
    Does Passport then facilitate the web portal and web app talking with each other?

  10. Man thank you sooo much! As some people said this is really simple exaple to explain jwt/passport auth process. I’ve spend much time to UNDERSTAND salt of that and found it here!

    1. Sorry ive found some confusion. In the end of post…
      “Note: It’s important the Auth header starts with JTW and a whitespace followed by the token, else passport-jwt will not extract it.”
      But in the POSTMAN screenshot it’s “JWT plus whitespace” before JWToken itself.
      Anyway i tried both and still reciveing error-401. Readed many topics. Most of them mentionin’ the main issue about that “JWT ” prefix. But i didnt figure out the issue.
      Thank you.

  11. Hey Jonathan,

    Great tutorial, it helped me implement this. Now I am trying something else.

    If I use a standard username/password authentication, I am able to use JwtStrategy to authenticate the JWT Token that I receive in the request header. jwt.sign() happens on the user id and secret. All of this works fine.

    When I try to modify this code to verify the id_token (JWT Token signed using RS256) from OpenID Connect, then I get 401 Unauthorized no matter what. I tried to debug in the JwtStrategy method and it looks like the request doesn’t even go inside that function. This id_token appears to be a lot longer than the one signed with HS256 algorithm.

    A simple passport.authenticate call app.get(‘/callback’, passport.authenticate(‘jwt’, { session: false }), function(req, res, next) {

    Can you please explain why it doesn’t even recognize my token or am I doing something wrong?

Leave a Reply

Your email address will not be published. Required fields are marked *