Javascript

How To Build Authentication in Angular Using Node and Passport

October 17th, 2019 | By Jay Raj | 7 min read

In this tutorial, you'll learn how to build authentication in your Node.js Angular app using Passport.js.

The tutorial assumes the reader is familiar with creating a basic application using Angular and the Node.js Express framework.

You'll implement it using Passport on an Angular Sales Dashboard application.

The source code for this tutorial is available on GitHub.

Why Authentication?

Why do you need authentication? Adding authentication makes your application secure and prevents unauthorized access.

Authentication can be done with a username and password or a One-Time Password (OTP) sent to your phone. Using existing user information from popular social networks, such as Google, Facebook, etc., is another way to add authentication.

What is Passport.js?

Passport.js is a middleware that can be easily used in your Node.js application. It helps to authenticate using a username and password on Facebook, GitHub, etc.

From the official documentation,

Passport is authentication middleware for Node.js. 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.

Getting Started

Let's start by cloning the source code of the Angular Sales Dashboard app from its GitHub repository.

git clone https://github.com/JscramblerBlog/angular_dashboard


Navigate to the project directory and install the required dependencies.

cd angular_dashboard
npm install


Once the dependencies have been installed, start the Angular application server.

npm start


You'll have the Angular application running on localhost:4200.

Setting Up Authentication API

You need to create a Node project to set up the authentication API.

mkdir node-api
cd node-api
npm init


Enter the required details, and you will have the Node project setup. Next, install the Express framework for creating the API.

npm install express --save


Once you have Express installed, create a file called app.js and add the following code to it:

const express = require('express');
const app = new express();

app.post('/authenticate', (req, res) => {
    res.status(200).json({"statusCode" : 200 ,"message" : "hello"});
});

app.listen(3000, () => {
    console.log('App running at 3000')
})

That's the Express server with an endpoint. You now need to add custom middleware to the /authenticate route.

What is Middleware?

A middleware is a function that can intercept a request. It has access to the request, response objects, and the next function. This next function, when invoked, executes the next middleware.

Let's add custom middleware to the route.

const auth = () => {
    return (req, res, next) => {
        next()
    }
}

app.post('/authenticate', auth() , (req, res) => {
    res.status(200).json({"statusCode" : 200 ,"message" : "hello"});
});


The auth custom middleware does nothing but invoke the next middleware by calling next. Inside the authentication middleware, you'll authenticate the user using a Passport.

To use a Passport, you need to install both passport and passport-local.

npm install passport --save
npm install passport-local --save


You'll be using the passport-local strategy to authenticate the user's login using a username and password.

Require both passport and passport-local in app.js.

const  passport  =  require('passport');
const  LocalStrategy  =  require('passport-local').Strategy;


Passport has several strategies when it comes to authentication. You'll be using the local strategy in this tutorial, so we need to define it as follows:

passport.use(new LocalStrategy(
    function(username, password, done) {
        if(username === "admin" && password === "admin"){
            return done(null, username);
        } else {
            return done("unauthorized access", false);
        }
    }
));


The local strategy uses the username and password for authentication. For the sake of this tutorial, we have hardcoded the username and password check.

Before getting into the detailed code, let's have a look at how the Passport authentication executes.

  • A request is received at the authenticated route.

  • The custom middleware intercepts the request and makes the Passport authentication call.

  • On successful authentication, Passport stores the user data in the session.

  • On subsequent requests, Passport fetches the user data from the session for authentication.


Let's make the Passport authentication call inside the custom middleware auth.

const auth = () => {
    return (req, res, next) => {
        passport.authenticate('local', (error, user, info) => {
            if(error) res.status(400).json({"statusCode" : 200 ,"message" : error});
            req.login(user, function(error) {
                if (error) return next(error);
                next();
            });
        })(req, res, next);
    }
}


passport.authenticate invokes the passport-local strategy, and once authentication is done, the callback is invoked.

On successful authentication, Passport saves the user's data in the session. For that to happen, you need to invoke req.login with the user object.

You also need to define the serialize and deserialize methods to facilitate user data storage in the session and retrieve the data on subsequent requests.

passport.serializeUser(function(user, done) {
    if(user) done(null, user);
});
  
passport.deserializeUser(function(id, done) {
    done(null, id);
});


Let’s now install and use the body-parser middleware so that the app can parse the posted parameters.

npm install body-parser --save


To use a Passport, you need to initialize it and use it as below.

app.use(passport.initialize());
app.use(passport.session());


To authenticate subsequent requests, you can define another middleware function. This function checks if the user data exists in the request. Passport provides a method called req.isAuthenticaed that can be used to check if the user is authenticated.

Here is how the middleware function looks:

const isLoggedIn = (req, res, next) => {
    if(req.isAuthenticated()){
        return next()
    }
    return res.status(400).json({"statusCode" : 400, "message" : "not authenticated"})
}


You can use the above middleware on other routes, as shown below:

app.get('/getData', isLoggedIn, (req, res) => {
    res.json("data")
})

Let's move on to adding authentication to the Angular Dashboard app.

Authenticating the Angular App

To add authentication to the Angular dashboard app, you need to add routes to the Angular application. From the project directory, execute the following command:

ng generate module app-routing --flat --module=app


It should create the routing module. Open app-module.routing.ts and replace it with the following code:

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { AppComponent } from './app.component';
import { LoginComponent } from './login/login.component';

const routes: Routes = [
  { path: 'home', component: AppComponent },
  { path: 'login', component : LoginComponent}
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }


You'll be using two additional components in the Angular app called the login and root components. The LoginComponent will handle the login functionality, and the RootComponent will serve as the container for rendering different views.

ng generate component login
ng generate component root


Adding Route Guard To The Home Route

To authenticate the Angular route against any unauthorized access, you'll be adding a route guard.

The guard uses an authorization service to check if the route access is authenticated. Let's create an authorization service to check if access is authenticated.

ng generate service auth


The above command creates a service called auth.service.ts. Add the following code to it:

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';


@Injectable({
  providedIn: 'root'
})
export class AuthService {

  constructor(private http : HttpClient) { }

  public isAuthenticated() : Boolean {
    let userData = localStorage.getItem('userInfo')
    if(userData && JSON.parse(userData)){
      return true;
    }
    return false;
  }

  public setUserInfo(user){
    localStorage.setItem('userInfo', JSON.stringify(user));
  }

  public validate(email, password) {
    return this.http.post('/api/authenticate', {'username' : email, 'password' : password}).toPromise()
  }
}

After validating the user's login, AuthService saves the user's information. It exposes a method called isAuthenticated, which can be utilized by the AuthGuardService service to authenticate the route.

Let's create an AuthGuardService.

ng generate service authGuard


Add the following code to the auth-guard.service.ts file:

import { Injectable } from '@angular/core';
import { CanActivate,Router } from '@angular/router';
import {AuthService} from './auth.service';

@Injectable({
  providedIn: 'root'
})
export class AuthGuardService implements CanActivate {

  constructor(private authService : AuthService, private route : Router) { }

  canActivate(){
    if(this.authService.isAuthenticated()){
      return true;
    }
    this.route.navigate(['login']);
    return false;
  }
}	


The above AuthGuardService implements the CanActivate route guard. It means that, if the guard returns true, the navigation will continue; otherwise, it navigates to login.

Import AuthGuardService in app-routing.module.ts.

import { 
  AuthGuardService as AuthGuard 
} from './auth-guard.service';


Add the route guard to the home route in app-routing.module.ts.

const routes: Routes = [
  { path: 'home', component: AppComponent, canActivate : [AuthGuard] },
  { path: 'login', component : LoginComponent}
];


Inside the Login component, on click, you need to make the API call the Node authentication API. Here is how the login.component.ts file looks:

import { Component, OnInit } from '@angular/core';
import { AuthService } from '../auth.service';
import { Router } from '@angular/router';

@Component({
  selector: 'app-login',
  templateUrl: './login.component.html',
  styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {

  userEmail : String;
  userPassword : String;

  constructor(private authService : AuthService, private router : Router) { }

  ngOnInit() {

  }

  login(){
    this.authService.validate(this.userEmail, this.userPassword)
    .then((response) => {
      this.authService.setUserInfo({'user' : response['user']});
      this.router.navigate(['home']);

    })
  }

}


For the API call to work from Angular to Node, you need to add a proxy conf file in the Angular app. Create a file called proxy.conf.json and add the following code :

{
    "/api/*": {
      "target": "http://localhost:3000",
      "pathRewrite": {"^/api" : ""}
    }
  }

Save the above changes and run the Angular app along with the Node REST API.

Open the localhost:4200/home route, and you will be redirected to the login screen. Once there, enter the credentials as admin and admin, and you will be redirected to the Angular dashboard screen.

Wrapping it Up

In this tutorial, you learned how to authenticate a REST API using Passport. You also learned how to authenticate the Angular routes using route guards.

You used the passport-local strategy to implement authentication. In addition to passport-local, there are several other Passport strategies for authentication.

Don't forget to pay special attention if you're developing commercial Angular apps that contain sensitive logic. You can protect them against code theft, tampering, and reverse engineering.

Jscrambler

The leader in client-side Web security. With Jscrambler, JavaScript applications become self-defensive and capable of detecting and blocking client-side attacks like Magecart.

View All Articles

Must read next

Web Security

Authentication & Authorization in Web Apps

Identity and role management in Web Apps can get complicated. Plus, both are security-critical areas. Let's explore these concepts and some best practices.

April 2, 2020 | By Karan Gandhi | 9 min read

Web Development

Creating a Sales Dashboard Using Angular and Google Charts

The Google Charts service enables you to create dynamic dashboards in your own apps. Learn how to create a sales dashboard using Angular 7!

May 8, 2019 | By Jay Raj | 9 min read

Section Divider