by Antonio Erdeljac

Learn how to handle authentication with Node using Passport.js

1*OUk_mC8ojHhStMEURjbI8g
Photo by Oskar Yildiz on Unsplash

Support me by reading it from its original source: ORIGINAL SOURCE

In this article you will learn how to handle authentication for your Node server using Passport.js. This article does not cover Frontend authentication. Use this to configure your Backend authentication (Generate token for each user & protect routes).

Keep in mind that if you get stuck on any step, you can refer to this GitHub repo.

In this article I will teach you the following:

  • Handling protected routes
  • Handling JWT tokens
  • Handling unauthorised responses
  • Creating a basic API
  • Creating models & schemas

Introduction

What is Passport.js?

Passport is authentication middleware for Node.js. As it’s extremely flexible and modular, Passport can be unobtrusively dropped into any Express-based web application. A comprehensive set of strategies supports authentication using a username and password, Facebook, Twitter, and more. Find out more about Passport here.

Tutorial

Creating our node server from scratch

Create a new directory with this “app.js” file inside:

We will install nodemon for easier development.

and then we will run our “app.js” with it.

$ nodemon app.js
1*6kdVzksHWBymrCL20pNyzA
Expected result after running the command above

Creating the user model

Create a new folder called “models”, and create the “Users.js” file inside that folder. This is where we will define our “UsersSchema”. We are going to use JWT and Crypto to generate hash and salt from the received password string. This will later be used to validate the user.

1*updLloBs1oJyVGplMGG4lQ
You should now have this structure

Let’s add our newly created model to “app.js”.

Add the following line to your “app.js” file after configuring Mongoose:

require('./models/Users');
1*YDxu9Xcr1SqDjQLzTVI9MA

Configure Passport

Create a new folder “config” with the “passport.js” file inside it:

In this file, we use the method validatePassword that we defined in the User model . Based on the result, we return a different output from Passport’s LocalStrategy.

1*TxTXHZEmeZoEff1TeW9hDA
You should now have this structure

Let’s connect “passport.js” to our “app.js” file. Add the following line below all models:

require('./config/passport');
1*_Uem3m6YuPSnhx9DZsJ5sA
The Passport require must be below all models

Routes and authentication options

Create a new folder called “routes” with the file “auth.js” inside it.

In this file we use the function getTokenFromHeaders to get a JWT token that will be sent from the client side in the request’s headers. We also create an auth object with optional and required properties. We will use these later in our routes.

In the same “routes” folder create an “index.js” file:

We now need an “api” folder inside the “routes” folder, with another “index.js” file inside it.

1*xT-bMD4RPNbS0trhqltHQQ
You should now have this structure

Now, let’s create the “users.js” file that we require in “api/index.js”.

First, we are going to create an optional auth route ‘/’ which will be used for new model creation (register).

router.post('/', auth.optional, (req, res, next) ...

After that, we are going to create another optional auth route ‘/login’ . This will be used to activate our passport configuration and validate a received password with email.

router.post('/login', auth.optional, (req, res, next) ...

Lastly, we will create a required auth route, which will be used to return the currently logged in user. Only logged in users (users that have their token successfully sent through request’s headers) have access to this route.

router.get('/current', auth.required, (req, res, next) ...
1*FhlHO36q_NTY73Qhw2Vfiw
You should now have this structure

Let’s add our “routes” folder to “app.js”. Add the following line below our passport require:

app.use(require('./routes'));
1*B44dNEd8f0Ii5GDkNJ0fLQ

Route testing

I will be using Postman to send requests to our server.

Our server accepts the following body:

{
  "user": {
    "email": String,
    "password": String
  }
}

Creating a POST request to create a user

Test body:

1*e_U1SfVcGty_8XAZ8gWuSQ

Response:

{
    "user": {
        "_id": "5b0f38772c46910f16a058c5",
        "email": "erdeljac.antonio@gmail.com",
        "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImVyZGVsamFjLmFudG9uaW9AZ21haWwuY29tIiwiaWQiOiI1YjBmMzg3NzJjNDY5MTBmMTZhMDU4YzUiLCJleHAiOjE1MzI5MDgxNTEsImlhdCI6MTUyNzcyNDE1MX0.4TWc1TzY6zToHx_O1Dl2I9Hf9krFTqPkNLHI5U9rn8c"
    }
}

We will now use this token and add it to our “Headers” in Postman’s configuration.

1*3TqFAWgy1bULj-ECJRyKKw

And now let’s test our auth only route.

Creating a GET request to return the currently logged in user

Request URL:

GET http://localhost:8000/api/users/current

Response:

{
    "user": {
        "_id": "5b0f38772c46910f16a058c5",
        "email": "erdeljac.antonio@gmail.com",
        "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImVyZGVsamFjLmFudG9uaW9AZ21haWwuY29tIiwiaWQiOiI1YjBmMzg3NzJjNDY5MTBmMTZhMDU4YzUiLCJleHAiOjE1MzI5MDgzMTgsImlhdCI6MTUyNzcyNDMxOH0.5UnA2mpS-_puPwwxZEb4VxRGFHX6qJ_Fn3pytgGaJT0"
    }
}

Let’s try to do it without token in “Headers”.

Response:

1*ggNxOl_DMzg6dklIJAKG3g

The end

Thank you for going through this tutorial. If you notice any errors please report them to me. If you got stuck on any step, please refer to this GitHub repo.

You can contact me through:

  • erdeljac DOT antonio AT gmail.com
  • Linkedin

Check out my app SwipeFeed.