How to manage Authentication in the MEAN stack

How to manage Authentication in the MEAN stack

In this article, we’re going to look at managing user authentication in the MEAN stack. We’ll use the most common MEAN architecture of having an Angular single-page app using a REST API built with Node, Express and MongoDB.

In this article, we’re going to look at managing user authentication in the MEAN stack. We’ll use the most common MEAN architecture of having an Angular single-page app using a REST API built with Node, Express and MongoDB.

When thinking about user authentication, we need to tackle the following things:

  1. let a user register
  2. save their data, but never directly store their password
  3. let a returning user log in
  4. keep a logged in user’s session alive between page visits
  5. have some pages that can only been seen by logged in users
  6. change output to the screen depending on logged in status (e.g. a “login” button or a “my profile” button).

Before we dive into the code, let’s take a few minutes for a high-level look at how authentication is going to work in the MEAN stack.

The MEAN Stack Authentication Flow

So what does authentication look like in the MEAN stack?

Still keeping this at a high level, these are the components of the flow:

  • user data is stored in MongoDB, with the passwords hashed
  • CRUD functions are built in an ExpressAPI — Create (register), Read (login, get profile), Update, Delete
  • an Angular application calls the API and deals with the responses
  • the Express API generates a JSON Web Token (JWT, pronounced “Jot”) upon registration or login, and passes this to the Angular application
  • the Angular application stores the JWT in order to maintain the user’s session
  • the Angular application checks the validity of the JWT when displaying protected views
  • the Angular application passes the JWT back to Express when calling protected API routes.

JWTs are preferred over cookies for maintaining the session state in the browser. Cookies are better for maintaining state when using a server-side application.

The Example Application

The code for this article is available on GitHub. To run the application, you’ll need to have Node.js installed, along with MongoDB. (For instructions on how to install, please refer to Mongo’s official documentation — Windows, Linux, macOS).

The Angular App

To keep the example in this article simple, we’ll start with an Angular app with four pages:

  1. home page
  2. register page
  3. login page
  4. profile page

The pages are pretty basic and look like this to start with:

The profile page will only be accessible to authenticated users. All the files for the Angular app are in a folder inside the Angular CLI app called /client.

We’ll use the Angular CLI for building and running the local server. If you’re unfamiliar with the Angular CLI, refer to the Angular Tutorial: Create a CRUD App with Angular CLI to get started.

The REST API

We’ll also start off with the skeleton of a REST API built with Node, Express and MongoDB, using Mongoose to manage the schemas. This API has three routes:

  1. /api/register (POST) — to handle new users registering
  2. /api/login (POST) — to handle returning users logging in
  3. /api/profile/USERID (GET) — to return profile details when given a USERID.

The code for the API is all held in another folder inside the Express app, called api. This holds the routes, controllers and model, and is organized like this:

At this starting point, each of the controllers simply responds with a confirmation, like this:

module.exports.register = function(req, res) {
  console.log("Registering user: " + req.body.email);
  res.status(200);
  res.json({
    "message" : "User registered: " + req.body.email
  });
};

Okay, let’s get on with the code, starting with the database.

Creating the MongoDB Data Schema with Mongoose

There’s a simple user schema defined in [/api/models/users.js](https://github.com/sitepoint-editors/MEAN-stack-authentication/blob/master/api/models/users.js). It defines the need for an email address, a name, a hash and a salt. The hash and salt will be used instead of saving a password. The email is set to unique as we’ll use it for the login credentials. Here’s the schema:

var userSchema = new mongoose.Schema({
  email: {
    type: String,
    unique: true,
    required: true
  },
  name: {
    type: String,
    required: true
  },
  hash: String,
  salt: String
});

Managing the Password without Saving It

Saving user passwords is a big no-no. Should a hacker get a copy of your database, you want to make sure they can’t use it to log in to accounts. This is where the hash and salt come in.

The salt is a string of characters unique to each user. The hash is created by combining the password provided by the user and the salt, and then applying one-way encryption. As the hash can’t be decrypted, the only way to authenticate a user is to take the password, combine it with the salt and encrypt it again. If the output of this matches the hash, the password must have been correct.

To do the setting and the checking of the password, we can use Mongoose schema methods. These are essentially functions that you add to the schema. They’ll both make use of the Node.js [crypto](https://nodejs.org/api/crypto.html) module.

At the top of the users.js model file, require crypto so that we can use it:

var crypto = require('crypto');

Nothing needs installing, as crypto ships as part of Node. Crypto itself has several methods; we’re interested in randomBytes to create the random salt and pbkdf2Sync to create the hash (there’s much more about Crypto in the Node.js API docs).

Setting the Password

To save the reference to the password, we can create a new method called setPassword on the userSchema schema that accepts a password parameter. The method will then use crypto.randomBytes to set the salt, and crypto.pbkdf2Sync to set the hash:

userSchema.methods.setPassword = function(password){
  this.salt = crypto.randomBytes(16).toString('hex');
  this.hash = crypto.pbkdf2Sync(password, this.salt, 1000, 64, 'sha512').toString('hex');
};

We’ll use this method when creating a user. Instead of saving the password to a password path, we’ll be able to pass it to the setPassword function to set the salt and hash paths in the user document.

Checking the Password

Checking the password is a similar process, but we already have the salt from the Mongoose model. This time we just want to encrypt the salt and the password and see if the output matches the stored hash.

Add another new method to the users.js model file, called validPassword:

userSchema.methods.validPassword = function(password) {
  var hash = crypto.pbkdf2Sync(password, this.salt, 1000, 64, 'sha512').toString('hex');
  return this.hash === hash;
};
Generating a JSON Web Token (JWT)

One more thing the Mongoose model needs to be able to do is generate a JWT, so that the API can send it out as a response. A Mongoose method is ideal here too, as it means we can keep the code in one place and call it whenever needed. We’ll need to call it when a user registers and when a user logs in.

To create the JWT, we’ll use a module called [jsonwebtoken](https://www.npmjs.com/package/jsonwebtoken) which needs to be installed in the application, so run this on the command line:

npm install jsonwebtoken --save

Then require this in the users.js model file:

var jwt = require('jsonwebtoken');

This module exposes a sign method that we can use to create a JWT, simply passing it the data we want to include in the token, plus a secret that the hashing algorithm will use. The data should be sent as a JavaScript object, and include an expiry date in an exp property.

Adding a generateJwt method to userSchema in order to return a JWT looks like this:

userSchema.methods.generateJwt = function() {
  var expiry = new Date();
  expiry.setDate(expiry.getDate() + 7);

  return jwt.sign({
    _id: this._id,
    email: this.email,
    name: this.name,
    exp: parseInt(expiry.getTime() / 1000),
  }, "MY_SECRET"); // DO NOT KEEP YOUR SECRET IN THE CODE!
};

Note: It’s important that your secret is kept safe: only the originating server should know what it is. It’s best practice to set the secret as an environment variable, and not have it in the source code, especially if your code is stored in version control somewhere.

That’s everything we need to do with the database.

Set Up Passport to Handle the Express Authentication

Passport is a Node module that simplifies the process of handling authentication in Express. It provides a common gateway to work with many different authentication “strategies”, such as logging in with Facebook, Twitter or Oauth. The strategy we’ll use is called “local”, as it uses a username and password stored locally.

To use Passport, first install it and the strategy, saving them in package.json:

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

Configure Passport

Inside the api folder, create a new folder config and create a file in there called passport.js. This is where we define the strategy.

Before defining the strategy, this file needs to require Passport, the strategy, Mongoose and the User model:

var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var mongoose = require('mongoose');
var User = mongoose.model('User');

For a local strategy, we essentially just need to write a Mongoose query on the User model. This query should find a user with the email address specified, and then call the validPassword method to see if the hashes match. Pretty simple.

There’s just one curiosity of Passport to deal with. Internally, the local strategy for Passport expects two pieces of data called username and password. However, we’re using email as our unique identifier, not username. This can be configured in an options object with a usernameField property in the strategy definition. After that, it’s over to the Mongoose query.

So all in, the strategy definition will look like this:

passport.use(new LocalStrategy({
    usernameField: 'email'
  },
  function(username, password, done) {
    User.findOne({ email: username }, function (err, user) {
      if (err) { return done(err); }
      // Return if user not found in database
      if (!user) {
        return done(null, false, {
          message: 'User not found'
        });
      }
      // Return if password is wrong
      if (!user.validPassword(password)) {
        return done(null, false, {
          message: 'Password is wrong'
        });
      }
      // If credentials are correct, return the user object
      return done(null, user);
    });
  }
));

Note how the validPassword schema method is called directly on the user instance.

Now Passport just needs to be added to the application. So in app.js we need to require the Passport module, require the Passport config and initialize Passport as middleware. The placement of all of these items inside app.js is quite important, as they need to fit into a certain sequence.

The Passport module should be required at the top of the file with the other general require statements:

var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var passport = require('passport');

The config should be required after the model is required, as the config references the model.

require('./api/models/db');
require('./api/config/passport');

Finally, Passport should be initialized as Express middleware just before the API routes are added, as these routes are the first time that Passport will be used.

app.use(passport.initialize());
app.use('/api', routesApi);

We’ve now got the schema and Passport set up. Next, it’s time to put these to use in the routes and controllers of the API.

Configure API Endpoints

With the API we’ve got two things to do:

  1. make the controllers functional
  2. secure the /api/profile route so that only authenticated users can access it.

Code the Register and Login API Controllers

In the example app the register and login controllers are in [/api/controllers/authentication.js](https://github.com/sitepoint-editors/MEAN-stack-authentication/blob/master/api/controllers/authentication.js). In order for the controllers to work, the file needs to require Passport, Mongoose and the user model:

var passport = require('passport');
var mongoose = require('mongoose');
var User = mongoose.model('User');

The Register API Controller

The register controller needs to do the following:

  1. take the data from the submitted form and create a new Mongoose model instance
  2. call the setPassword method we created earlier to add the salt and the hash to the instance
  3. save the instance as a record to the database
  4. generate a JWT
  5. send the JWT inside the JSON response.

In code, all of that looks like this:

module.exports.register = function(req, res) {
  var user = new User();

  user.name = req.body.name;
  user.email = req.body.email;

  user.setPassword(req.body.password);

  user.save(function(err) {
    var token;
    token = user.generateJwt();
    res.status(200);
    res.json({
      "token" : token
    });
  });
};

This makes use of the setPassword and generateJwt methods we created in the Mongoose schema definition. See how having that code in the schema makes this controller really easy to read and understand.

Don’t forget that, in reality, this code would have a number of error traps, validating form inputs and catching errors in the save function. They’re omitted here to highlight the main functionality of the code.

The Login API Controller

The login controller hands over pretty much all control to Passport, although you could (and should) add some validation beforehand to check that the required fields have been sent.

For Passport to do its magic and run the strategy defined in the config, we need to call the authenticate method as shown below. This method will call a callback with three possible parameters err, user and info. If user is defined, it can be used to generate a JWT to be returned to the browser:

module.exports.login = function(req, res) {

  passport.authenticate('local', function(err, user, info){
    var token;

    // If Passport throws/catches an error
    if (err) {
      res.status(404).json(err);
      return;
    }

    // If a user is found
    if(user){
      token = user.generateJwt();
      res.status(200);
      res.json({
        "token" : token
      });
    } else {
      // If user is not found
      res.status(401).json(info);
    }
  })(req, res);

};

Securing an API Route

The final thing to do in the back end is make sure that only authenticated users can access the /api/profile route. The way to validate a request is to ensure that the JWT sent with it is genuine, by using the secret again. This is why you should keep it a secret and not in the code.

Configuring the Route Authentication

First we need to install a piece of middleware called express-jwt:

npm install express-jwt --save

Then we need to require it and configure it in the file where the routes are defined. In the sample application, this is [/api/routes/index.js](https://github.com/sitepoint-editors/MEAN-stack-authentication/blob/master/api/routes/index.js). Configuration is a case of telling it the secret, and — optionally — the name of the property to create on the req object that will hold the JWT. We’ll be able to use this property inside the controller associated with the route. The default name for the property is user, but this is the name of an instance of our Mongoose User model, so we’ll set it to payload to avoid confusion:

var jwt = require('express-jwt');
var auth = jwt({
  secret: 'MY_SECRET',
  userProperty: 'payload'
});

Again, don’t keep the secret in the code!

Applying the Route Authentication

To apply this middleware, simply reference the function in the middle of the route to be protected, like this:

router.get('/profile', auth, ctrlProfile.profileRead);

If someone tries to access that route now without a valid JWT, the middleware will throw an error. To make sure our API plays nicely, catch this error and return a 401 response by adding the following into the error handlers section of the main app.js file:

// error handlers
// Catch unauthorised errors
app.use(function (err, req, res, next) {
  if (err.name === 'UnauthorizedError') {
    res.status(401);
    res.json({"message" : err.name + ": " + err.message});
  }
});

Using the Route Authentication

In this example, we only want people to be able to view their own profiles, so we get the user ID from the JWT and use it in a Mongoose query.

The controller for this route is in [/api/controllers/profile.js](https://github.com/sitepoint-editors/MEAN-stack-authentication/blob/master/api/controllers/profile.js). The entire contents of this file look like this:

var mongoose = require('mongoose');
var User = mongoose.model('User');

module.exports.profileRead = function(req, res) {

  // If no user ID exists in the JWT return a 401
  if (!req.payload._id) {
    res.status(401).json({
      "message" : "UnauthorizedError: private profile"
    });
  } else {
    // Otherwise continue
    User
      .findById(req.payload._id)
      .exec(function(err, user) {
        res.status(200).json(user);
      });
  }

};

Naturally, this should be fleshed out with some more error trapping — for example, if the user isn’t found — but this snippet is kept brief to demonstrate the key points of the approach.

That’s it for the back end. The database is configured, we have API endpoints for registering and logging in that generate and return a JWT, and also a protected route. On to the front end!

Create Angular Authentication Service

Most of the work in the front end can be put into an Angular service, creating methods to manage:

  • saving the JWT in local storage
  • reading the JWT from local storage
  • deleting the JWT from local storage
  • calling the register and login API endpoints
  • checking whether a user is currently logged in
  • getting the details of the logged-in user from the JWT.

We’ll need to create a new service called AuthenticationService. With the CLI, this can be done by running ng generate service authentication, and making sure it’s listed in the app module providers. In the example app, this is in the file [/client/src/app/authentication.service.ts](https://github.com/sitepoint-editors/MEAN-stack-authentication/blob/master/client/src/app/authentication.service.ts).

Local Storage: Saving, Reading and Deleting a JWT

To keep a user logged in between visits, we use localStorage in the browser to save the JWT. An alternative is to use sessionStorage, which will only keep the token during the current browser session.

First, we want to create a few interfaces to handle the data types. This is useful for type checking our application. The profile returns an object formatted as UserDetails, and the login and register endpoints expect a TokenPayload during the request and return a TokenResponse object:

export interface UserDetails {
  _id: string;
  email: string;
  name: string;
  exp: number;
  iat: number;
}

interface TokenResponse {
  token: string;
}

export interface TokenPayload {
  email: string;
  password: string;
  name?: string;
}

This service uses the HttpClient service from Angular to make HTTP requests to our server application (which we’ll use in a moment) and the Router service to navigate programmatically. We must inject them into our service constructor.

Then we define four methods that interact with the JWT token. We implement saveToken to handle storing the token into localStorage and onto the token property, a getToken method to retrieve the token from localStorage or from the token property, and a logout function that removes the JWT token from memory and redirects to the home page.

It’s important to note that this code doesn’t run if you’re using server-side rendering, because APIs like localStorage and window.atob aren’t available, and there are details about solutions to address server-side rendering in the Angular documentation.

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import { map } from 'rxjs/operators/map';
import { Router } from '@angular/router';

// Interfaces here

@Injectable()
export class AuthenticationService {
  private token: string;

  constructor(private http: HttpClient, private router: Router) {}

  private saveToken(token: string): void {
    localStorage.setItem('mean-token', token);
    this.token = token;
  }

  private getToken(): string {
    if (!this.token) {
      this.token = localStorage.getItem('mean-token');
    }
    return this.token;
  }

  public logout(): void {
    this.token = '';
    window.localStorage.removeItem('mean-token');
    this.router.navigateByUrl('/');
  }
}

Now let’s add a method to check for this token — and the validity of the token — to find out if the visitor is logged in.

Getting Data from a JWT

When we set the data for the JWT (in the generateJwt Mongoose method) we included the expiry date in an exp property. But if you look at a JWT, it seems to be a random string, like this following example:

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJfaWQiOiI1NWQ0MjNjMTUxMzcxMmNkMzE3YTRkYTciLCJlbWFpbCI6InNpbW9uQGZ1bGxzdGFja3RyYWluaW5nLmNvbSIsIm5hbWUiOiJTaW1vbiBIb2xtZXMiLCJleHAiOjE0NDA1NzA5NDUsImlhdCI6MTQzOTk2NjE0NX0.jS50GlmolxLoKrA_24LDKaW3vNaY94Y9EqYAFvsTiLg

So how do you read a JWT?

A JWT is actually made up of three separate strings, separated by a dot .. These three parts are:

  1. Header — an encoded JSON object containing the type and the hashing algorithm used
  2. Payload — an encoded JSON object containing the data, the real body of the token
  3. Signature — an encrypted hash of the header and payload, using the “secret” set on the server.

It’s the second part we’re interested in here — the payload. Note that this is encoded rather than encrypted, meaning that we can decode it.

There’s a function called atob() that’s native to modern browsers, and which will decode a Base64 string like this.

So we need to get the second part of the token, decode it and parse it as JSON. Then we can check that the expiry date hasn’t passed.

At the end of it, the getUserDetails function should return an object of the UserDetails type or null, depending on whether a valid token is found or not. Put together, it looks like this:

public getUserDetails(): UserDetails {
  const token = this.getToken();
  let payload;
  if (token) {
    payload = token.split('.')[1];
    payload = window.atob(payload);
    return JSON.parse(payload);
  } else {
    return null;
  }
}

The user details that are provided include the information about the user’s name, email, and the expiration of the token, which we’ll use to check if the user session is valid.

Check Whether a User Is Logged In

Add a new method called isLoggedIn to the service. It uses the getUserDetails method to get the token details from the JWT token and checks the expiration hasn’t passed yet:

public isLoggedIn(): boolean {
  const user = this.getUserDetails();
  if (user) {
    return user.exp > Date.now() / 1000;
  } else {
    return false;
  }
}

If the token exists, the method will return if the user is logged in as a boolean value. Now we can construct our HTTP requests to load data, using the token for authorization.

Structuring the API Calls

To facilitate making API calls, add the request method to the AuthenticationService, which is able to construct and return the proper HTTP request observable depending on the specific type of request. It’s a private method, since it’s only used by this service, and exists just to reduce code duplication. This will use the Angular HttpClient service; remember to inject this into the AuthenticationService if it’s not already there:

private request(method: 'post'|'get', type: 'login'|'register'|'profile', user?: TokenPayload): Observable {
  let base;

  if (method === 'post') {
    base = this.http.post(`/api/${type}`, user);
  } else {
    base = this.http.get(`/api/${type}`, { headers: { Authorization: `Bearer ${this.getToken()}` }});
  }

  const request = base.pipe(
    map((data: TokenResponse) => {
      if (data.token) {
        this.saveToken(data.token);
      }
      return data;
    })
  );

  return request;
}

It does require the map operator from RxJS in order to intercept and store the token in the service if it’s returned by an API login or register call. Now we can implement the public methods to call the API.

Calling the Register and Login API Endpoints

Just three methods to add. We’ll need an interface between the Angular app and the API, to call the login and register endpoints and save the returned token, or the profile endpoint to get the user details:

	public register(user: TokenPayload): Observable {
  return this.request('post', 'register', user);
}

public login(user: TokenPayload): Observable {
  return this.request('post', 'login', user);
}

public profile(): Observable {
  return this.request('get', 'profile');
}

Each method returns an observable that will handle the HTTP request for one of the API calls we need to make. That finalizes the service; now to tie everything together in the Angular app.

Apply Authentication to Angular App

We can use the AuthenticationService inside the Angular app in a number of ways to give the experience we’re after:

  1. wire up the register and sign-in forms
  2. update the navigation to reflect the user’s status
  3. only allow logged-in users access to the /profile route
  4. call the protected /api/profile API route.

Connect the Register and Login Controllers

We’ll begin by looking at the register and login forms.

The Register Page

The HTML for the registration form already exists and has NgModel directives attached to the fields, all bound to properties set on the credentials controller property. The form also has a (submit) event binding to handle the submission. In the example application, it’s in [/client/src/app/register/register.component.html](https://github.com/sitepoint-editors/MEAN-stack-authentication/blob/master/client/src/app/register/register.component.html) and looks like this:

	
  
    Full name
    
  
  
    Email address
    
  
  
    Password
    
  
  Register!


The first task in the controller is to ensure our AuthenticationService and the Router are injected and available through the constructor. Next, inside the register handler for the form submit, make a call to auth.register, passing it the credentials from the form.

The register method returns an observable, which we need to subscribe to in order to trigger the request. The observable will emit success or failure, and if someone has successfully registered, we’ll set the application to redirect them to the profile page or log the error in the console.

In the sample application, the controller is in [/client/src/app/register/register.component.ts](https://github.com/sitepoint-editors/MEAN-stack-authentication/blob/master/client/src/app/register/register.component.ts) and looks like this:

	import { Component } from '@angular/core';
import { AuthenticationService, TokenPayload } from '../authentication.service';
import { Router } from '@angular/router';

@Component({
  templateUrl: './register.component.html'
})
export class RegisterComponent {
  credentials: TokenPayload = {
    email: '',
    name: '',
    password: ''
  };

  constructor(private auth: AuthenticationService, private router: Router) {}

  register() {
    this.auth.register(this.credentials).subscribe(() => {
      this.router.navigateByUrl('/profile');
    }, (err) => {
      console.error(err);
    });
  }
}

The Login Page

The login page is very similar in nature to the register page, but in this form we don’t ask for the name, just email and password. In the sample application, it’s in [/client/src/app/login/login.component.html](https://github.com/sitepoint-editors/MEAN-stack-authentication/blob/master//client/src/app/login/login.component.html) and looks like this:


  
    Email address
    
  
  
    Password
    
  
  Sign in!

	

Once again, we have the form submit handler, and NgModel attributes for each of the inputs. In the controller, we want the same functionality as the register controller, but this time called the login method of the AuthenticationService.

In the sample application, the controller is in [/client/src/app/login/login.controller.ts](https://github.com/sitepoint-editors/MEAN-stack-authentication/blob/master/client/src/app/login/login.controller.ts) and look like this:

import { Component } from '@angular/core';
import { AuthenticationService, TokenPayload } from '../authentication.service';
import { Router } from '@angular/router';

@Component({
  templateUrl: './login.component.html'
})
export class LoginComponent {
  credentials: TokenPayload = {
    email: '',
    password: ''
  };

  constructor(private auth: AuthenticationService, private router: Router) {}

  login() {
    this.auth.login(this.credentials).subscribe(() => {
      this.router.navigateByUrl('/profile');
    }, (err) => {
      console.error(err);
    });
  }
}

Now users can register and sign in to the application. Note that, again, there should be more validation in the forms to ensure that all required fields are filled before submitting. These examples are kept to the bare minimum to highlight the main functionality.

Change Content Based on User Status

In the navigation, we want to show the Sign in link if a user isn’t logged in, and their username with a link to the profile page if they are logged in. The navbar is found in the App component.

First, we’ll look at the App component controller. We can inject the AuthenticationService into the component and call it directly in our template. In the sample app, the file is in [/client/src/app/app.component.ts](https://github.com/sitepoint-editors/MEAN-stack-authentication/blob/master/client/src/app/app.component.ts) and looks like this:

import { Component } from '@angular/core';
import { AuthenticationService } from './authentication.service';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html'
})
export class AppComponent {
  constructor(public auth: AuthenticationService) {}
}

That’s pretty simple, right? Now, in the associated template we can use auth.isLoggedIn() to determine whether to display the sign-in link or the profile link. To add the user’s name to the profile link, we can access the name property of auth.getUserDetails()?.name. Remember that this is getting the data from the JWT. The ?. operator is a special way to access a property on an object that may be undefined, without throwing an error.

In the sample app, the file is in [/client/src/app/app.component.html](https://github.com/sitepoint-editors/MEAN-stack-authentication/blob/master/client/src/app/app.component.html) and the updated part looks like this:


  Sign in
  {{ auth.getUserDetails()?.name }}
  Logout


Protect a Route for Logged in Users Only

In this step, we’ll see how to make a route accessible only to logged-in users, by protecting the /profile path.

Angular allows you to define a route guard, which can run a check at several points of the routing life cycle to determine if the route can be loaded. We’ll use the CanActivate hook to tell Angular to load the profile route only if the user is logged in.

To do, this we need to create a route guard service, ng generate service auth-guard. It must implement the CanActivate interface, and the associated canActivate method. This method returns a boolean value from the AuthenticationService.isLoggedIn method (basically checks if the token is found, and still valid), and if the user is not valid also redirects them to the home page:

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

@Injectable()
export class AuthGuardService implements CanActivate {

  constructor(private auth: AuthenticationService, private router: Router) {}

  canActivate() {
    if (!this.auth.isLoggedIn()) {
      this.router.navigateByUrl('/');
      return false;
    }
    return true;
  }
}
	

To enable this guard, we have to declare it on the route configuration. There’s a property called canActivate, which takes an array of services that should be called before activating the route. Ensure you also declare these services in the App NgModule’s providers array. The routes are defined in the App module, which contains the routes like you see here:

const routes: Routes = [
  { path: '', component: HomeComponent },
  { path: 'login', component: LoginComponent },
  { path: 'register', component: RegisterComponent },
  { path: 'profile', component: ProfileComponent, canActivate: [AuthGuardService] }
];
	

With that route guard in place, now if an unauthenticated user tries to visit the profile page, Angular will cancel the route change and redirect to the home page, thus protecting it from unauthenticated users.

Call a Protected API Route

The /api/profile route has been set up to check for a JWT in the request. Otherwise, it will return a 401 unauthorized error.

To pass the token to the API, it needs to be sent through as a header on the request, called Authorization. The following snippet shows the main data service function, and the format required to send the token. The AuthenticationService already handles this, but you can find this in [/client/src/app/authentication.service.ts](https://github.com/sitepoint-editors/MEAN-stack-authentication/blob/master/client/src/app/authentication.service.ts).

base = this.http.get(`/api/${type}`, { headers: { Authorization: `Bearer ${this.getToken()}` }});	

Remember that the back-end code is validating that the token is genuine when the request is made, by using the secret known only to the issuing server.

To make use of this in the profile page, we just need to update the controller, in [/client/src/app/profile/profile.component.ts](https://github.com/sitepoint-editors/MEAN-stack-authentication/blob/master/client/src/app/profile/profile.component.ts) in the sample app. This will populate a details property when the API returns some data, which should match the UserDetails interface.

import { Component } from '@angular/core';
import { AuthenticationService, UserDetails } from '../authentication.service';

@Component({
  templateUrl: './profile.component.html'
})
export class ProfileComponent {
  details: UserDetails;

  constructor(private auth: AuthenticationService) {}

  ngOnInit() {    
    this.auth.profile().subscribe(user => {
      this.details = user;
    }, (err) => {
      console.error(err);
    });
  }
}
	

Then, of course, it’s just a case of updating the bindings in the view ([/client/src/app/profile/profile.component.html](https://github.com/sitepoint-editors/MEAN-stack-authentication/blob/master/)). Again, the ?. is a safety operator for binding properties that don’t exist on first render (since data has to load first).


  
    Full name
    
{{ details?.name }}

  
  
    Email
    
{{ details?.email }}

  

	

And here’s the final profile page, when logged in:

That’s how to manage authentication in the MEAN stack, from securing API routes and managing user details to working with JWTs and protecting routes. If you’ve implemented an authentication system like this in one of your own apps and have any tips, tricks, or advice, be sure to share them in the comments below!

Creating a RESTful Web API with Node.js and Express.js from scratch

Creating a RESTful Web API with Node.js and Express.js from scratch

In this article, I’ll show you step by step how to create a RESTful Web API with Node.js and Express.js by building a simple and useful Todo API. This article assumes you have basic javascript knowledge and terminal using capabilities.

In this article, I’ll show you step by step how to create a RESTful Web API with Node.js and Express.js by building a simple and useful Todo API. This article assumes you have basic javascript knowledge and terminal using capabilities.

You can also build a Web API in Node.js by using another framework except Express.js but Express.js is one of the most popular web framework for Node.js.

You can found the final source code of this Web API in this github repository.

Let’s start to create our mentioned Web API.

Before start

If you have never used Node.js or npm package manager you should install them.

To check whether the Node.js is already installed on your computer, open your terminal and run node -v command. If you see your Node.js version it's installed. Otherwise go to below link.

Click here to download and install Node.js (You can choose LTS version)

And if you don’t have any IDE or text editor for writing javascript I advice you Visual Studio Code.

Click here to download VS Code (Optional)

About express-generator

In fact we could use <a href="https://expressjs.com/en/starter/generator.html" target="_blank">express-generator</a> tool which designed to creating an Express Web API quickly but I want to create this API from scratch because of that tool puts some extra files and folder structures that we don't need them now. But you can use this useful tool next time on creating new Web API. I won't use it now due to keep article simple.

Creating Project

Go to your workspace root folder and create a new folder there named "todo-api".

Then create "package.json" and "server.js" files into "todo-api" folder like below.

package.json

{
    "name": "todo-api",
    "version": "1.0.0",
    "scripts": {
        "start": "node server.js"
    },
    "dependencies": {
        "express": "^4.16.4"
    }
}

server.js

const http = require('http');
const express = require('express');
const app = express();
app.use(express.json());
app.use('/', function(req, res) {
    res.send('todo api works');
});
const server = http.createServer(app);
const port = 3000;
server.listen(port);
console.debug('Server listening on port ' + port);

After creating above files open your terminal in the "todo-api" folder and run npm installcommand.

This command will be install your project dependencies which pointed at the "package.json" file.

After finished package download process, downloaded dependency files will be installed into"node_modules" folder at the root of the "todo-api" folder.

After finished package installing then run npm start to start our Web API.

Now our Web API listening. To see result open your web browser then write localhost:3000 to address bar and press enter.

As result you’ll see our request handler response in your browser: “todo api works”.

This is a dead simple Express.js Web API. And it needs the some development. For example we need to an api endpoint to get todo items. So let’s add a new API endpoint for this.

Create a new folder named "routes" in the root of the "todo-api" folder.

Then create a "items.js" file inside of "routes" folder and put following codes inside it.

Your final folder structure should be like below;

/todo-api
/node_modules
/routes
    items.js
package.json
server.js

items.js

const express = require('express');
const router = express.Router();
const data = [
    {id: 1, title: 'Finalize project', order: 1, completed: false, createdOn: new Date()},
    {id: 2, title: 'Book ticket to London', order: 2, completed: false, createdOn: new Date()},
    {id: 3, title: 'Finish last article', order: 3, completed: false, createdOn: new Date()},
    {id: 4, title: 'Get a new t-shirt', order: 4, completed: false, createdOn: new Date()},
    {id: 5, title: 'Create dinner reservation', order: 5, completed: false, createdOn: new Date()},
];
router.get('/', function (req, res) {
    res.status(200).json(data);
});
router.get('/:id', function (req, res) {
    let found = data.find(function (item) {
        return item.id === parseInt(req.params.id);
    });
    if (found) {
        res.status(200).json(found);
    } else {
        res.sendStatus(404);
    }
});
module.exports = router;

Initial code of "items.js" file contains two endpoints. First one gets all todo items and second one gets one item which matches given id parameter.

Before testing items routes we should register it in the "server.js" file.

Modify "server.js" file like below to register new item routes.

server.js

const http = require('http');
const express = require('express');
const itemsRouter = require('./routes/items');
const app = express();
app.use(express.json());
app.use('/items', itemsRouter);
app.use('/', function(req, res) {
    res.send('todo api works');
});
const server = http.createServer(app);
const port = 3000;
server.listen(port);
console.debug('Server listening on port ' + port);

Now run npm start to start our Web API.

Then open your web browser and write localhost:3000/items to address bar and press enter.

You’ll see todo items json array in the response body.

And write localhost:3000/items/3 to address bar and press enter.

You’ll see the todo item which has id 3 in the response body.

But not finished up yet.

CRUD Operations and HTTP methods

I think we’ll need CRUD operations to Create, Read, Update and Delete todo items.

We have already two endpoints for getting items. So we need Create, Update and Delete endpoints.

Let’s add also these endpoints into the items.js file.

Our final "items.js" file and endpoints should be like below.

const express = require('express');
const router = express.Router();

const data = [
  {id: 1, title: 'Finalize project',          order: 1, completed: false, createdOn: new Date()},
  {id: 2, title: 'Book ticket to London',     order: 2, completed: false, createdOn: new Date()},
  {id: 3, title: 'Finish last article',       order: 3, completed: false, createdOn: new Date()},
  {id: 4, title: 'Get a new t-shirt',         order: 4, completed: false, createdOn: new Date()},
  {id: 5, title: 'Create dinner reservation', order: 5, completed: false, createdOn: new Date()},
];

router.get('/', function (req, res) {
  res.status(200).json(data);
});

router.get('/:id', function (req, res) {
  let found = data.find(function (item) {
    return item.id === parseInt(req.params.id);
  });

  if (found) {
    res.status(200).json(found);
  } else {
    res.sendStatus(404);
  }
});

router.post('/', function (req, res) {
  let itemIds = data.map(item => item.id);
  let orderNums = data.map(item => item.order);

  let newId = itemIds.length > 0 ? Math.max.apply(Math, itemIds) + 1 : 1;
  let newOrderNum = orderNums.length > 0 ? Math.max.apply(Math, orderNums) + 1 : 1;

  let newItem = {
    id: newId,
    title: req.body.title,
    order: newOrderNum,
    completed: false,
    createdOn: new Date()
  };

  data.push(newItem);

  res.status(201).json(newItem);
});

router.put('/:id', function (req, res) {
  let found = data.find(function (item) {
    return item.id === parseInt(req.params.id);
  });

  if (found) {
    let updated = {
      id: found.id,
      title: req.body.title,
      order: req.body.order,
      completed: req.body.completed
    };

    let targetIndex = data.indexOf(found);

    data.splice(targetIndex, 1, updated);

    res.sendStatus(204);
  } else {
    res.sendStatus(404);
  }
});

router.delete('/:id', function (req, res) {
  let found = data.find(function (item) {
    return item.id === parseInt(req.params.id);
  });

  if (found) {
    let targetIndex = data.indexOf(found);

    data.splice(targetIndex, 1);
  }

  res.sendStatus(204);
});

module.exports = router;

Short Explanation

I wanna explain shortly some points of our last codes.

First of all you must have noticed that our api works on a static data and keeps it on memory. All of our GET, POST, PUT and DELETE http methods just manipulate a json array. The purpose of this is to keep article simple and draw attention to the Web API structure.

Due to this situation our POST method has some extra logic such as calculating next item ids and order numbers.

So you can modify logic and data structures in these http methods to use a database or whatever you want.

Testing API with Postman

We have tested the GET methods of our Web API in our web browser and seen responses. But we can’t test directly POST, PUT and DELETE http methods in web browser.

If you want to test also other http methods you should use Postman or another http utility.

Now I’ll show you how to test the Web API with Postman

Before we start click here and install Postman.

When you first launch Postman after installing you’ll see start window. Close this start window by clicking close button on top right corner. Then you must see following screen.

An empty Postman request

Sending GET Request

Before sending a request to API we should start it by running npm startcommand as we do before.

After start the Web API and seeing “Server listening on…” message write localhost:3000/itemsto address bar as seen below and click Send button. You'll see todo items array as API response like below.

Sending a GET request with Postman

You can try similarly by giving an item id in request url like this localhost:3000/items/3

Sending POST Request

To sending a POST request and create a new todo item write localhost:3000/items to address bar and change HTTP verb to POST by clicking arrow at front of the address bar as seen below.

Sending a POST request with Postman

Before sending the POST request you should add request data to body of the request by clicking body tab and selecting raw and JSON as seen below.

Attaching a JSON body to POST request in Postman

Now click Send button to send POST request to the Web API. Then you must get “201 Created” http response code and seeing created item in the response body.

To see the last status of todo items send a get request to localhost:3000/itemsaddress. You must see newly created item at the end of the list.

Sending PUT Request

Sending PUT request is very similar to sending POST request.

The most obvious difference is request url should be pointed specific item like this localhost:3000/items/3

And you should choose PUT as http verb instead of POST and send all of the required data in the request body unlike POST.

For example you could send a JSON body in the PUT request as below.

An example JSON body for PUT request

{
    "title": "New title of todo item",
    "order": 3,
    "completed": false
}

When you click Send button you must get “204 No Content” http response code. You can check item you updated by sending a get request.

Sending DELETE Request

To send a DELETE request, change the request url to address a specific item id like this localhost:3000/items/3

And select DELETE as http verb and click Send button.

You must get “204 No Content” http response code as result of the DELETE operation.

Send a get request and see the last status of list.

About the DELETE Http Request

I want to say a few words about DELETE http request. You must have noticed something in our delete code. DELETE request returns “204 No Content” every situation.

Http DELETE requests are idempotent. So what that mean? If you delete a resource on server by sending DELETE request, it’s removed from the collection. And every next DELETE request on the same resource won’t change outcome. So you won’t get “404 Not Found” in the second request. Each request returns same response whether succeed or not. That’s mean idempotent operation.

Conclusion

Finally we’ve tested all http methods of our Web API.

As you can see, it works just fine.

Thanks for reading ❤

If you liked this post, share it with all of your programming buddies!

Develop this one fundamental skill if you want to become a successful developer

Throughout my career, a multitude of people have asked me&nbsp;<em>what does it take to become a successful developer?</em>

Throughout my career, a multitude of people have asked me what does it take to become a successful developer?

It’s a common question newbies and those looking to switch careers often ask — mostly because they see the potential paycheck. There is also a Hollywood level of coolness attached to working with computers nowadays. Being a programmer or developer is akin to being a doctor or lawyer. There is job security.

But a lot of people who try to enter the profession don’t make it. So what is it that separates those who make it and those who don’t? 

Read full article here

How to Build a RESTful API using Node, Express and MongoDB

How to Build a RESTful API using Node, Express and MongoDB

In this tutorial, we walk you through seven steps for developing a RESTFul API using popular JavaScript frameworks such as Node and Express. In doing so, we learn how to integrate our API with the MongoDB database

Without a doubt, Application Programming Interfaces or APIs play a very important role in communication and data exchange between servers and services. From computers to smartphones and Internet of Things (IoT), applications talk and exchange info via APIs. Almost every day we use or interact with an API service, and many sites use a custom API to scale up their website. As such, learning how to develop a custom API adds lots of value to your developer profile.

Motivated by the importance of APIs and the popularity of JavaScript (JS), we’d like to show you how to develop a custom RESTful API using Node.JS and MongoDB. Along the way, you will be able to leverage and improve your JS skills. Developers can also expand this tutorial by using MySQL instead of MongoDB or securing API by adding authentication call-backs.

About the Project

This tutorial requires an intermediate knowledge of JavaScript and Node.JS along with basic knowledge of, JSON, NPM, MongoDB (a No-SQL database), and Express.JS. This tutorial is geared toward back-end web development as we will not discuss HTML, CSS or Angular. Click here to download the .zip project file for this tutorial. Click here to see its live demo.

Tutorial Overview

In this tutorial, we walk you through seven steps for developing a RESTFul API using popular JavaScript frameworks such as Node.JS and Express.JS. In doing so, we learn how to integrate our API with the MongoDB database. Here are the main steps:

1. Project Initialization
2. Install Application Dependencies
3. Run the Application
4. Test the Application
5. Establish Connection with MongoDB
6. Build REST API Endpoints
7. Put Things Together

Some background on REST APIs is helpful for understanding and following this tutorial.

RESTful API Overview

REST stands for REpresentational State Transfer. When a RESTful API is called, the server will transfer to the client a representation of the state of the requested resource. For example, when a developer calls OpenWeather API to fetch weather for a specific city (the resource), the API will return the state of that city, including the temperature, humidity, wind speed, current forecast, extended forecast, and more. The representation of the state can be in a JSON format, and for most web APIs, this is indeed the case. Other possible data formats include XML or HTML. What does the server does when you call it depends on two things that you need to provide to the server:
1. An identifier for the resource. – This is the URL for the resource, also known as the endpoint. In fact, URL stands for Uniform Resource Locator.
2. The operation you want the server to perform on that resource, in the form of an HTTP method. The common HTTP methods are GET, POST, PUT, and DELETE.

Prerequisites:
  1. Install Node.js by following the appropriate guidelines for your local machine given here.
  2. You may use Node Version Manager to install multiple versions of Node.js on your local machine.
  3. Signup for MongoDB Atlas which is a cloud database as a service. We’re using MongoDB Atlas which offers us a free sandbox environment so that we can focus on building our REST API.
  4. Code Editor like Visual Studio Code or Sublime Text
1. Project Initialization

We need to create an application folder where our application will reside. To initialize the application, we need to create a package.json file, which will hold all the metadata for the node application. The file allows npm to handle installing the package dependencies and scripts we write to handle the application.
Assuming that you’ve Node.js installed, we can initialize the application from the command line by executing the following:

npm init -y

The above command will create a package.json file.

2. Install Application Dependencies

We need a file that can act as command central for our application. This file will be executed first by npm when we ask it to run our application. This file can have object instances of multiple modules that we write as well as third party modules that we install from the npm directory.
These modules are dependencies of the project. We’ll install a few of these dependencies now:

touch app.js
npm install express mongodb body-parser --save

Using the above commands we created a file called app.js which will be the main entry point to the application, and we installed a few dependencies that are essential to start our application.
These dependencies are:
1. Express: This is a Node.js framework.
2. MongoDB: This is an official module provided by the MongoDB team to help our Node.js application communicate with MongoDB.
3. body-parser: This package will allow us to handle request bodies with Express.

Why use body-parser?

Let’s say you are sending an HTML form data to Node.js server i.e. you made a request to the server. HTTP sends your form data in bits and pieces which are intended to get assembled as they reach their destination. To extract these bits and pieces of data and assemble it so it is in a format that can be useful, we use a body-parser middleware.

3. Run the Application

Let’s run the code for our application –

const Express = require("express");
const BodyParser = require("body-parser");
const MongoClient = require("mongodb").MongoClient;
const ObjectId = require("mongodb").ObjectID;
var app = Express();
app.use(BodyParser.json());
app.use(BodyParser.urlencoded({ extended: true }));
app.listen(5000, () => {});

Here, we’re importing our downloaded dependencies. We initialize the express framework by utilizing the Express object that will use the express framework to start the server and run our application at a given port and configure the body-parser, which is a middleware to parse incoming chunks of data.

4. Test the Application

We can test the application by running the following:

node app.js

The server will be listening on port 5000 for requests according to the above boilerplate we wrote.

5. Establish Connection with MongoDB

We will need the connection string for MongoDB. This can be found in the Atlas dashboard by choosing Clusters, then the Overview tab followed by the Connect button.
We need to add the string to our app.js and make the following changes to the code.

Side note: In an ideal world, developers will benefit from adding it to an .env file to keep their environment variables separate from the application.

const Express = require("express");
const BodyParser = require("body-parser");
const MongoClient = require("mongodb").MongoClient;
const ObjectId = require("mongodb").ObjectID;
const CONNECTION_URL = <YOUR CONNECTION STRING WITH USERNAME AND PASSWORD>;
const DATABASE_NAME = "accounting_department";


var app = Express();
app.use(BodyParser.json());
app.use(BodyParser.urlencoded({ extended: true }));
var database, collection;

app.listen(5000, () => {
    MongoClient.connect(CONNECTION_URL, { useNewUrlParser: true }, (error, client) => {
        if(error) {
            throw error;
        }
        database = client.db(DATABASE_NAME);
        collection = database.collection("personnel");
        console.log("Connected to `" + DATABASE_NAME + "`!");
    });
});

Here, we’ve defined the connection string to use. You need to add a CONNECTION_URL property according to the connection string you received from MongoDB Atlas. We’ve also defined the database name which we wish to create (if not already present and collection).
We establish a connection once we start again the application and use globally defined variables so that they can be used in each of our endpoints.

Now let’s start designing our HTTP consumable API endpoints.

6. Build REST API Endpoints

Now we’re going to develop endpoints for creating and querying the data. Let’s create an endpoint to add the data. Add the following code to app.js:

app.post("/personnel", (request, response) => {
    collection.insert(request.body, (error, result) => {
        if(error) {
            return response.status(500).send(error);
        }
        response.send(result.result);
    });
});

We aren’t doing any data validation, but when a client makes a POST request to the /personnel endpoint, we take the body and insert it into our collection. Depending on the success or error response of the database, we return information back to the client.

7. Put Things Together

Now, things are starting to come together. Let’s test out our application.

curl -X POST \
    -H 'content-type:application/json' \
    -d '{"firstname":"John","lastname":"Doe"}' \
    http://localhost:5000/personnel

If you do not receive any errors, you’ll see the personnel record for John Doe added into MongoDB database of accounting_department and under collection personnel. Feel free to add more records to your database.

GET

Now let’s create an endpoint to retrieve all the records data. Add the following code to app.js:

 app.get("/personnel", (request, response) => {
    collection.find({}).toArray((error, result) => {
        if(error) {
            return response.status(500).send(error);
        }
        response.send(result);
    });
});

The goal here is to return all data in our collection representing people. We have no query conditions, hence the empty {} in the find command, and the results get converted into an array.
Let’s test this out using cURL, a command-line tool for transferring data and supports HTTP; a very good ad-hoc tool for testing REST services.

curl -X GET http://localhost:5000/personnel

GET (by ID)

By now let’s assume you’ve added more records into your database. API consumers will need to retrieve a single record according to its ID.

Write the following endpoint to your app.js:

app.get("/person/:id", (request, response) => {
    collection.findOne({ "_id": new ObjectId(request.params.id) }, (error, result) => {
        if(error) {
            return response.status(500).send(error);
        }
        response.send(result);
    });
});

We’re going to use a route parameter to get specific personnel information from MongoDB. Parameters are options you can pass with the endpoint (such as specifying the response format or the amount returned) to influence the response. This time around we have a route parameter called id which will represent an object id in MongoDB. Using the findOne method, we can get a single record based on the criteria included in the object. The id isn’t a string which is why we have to use the ObjectId.

Depending on the actual data in our database, we can do a cURL command similar to this:

curl -X GET http://localhost:5000/personnel/4b103f89403f841059524fd1
Conclusion

In this tutorial, we’ve learned how to develop a custom API and connect it with MongoDB to fetch and manipulate the data. From here, you can take different steps. For instance, you can expand this project by adding more features like data validation to it. You can also improve the API security and salability by following Node.JS best practices. Lastly, you can try this tutorial with MySQL database or another server-side coding language like PHP or Django.

What do you think of this tutorial? What tools are you using to develop REST APIs?