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.

Updated 10th of August 2017, thanks to the feedback from micaksica!

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'

Security notice: Don’t ever save passwords in plain text. Every time you do outside of a learning environment, an ancient god decapitates an alpaca!

  1. Use bcrypt (or similar strength)
  2. Read The OWASP wikis Password Storage Cheat Sheet (it’s really good)

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);


Note: The API for the jwt package has changed and now should be:

jwtOptions.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken();

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!

Further Steps

Most importantly: Don’t put secret stuff into a JWT, unless you’ve read the following post and know what you’re doing.If you want to build anything half-way secure, you should use a token store that associates a generated string with a user-id backed by redis, in memory or your database like MongoDB or SQL. These rows or documents will basically store a session equivalent with the following fields:

  • the token
  • the user id
  • expiration time

Don’t put your stuff into production without this 😉

Thank you for reading! If you have any comments, additions or questions, please leave them in the form below! You can also tweet them at me

If you want to read more like this, follow me on feedly or other rss readers

73 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. 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.

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

  5. 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.

  6. 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?

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

  8. 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?

  9. 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.

  10. 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?

  11. Goodday.
    Wow. Thanks a lot.

    I tried implementing the passport-jwt and it returns a text/html response when there is no token.
    Is there a way to customize this response?

    NodeJS beginner here.

  12. This entirely defeats the purpose of JWT. The whole point is to have a stateless api and reduce calls to the database. By making a request against the database for every call, and using a session, you’ve eliminated any benefit you might get from using JWT.

    1. @matt Could you provide a link to a better solution? Thank you Johnathan for a great solution. Could you post a full link to your github for working code? I am running into an issue with ExtractJWT being undefined. I’m thinking that my issue may be caused by using a newer version of passport-jwt. I am using passport-jwt@3.0.0.

      1. Hi Will! I don’t have a full up to date project I can publish at the moment. Can you have a look at the “debug” middleware that I’ve included and what that gives you on the request headers?

      2. I had to change “jwtOptions.jwtFromRequest = ExtractJwt.fromAuthHeader();” to “jwtOptions.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken();”.

        And in the request header for /secret I had to change “Authorization”:”JWT TOKEN_STRING” to “Authorization”:”bearer TOKEN_STRING”.

        1. Same With me. Initially I tried to use fromHeader(‘Authorization’) and in header I passed “Authorization”: “JWT token”, but for some reason that wasnt working.

        2. OMG this worked for me also! hours fiddling with this! Jonathan, please add a note in the text for this.

  13. Hi Jonathan!

    Thanks for this tutorial, its very helpful.
    When I tried to use this code, I had to replace ExtractJwt.fromAuthHeader() with ExtractJwt.fromAuthHeaderAsBeareToken and send use prefix Bearer rather than JWT to make it work 🙂

  14. I ran into some issues regarding the auth header resulting in an “Unauthorized” result everytime, just general info for anyone who has the problem next time:

    From the passport-jwt documentation:

    Migrating from 2.x.x to 3.x.x
    Version 3.0.0 removes the ExtractJwt.fromAuthHeader() extractor function that would extract JWT’s from Authorization headers with the auth scheme ‘jwt’. The default authorization scheme of ‘jwt’ as the was not RFC 6750 compliant. The extractor was replaced with ExtractJwt.fromAuthHeaderAsBearerToken(). The removal of ExtractJwt.fromAuthHeader() was done to clearly change the API so any code relying on the old API would clearly break, hopefully saving people some debugging time.

    If you want to maintain the behavior of ExtractJwt.fromAuthHeader() when switching to v3.3.0, simply replace it with ExtractJwt.fromAuthHeaderWithScheme(‘jwt’) in your implementation.

  15. Hello Jonathan!

    First of all, thanks a lot for your work. I checked and I had a problem with these dependencies:
    “body-parser”: “^1.18.2”,
    “express”: “^4.16.2”,
    “jsonwebtoken”: “^8.1.0”,
    “lodash”: “^4.17.4”,
    “passport”: “^0.4.0”,
    “passport-jwt”: “^3.0.1”

    I fixed using:
    jwtOptions.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken();

    Instead of:
    jwtOptions.jwtFromRequest = ExtractJwt.fromAuthHeader();

    I hope it helps.

    Best regards Jonathan,
    Aaron Planell

      1. Thank you very much Jonathan!
        When you change it to ExtractJwt.fromAuthHeaderAsBearerToken(), you should also change ‘JWT’ to ‘Bearer’ in – ‘inside Headers: add Authorization and add JWT + token’ or keep ‘JWT’ and use ExtractJwt.fromAuthHeaderWithScheme(‘JWT’)


  16. Great tutorial for my project, but I’ve an issue with a “ñ” character. Using AngularJS+ExpressJs when I try to retrieve the token payload from localStorage it prints “ñ” instead “ñ”. But if I copy+paste the token into utility it shows “ñ” , that’s right.
    What I’m doing wrong?:
    1. $window.localStorage.getItem(‘web-token’):
    2. var payload = JSON.parse($window.atob(token.split(‘.’)[1]));
    3. Then prints “ñ”

    Thank you in advance.

  17. For me please make something like this. PHP being the server and react being the client.
    Thank you in advance. 🙂

  18. Hello jonathan,
    Nice tutorial, you explained very well.
    but i need to know how we logout the user using this strategy?
    Any suggestions,
    Thanks in Advance.

  19. Thank you, this was good.

    Small updates:

    jwtOptions.jwtFromRequest = ExtractJwt.fromAuthHeader();
    jwtOptions.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken();

    In Postman,
    use bearer instead of JWT

  20. Hi I have a problem using express routers and passport :
    I have routes that are declared in external files (what are called routers, with route prefix in express I think), and when I put my passport authenticate() function as second parameter of an express route it just doesn’t work, and when I do the same but from a route declared in my main file it works.

    Any idea why? Thank you

  21. What do you mean by “Don’t put your stuff into production without this”?
    Dose that mean I have to implement a session with tokens in production ?

  22. Hi Jonathan , thankyou for this wonderful article , just a simple question should the database be access on every request to know wether he is authorized , If no please let me knoe how to implement it .

  23. Hi Jonathan,

    Thank you. Your article is very good and it helped me setup authorization for my app and understand a bit what’s going on around. There is one thing I notice and it does not work for new passport.

    For `opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken();`
    Authorization Value should looks like: Bearer xxx.yyy.zzz

    Fot `opts.jwtFromRequest = ExtractJwt.fromAuthHeaderWithScheme(‘jwt’)`
    You can keep JWT xxxx.yyyy.zzzz

  24. Hello,

    Thanks a lot for the article. Helped me setup authentication for my server. While working, i noticed using “JWT token” as header returns a 401 (UnAuthorized). But using “Bearer token” works ok.

    * passport 0.4.0
    * passport-jwt 4.0.0
    * jsonwebtoken 8.2.1

  25. Great article, thank you! I used “Bearer token” but removed “JWT ” from the start of the token. Cheers

  26. it is anyway to set Timeout on tokens? this is different than Token expire.

    I would like to use a token for some time, and if I use it, reset the time to Zero, so can restart the timeout.

    I know I can put and expiration time, but the token will expire in that time use it or not. I don’t want that, I need to re-start the time every time I access or use the token…

  27. Thanks for the article. Really helped.

    The last days I’m really struggling with CORS and User Sessions and since for some reason the Client connection.sid Cookie is not sent towards the server, I’m gonna simply use LocalStorage along with JWT.

  28. Det her er meget godt!

    I spent a couple hours looking into an implementation of a JWT with passport and was about to jump into the rabbit hole, but this hits the nail right on the head. Concise, easy to read and most importantly, easy to follow. The only recommendation I’d have is to include your edits in the code itself rather than having to change it manually :-P.

    Mange tak!

  29. Hi,
    this is good in postman but how about sending the token from actual page
    i mean if i have a page called secret.html how do i send the token to the server route

Leave a Reply

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