API Authentication with JWT and Passport
In this tutorial, I am going to show you how authenticate your API using JWT and Passport. JWT is an open standard that defines a compact and self-contained way for securely transmitting information between parties as a JSON object.
Prerequisites
Setting up the Project
First you need to create a directory for your project. If you are going to use terminal to create directory, run below command on your termianl.
1
mkdir jwt-and-passport-auth
1 | mkdir jwt-and-passport-auth |
Then navigate to your project directory.>
1 | cd jwt-and-passport-auth |
Then we need to initialize a new package.json:
1 | npm init -y |
Next, we need to install to required dependencies:
1 | npm install --save bcrypt body-parser express jsonwebtoken mongoose passport passport-jwt passport-local |
We need,bcrypt for hashing passwordjsonwebtoken for signing tokenspassport-local for implementing local strategypassport-jwt for retrieving and verifying JWTs
At this point, we have been initialized and all the dependencies have been installed. Usually we start a project with creating our entry file such like app.js but in here, I start with creatind Database Schema.
Setting up the Database
Create a directory call model in your project's root directory.
1
npm init -y
1 | npm init -y |
Inside the model directory create a file namedmodel.js and place below code,
1 | const mongoose = require('mongoose'); |
When you store your passwords, you should avoid storing passwords in plain text.
To avoid this, we will use a package called bcryptto hash user passwords and store them safely. Add the library and the following lines of code:
1 | // ... |
UserScheme.pre() function will get the plain text password, hash it, and store it before user information is saved in the database.this refers to the current document about to be saved.
Then we also need to make sure that the user trying to log in has the correct credentials. To validate is add below code after the UserScheme.pre() function:
1 | // ... |
bcrypt hashes the password sent by the user for login and then checks if the hashed password stored in the database matches the one sent by the user. It will return true if there is a match. Otherwise, it will return false.
Setting up Registration and Login Middleware
In here, we used Passport authentication middleware to authenticate requests.
It allows developers to use different strategies for authenticating users, such as using a local database or connecting to social networks through APIs like login with Twitter, LinkedIn, Facebook, GitHub and many more.
In here, we use the local strategy (email and password).
You will use the passport-local strategy to create middleware that will handle user registration and login. This will then be plugged into certain routes and be used for authentication.
To implement this authentication, we create and directory called auth and create new file called auth.js within it. Then you should start it by requiring passport,passport-local, and the UserModel that was created in the previous step:
1 | const passport = require('passport'); |
First, add a Passport middleware to handle user registration:
1 | // ... |
Main functionality of this code is save the information provided by the user to the database, and then sends the user information to the next middleware if successful.
Next, add a Passport middleware to handle user login:
1 | // ... |
This code will use to finds one user associated with the email provided.
Creating the Signup Endpoint
To provide routing, we use popular Node.js framework Express. If you want to know more about Node.js frameworks, you can read my article about Node.js frameworks from here.
To provide routing functionality to our application, we need to create a directory called routes and create new file called routes.js within it.
Then you should start by requiring express and passport:
1 | const express = require('express'); |
Then we need to handling the POST request for signup:
1 | // ... |
Creating the Login Endpoint and Signing the JWT
To proceed with Login, first we need to require jsonwebtoken:
1
2
3
4
5
6
const express = require('express');
const passport = require('passport');
const jwt = require('jsonwebtoken');
// ...
1 | const express = require('express'); |
Then we need to handling the POST request for login:
1 | // ... |
We should not store sensitive information such as the user’s password in the token.
We store the id and email in the payload of the JWT. You then sign the token with a secret or key (TOP_SECRET). Finally, you send back the token to the user.
We have login endpoint now . A successfully logged in user will generate a token. Now we need to Verifying the JWT.
Verifying the JWT
To verifying the JWT, put below code below the require and above Passport middleware of handle user registration:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// ...
const JWTstrategy = require('passport-jwt').Strategy;
const ExtractJWT = require('passport-jwt').ExtractJwt;
passport.use(
new JWTstrategy(
{
secretOrKey: 'TOP_SECRET',
jwtFromRequest: ExtractJWT.fromUrlQueryParameter('secret_token')
},
async (token, done) => {
try {
return done(null, token.user);
} catch (error) {
done(error);
}
}
)
);
1 | // ... |
This code uses passport-jwt to extract the JWT from the query parameter. It then verifies that this token has been signed with the secret or key set during logging in (TOP_SECRET). If the token is valid, the user details are passed to the next middleware.
Creating Secure Routes
Now, we need to create secure routes that only users with verified tokens can access.
Create a new filesecure-routes.js in routes directory and add the following lines of code:
1 | const express = require('express'); |
This code handles GET request for profile. It returns a “You made it to the secure route” message also also returns information about the user and token.
Create app.js
Now create file called app.js which we are going to implement our database connection and etc. Then paste below code in it:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
const express = require('express');
const mongoose = require('mongoose');
const passport = require('passport');
const bodyParser = require('body-parser');
const UserModel = require('./model/model');
mongoose.connect('mongodb://127.0.0.1:27017/passport-jwt', { useMongoClient: true });
or
mongoose.connect("mongodb+srv://<user>:<password>@learning.eauwn.mongodb.net/<database>?retryWrites=true&w=majority", {
useNewUrlParser: true,
useUnifiedTopology: true,
});
mongoose.connection.on('error', error => console.log(error) );
mongoose.Promise = global.Promise;
require('./auth/auth');
const routes = require('./routes/routes');
const secureRoute = require('./routes/secure-routes');
const app = express();
app.use(bodyParser.urlencoded({ extended: false }));
app.use('/', routes);
// Plug in the JWT strategy as a middleware so only verified users can access this route.
app.use('/user', passport.authenticate('jwt', { session: false }), secureRoute);
// Handle errors.
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.json({ error: err });
});
app.listen(3000, () => {
console.log('Server started.')
});
1 | const express = require('express'); |
Run Application
To run your application, use below command,
1
2
3
4
5
6
nodemon app.js
or
node app.js
1 | nodemon app.js |
Testing with Postman
* Signup
Method: POST
URL:http://localhost:3000/signup
Body
x-www-form-urlencoded
| Key | Value |
|---|---|
| example@example.com | |
| password | password |
- Login
Method: POST
URL:http://localhost:3000/login
Body
x-www-form-urlencoded
| Key | Value |
|---|---|
| example@example.com | |
| password | password |
- Profile
Method: GET
URL:http://localhost:3000/user/profile
Params
| Key | Value |
|---|---|
| secret_token | token |





