Social Login via Google & Facebook to Your Single-page App

Social Login via Google & Facebook to Your Single-page App

The use of social login providers makes it very quick and easy to add user login and registration to your application. The fact that this uses browser redirects to send the user to the social login provider and

Increasingly, we are seeing web applications that are developed using a single page architecture, where the entire application is loaded into the browser as JavaScript and then all interactions with the server are carried out using HTTP based APIs that return JSON documents. Often, these applications will require some level of user-restricted interactions, e.g. for storing user profile details. Where this was a relatively simple task to implement in a traditional HTML based application, this is trickier in a single page application that needs to authenticate every API request.

This article will demonstrate a technique using the Passport.js library to implement social logins using a variety of providers, and leading from that to token-based authentication for the later API calls.

All of the source code for this article is available for download from our GitHub repository.

Why Use Social Sign-in for Your SPA?

When implementing a login mechanism on your web application, there are a number of concerns to take into account.

  • How should your UI handle authentication itself?
  • How should you store user information?
  • How should you best secure the user credentials?

These, and many more questions, need to be taken into consideration before you embark on writing a login portal. But, there is a better way.

Many sites, social networks chiefly among them, allow you to use their platforms for authentication of your own applications. This is achieved using a number of different APIs – OAuth 1.0, OAuth 2.0, OpenID, OpenID Connect, etc.

Implementing your login flow by using these social login technologies offers a number of advantages.

  • You are no longer responsible for rendering the UI for the user to authenticate with.
  • You are no longer responsible for storing and securing sensitive user details.
  • The user is able to use a single login for accessing multiple sites.
  • If the user feels their password has been compromised, they can reset it once and benefit across many sites.
  • Often, the service that provides the authentication functionality will make other details available. This can be used, for example, to automatically register users that have never used your site before, or to allow you to post updates to their profile on their behalf.
Why Use Token-based Authentication for Your API?

Any time a client requires access to your API, you will need some way to determine who they are and whether the access is permitted or not. There are several ways of achieving this, but the principal options are:

  • Session-based authentication
  • Cookie-based authentication
  • Token-based authentication

Session-based authentication requires some way for your API service to associate a session with the client. This is often very straightforward to set up, but can suffer if you are deploying your API across multiple servers. You are also at the mercy of the mechanism that your server uses for session management and expiry, which might be out of your control.

Cookie-based is where you simply have some identifier stored in a cookie, and this is used to automatically identify the API request. This means that you need some mechanism of setting the cookie in the first place, and you risk leaking it on subsequent requests, since cookies are automatically included in all (suitable) requests to the same host.

Token-based is a variation on the cookie-based authentication, but putting more control in your hands. Essentially you generate a token in the same way as in a cookie-based authentication system, but you will include it with requests yourself — normally in the “Authorization” header or else directly in the URL. This means that you are completely in control of storing the token, which requests will include it, and so on.

Note: even though the HTTP Header is called “Authorization”, we are actually doing authentication with it. This is because we are using it to ascertain “who” the client is, not “what” the client is allowed to do.

The strategy that is used for generating the token is important as well. These tokens can either be reference tokens, which means that they are nothing more than an identifier that the server uses to look up the real details. Or complete tokens, which means that the token contains all of the information needed already.

Reference tokens have a significant security advantage in that there is absolutely no leakage to the client of the users credentials. There is a performance penalty though, in that you need to resolve the token into the actual credentials on every single request made.

Complete tokens are the opposite. They expose the user credentials to anyone who can understand the token, but because the token is complete there is no performance penalty on looking it up.

Often, Complete Tokens will be implemented using the JSON Web Tokens standard, since this has allowances in it for improving the security of the tokens. Specifically, JWTs allow for the token to be cryptographically signed, meaning that you can guarantee that the token has not been tampered with. There is also provision for them to be encrypted, meaning that without the encryption key the token can not even be decoded.

If you’d like a refresher on using JWTs in Node, check out our tutorial: Using JSON Web Tokens with Node.js.

The other downside to using a complete token is one of size. A reference token could be implemented, for example, using a UUID which would have a length of 36 characters. Conversely, a JWT can easily be hundreds of characters long.

For this article we are going to use JWT tokens to demonstrate how they can work. However, when you implement this for yourself you will need to decide on whether you wish to use reference or complete tokens, and what mechanism you will use for these.

What Is Passport?

Passport is a set of modules for Node.js that implements authentication in your web application. It plugs into many Node based web servers very easily, and works with a modular structure to implement the login mechanisms that you need with a minimal of bloat.

Passport is a powerful suite of modules that cover a large range of authentication requirements. Using these we are able to have a pluggable setup that allows different authentication requirements for different endpoints. The authentication systems used can be as simple as checking for a special value in the URL all the way up to depending on third party providers to do all of the work for us.

For this article we are going to be making use of the passport-google-oauth, passport-facebook and passport-jwt modules, allowing us to implement both social logins and JWT token-based authentication for the API endpoints.

The passport-jwt module will be used to require that certain endpoints — our actual API endpoints that need authentication to access — will have a valid JWT present in the request. The passport-google-oauth and passport-facebook modules will be used to provide endpoints that authenticate against Google and Facebook respectively, and then generate a JWT that can be used to access the other endpoints in the application.

Implementing Social Logins for Your Single Page Application

From here, we are going to walk through taking a trivial single page application and implementing social logins in it. This application is written using Express, with a simple API providing one secured and one insecure endpoint. The source code for this can be checked out from https://github.com/sitepoint-editors/social-logins-spa if you wish to follow along. This application can be built by executing npm install inside the downloaded source code — to download all of the dependencies — and then run by executing node src/index.js.

In order to successfully use the application you will need to register for social login credentials with Google and Facebook, and make the credentials available to the application. Full instructions are available in the demo application’s README file. These are accessed as environment variables. As such, the application can be run as follows:

# Linux / OS X
$ export GOOGLE_CLIENTID=myGoogleClientId
$ export GOOGLE_CLIENTSECRET=myGoogleClientSecret
$ export FACEBOOK_CLIENTID=myFacebookClientId
$ export FACEBOOK_CLIENTSECRET=myFacebookClientSecret
$ node src/index.js

# Windows
> set GOOGLE_CLIENTID=myGoogleClientId
> set GOOGLE_CLIENTSECRET=myGoogleClientSecret
> set FACEBOOK_CLIENTID=myFacebookClientId
> set FACEBOOK_CLIENTSECRET=myFacebookClientSecret
> node src/index.js

The end result of this process is going to add token authentication support (using JSON Web Tokens) to our secured endpoints, and then add social login support (using Google and Facebook) in order to obtain a token for the rest of the application to use. This means that you need to authenticate with the social provider once, and having done so, use the generated JWT for all future API calls in to the application

JWTs are a particular good choice for our scenario because they are entirely self contained whilst still being secure. A JWT is made of a JSON payload and a cryptographic signature. The payload contains details of the authenticated user, the authenticating system and the validity period of the token. The signature then ensures that it can not be forged by malicious third parties — only someone with the signing key would be able to produce the tokens.

As you follow this article, you will see frequent references to a config.js module included as part of the application. This is used to configure the application, and makes use of the Node-convict module for external configuration. The configuration that is used throughout this article is as follows:

  • http.port – The port that the application runs on. This defaults to 3000, and is overridden using the “PORT” environment variable.
  • authentication.google.clientId – The Google client ID used for Google authentication. This is provided to the application using the “GOOGLE_CLIENTID” environment variable
  • authentication.google.clientSecret – The Google client secret used for Google authentication. This is provided to the application using the “GOOGLE_CLIENTSECRET” environment variable.
  • authentication.facebook.clientId – The Facebook client ID used for Facebook authentication. This is provided to the application using the “FACEBOOK_CLIENTID” environment variable
  • authentication.facebook.clientSecret – The Facebook client secret used for Facebook authentication. This is provided to the application using the “FACEBOOK_CLIENTSECRET” environment variable.
  • authentication.token.secret – The secret used to sign the JWT used for our authentication token. This defaults to “mySuperSecretKey”.
  • authentication.token.issuer – The Issuer stored inside the JWT. This is an indication of which service issued the token, in scenarios where one authentication service serves many applications.
  • authentication.token.audience – The audience stored inside the JWT. This is an indication of which service the token is intended for, in scenarios where one authentication service serves many applications.

Integrating Passport

Before it can be used in your application, Passport needs a small amount of setup. This is nothing more than making sure the module is installed, and initializing the middleware in your Express application.

The module we need for this stage is the passport module, and then to set up the middleware we simply need to add it to our Express app.

// src/index.js
const passport = require('passport');
.....
app.use(passport.initialize());

If you were to follow the instructions from the Passport website then it would have you set up session support – by use of the passport.session() call. We are not making use of any session support in our application, so this is unnecessary. This is because we are implementing a stateless API so we will provide authentication on every request, instead of persisting it in a session.

Implementing JWT Token Auth for the Secured Endpoint

Setting up JWT Token Authentication is relatively simple with Passport. We will be making use of the passport-jwt module, which does all of the hard work for us. This module looks for an “Authorization” header where the value starts “JWT “, and treats the rest of the header as the JWT token to use for authentication. It then decodes the JWT and makes the values stored inside it available for your own code to manipulate — to do user lookups, for example. If the JWT is not valid, e.g. if the signature is invalid, the token has expired… then the request will be unauthenticated without any extra involvement from your own code.

Configuring the JWT token authentication is then a case of doing as follows:

// src/authentication/jwt.js
const passport = require('passport');
const passportJwt = require('passport-jwt');
const config = require('../config');
const users = require('../users');

const jwtOptions = {
  // Get the JWT from the "Authorization" header.
  // By default this looks for a "JWT " prefix
  jwtFromRequest: passportJwt.ExtractJwt.fromAuthHeader(),
  // The secret that was used to sign the JWT
  secretOrKey: config.get('authentication.token.secret'),
  // The issuer stored in the JWT
  issuer: config.get('authentication.token.issuer'),
  // The audience stored in the JWT
  audience: config.get('authentication.token.audience')
};

passport.use(new passportJwt.Strategy(jwtOptions, (payload, done) => {
  const user = users.getUserById(parseInt(payload.sub));
  if (user) {
      return done(null, user, payload);
  }
  return done();
}));

In the above, we have a couple of internal modules that we make use of:

  • config.js – This contains our configuration properties for the entire application. It can be assumed that these are configured already, and that values are readily available for use
  • users.js – This is the user store for the application. This allows for users to be loaded and created — here we simply load a user by their internal ID.

Here, we are configuring the JWT decoder with a known secret, issuer and audience, and we are informing the strategy that it should get the JWT from the Authorization header. If either of the issuer or audience do not match what is stored in the JWT then authentication will fail. This gives us another level of anti-forgery protection, albeit a very simple one.

Token decoding is handled entirely by the passport-jwt module, and all we need to do is provide the configuration that corresponds to the configuration that was used to generate the token in the first place. Because JWT is a standard, any modules that follow the standard are able to work together perfectly well.

When the token is successfully decoded, it is then passed it as a payload to our callback. Here we simply try to look up the user identified by the “subject” from the token. In reality you might do extra checks, for example to ensure the token has not been revoked.

If the user is found, we provide it to Passport, which will then make it available to the rest of the request processing as req.user. If the user is not found, then we provide no user to Passport, which will then consider authentication to have failed.

This can now be wired in to a request handler so that the request needs authentication to succeed:

// src/index.js
app.get('/api/secure',
  // This request must be authenticated using a JWT, or else we will fail
  passport.authenticate(['jwt'], { session: false }),
  (req, res) => {
    res.send('Secure response from ' + JSON.stringify(req.user));
  }
);

Line 3 above is the magic that makes Passport process the request. This causes Passport to run the “jwt” strategy that we have just configured on the incoming request, and either allow it to proceed or else fail immediately.

We can see this in action by running the application — by executing node src/index.js — and trying to access this resource:

$ curl -v http://localhost:3000/api/secure
> GET /api/secure HTTP/1.1
> Host: localhost:3000
> User-Agent: curl/7.51.0
> Accept: */*
>
< HTTP/1.1 401 Unauthorized
< X-Powered-By: Express
< Date: Tue, 13 Jun 2017 07:53:10 GMT
< Connection: keep-alive
< Content-Length: 12
<
Unauthorized

We don’t provide any Authorization header, and it fails to allow us to proceed.
However, if you were to provide a valid Authorization header you would get a successful response:

$ curl -v http://localhost:3000/api/secure -H "Authorization: JWT eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE0OTczNDAzNzgsImV4cCI6MTQ5NzM0Mzk3OCwiYXVkIjoic29jaWFsLWxvZ2lucy1zcGEiLCJpc3MiOiJzb2NpYWwtbG9naW5zLXNwYSIsInN1YiI6IjAifQ.XlVnG59dX-SykXTJqCmvz_ALvzPW-yGZKOJEGFZ5KUs"
> GET /api/secure HTTP/1.1
> Host: localhost:3000
> User-Agent: curl/7.51.0
> Accept: */*
> Authorization: JWT eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE0OTczNDAzNzgsImV4cCI6MTQ5NzM0Mzk3OCwiYXVkIjoic29jaWFsLWxvZ2lucy1zcGEiLCJpc3MiOiJzb2NpYWwtbG9naW5zLXNwYSIsInN1YiI6IjAifQ.XlVnG59dX-SykXTJqCmvz_ALvzPW-yGZKOJEGFZ5KUs
>
< HTTP/1.1 200 OK
< X-Powered-By: Express
< Content-Type: text/html; charset=utf-8
< Content-Length: 60
< ETag: W/"3c-2im1YD4hSDFtwS8eVcEUzt3l5XQ"
< Date: Tue, 13 Jun 2017 07:54:37 GMT
< Connection: keep-alive
<
Secure response from {"id":0,"name":"Graham","providers":[]}

In order to perform this test, I manually generated a JWT by visiting https://www.jsonwebtoken.io, and filling in the form there. The “Payload” that I used was

{
  "iat": 1497340378, // Tuesday, 13 June 2017 07:52:58 UTC
  "exp": 1497343978, // Tuesday, 13 June 2017 08:52:58 UTC
  "aud": "social-logins-spa",
  "iss": "social-logins-spa",
  "sub": "0"
}

And the “Signing Key” was “mySuperSecretKey”, as taken from the configuration.

Supporting Token Generation

Now that we can access resources only with a valid token, we need a way to actually generate the tokens.
This is done using the jsonwebtoken module, building a JWT containing the correct details and signed with the same key as used above.

// src/token.js
const jwt = require('jsonwebtoken');
const config = require('./config');

// Generate an Access Token for the given User ID
function generateAccessToken(userId) {
  // How long will the token be valid for
  const expiresIn = '1 hour';
  // Which service issued the token
  const issuer = config.get('authentication.token.issuer');
  // Which service is the token intended for
  const audience = config.get('authentication.token.audience');
  // The signing key for signing the token
  const secret = config.get('authentication.token.secret');

  const token = jwt.sign({}, secret, {
    expiresIn: expiresIn,
    audience: audience,
    issuer: issuer,
    subject: userId.toString()
  });

  return token;
}

Note that we use the exact same configuration settings for the audience, issuer and secret when generating the JWT. We also specify that the JWT will have an expiry period of one hour. This could be any period that you deem sensible for your application, or even pulled from the configuration so that it can be changed easily.

In this case, no JWT ID is specified, but this can be used to generate a completely unique ID for the token — using a UUID for example. This then gives you a way to revoke tokens and store a collection of revoked IDs in a data store and check that the JWT ID is not on the list when processing the JWT in the Passport strategy.

Social Login Providers

Now that we have the ability to generate tokens, we need a way for users to actually log in. This is where the social login providers come in. We will add the ability for a user to be redirected to a social login provider, and on success to generate a JWT Token and provide it to the browser’s JavaScript engine for use in future requests.
We have almost all of the pieces for this in place, we just need to plug them together.

Social login providers in Passport come in two parts. First there is the need to actually configure Passport for the social login provider, using the appropriate plugins. Secondly there is a need to have Express routes that the user is directed to in order to start the authentication, and for the user to be redirected back to when authentication is successful.

We will be opening these URLs in a new child browser window, which we will be able to close on completion, and which is able to call JavaScript methods inside of the window that opened it. This means that the process is relatively transparent to the user – at most they will see a new window open asking for their credentials, but at best they might see nothing apart from the fact that they are now logged in.

The browser side of this will need to consist of two parts. The view for the popup window, and the JavaScript that handles this in the main window. This can be done easily enough to integrate with any framework, but for this example we are going to use vanilla JavaScript for simplicity reasons.

The main page JavaScript simply needs something like this:

// src/public/index.html
let accessToken;

function authenticate(provider) {
  window.authenticateCallback = function(token) {
    accessToken = token;
  };

  window.open('/api/authentication/' + provider + '/start');
}

This registers a global function object on the window (named authenticateCallback) which will store the access token, and then opens our route to start authentication, which we are accessing on /api/authentication/{provider}/start.

This function can then be triggered by whatever means you desire to initiate authentication. This is normally a login link in the header area somewhere, but the details are entirely up to your application.

The second part of this is the view to be rendered on successful authentication. In this case we are using Mustache for simplicity, but this would use whatever view technology makes the most sense to you.

<!-- src/public/authenticated.html -->
<!DOCTYPE html>
<html>
  <head>
    <title>Authenticated</title>
  </head>
  <body>
    Authenticated successfully.

    <script type="text/javascript">
      window.opener.authenticateCallback('{{token}}');
      window.close();
    </script>
  </body>
</html>

Here we simply have a bit of JavaScript that calls the authenticateCallback method from above on the opener of this window, i.e. on the main application window, and then we close ourselves.

At this point, the JWT Token will be available in the main application window for whatever purpose you desire.

Implementing Google Authentication

Authenticating against Google will be done using the passport-google-oauth module. This needs to be supplied three pieces of information:

  • Client ID
  • Client Secret
  • Redirect URL

The Client ID and secret are obtained by registering your application at the Google Developer Console. The redirect URL is the URL inside your application that the user will be sent back to when they have signed in with their Google credentials. This will be dependent on how and where the application is deployed, but for now we are going to hard-code it.

Our Passport configuration for Google Authentication will then look like this:

// src/authentication/google.js
const passport = require('passport');
const passportGoogle = require('passport-google-oauth');
const config = require('../config');
const users = require('../users');

const passportConfig = {
  clientID: config.get('authentication.google.clientId'),
  clientSecret: config.get('authentication.google.clientSecret'),
  callbackURL: 'http://localhost:3000/api/authentication/google/redirect'
};

if (passportConfig.clientID) {
  passport.use(new passportGoogle.OAuth2Strategy(passportConfig, function (request, accessToken, refreshToken, profile, done) {
    // See if this user already exists
    let user = users.getUserByExternalId('google', profile.id);
    if (!user) {
      // They don't, so register them
      user = users.createUser(profile.displayName, 'google', profile.id);
    }
    return done(null, user);
  }));
}

When the user is redirected back to us after a successful authentication, we are provided their ID inside of Google’s system and some profile information. The first thing we try to see if this user has logged in before.
If so then we grab their user record and we’re done. If not then we will register a new account for them, and this new account is the one we will then use. This gives us a transparent mechanism where user registration is done on first login. We can do this differently if you so choose, but for now there’s no need.

The next part is to set up the route handlers to manage this login. These will look like this:

// src/index.js
function generateUserToken(req, res) {
  const accessToken = token.generateAccessToken(req.user.id);
  res.render('authenticated.html', {
    token: accessToken
  });
}

app.get('/api/authentication/google/start',
  passport.authenticate('google', { session: false, scope: ['openid', 'profile', 'email'] }));
app.get('/api/authentication/google/redirect',
  passport.authenticate('google', { session: false }),
  generateUserToken);

Note the routes for /api/authentication/google/start and /api/authentication/gogle/redirect. As noted above, the /start variation is the URL that we open, and the /redirect variant is the one that Google redirects the user back to on success. This then renders our authenticated view as shown above, providing the generated JWT for it to use.

Implementing Facebook Authentication

Now that we’ve got our first social login provider, let’s expand and add a second. This time it’s going to be Facebook, using the passport-facebook module.

This module works virtually the same as the Google module, requiring the same configuration and the same setup. The only real differences are in the fact that it’s a different module and a different URL structure to access it.

In order to configure Facebook Authentication you will also need a Client ID, Client Secret and Redirect URL.
The Client ID and Client Secret (referred to as an App ID and App Secret by Facebook) can be obtained by creating a Facebook Application in the Facebook Developer Console.
You will need to ensure that you add the “Facebook Login” product to your application in order for this to work.

Our Passport configuration for Facebook Authentication will be:

// src/authentication/facebook.js
const passport = require('passport');
const passportFacebook = require('passport-facebook');
const config = require('../config');
const users = require('../users');

const passportConfig = {
  clientID: config.get('authentication.facebook.clientId'),
  clientSecret: config.get('authentication.facebook.clientSecret'),
  callbackURL: 'http://localhost:3000/api/authentication/facebook/redirect'
};

if (passportConfig.clientID) {
  passport.use(new passportFacebook.Strategy(passportConfig, function (accessToken, refreshToken, profile, done) {
    let user = users.getUserByExternalId('facebook', profile.id);
    if (!user) {
      user = users.createUser(profile.displayName, 'facebook', profile.id);
    }
    return done(null, user);
  }));
}

This is almost identical to that for Google, only with the term “facebook” instead. And the URL Routes are similar:

// src/index.js
app.get('/api/authentication/facebook/start',
  passport.authenticate('facebook', { session: false }));
app.get('/api/authentication/facebook/redirect',
  passport.authenticate('facebook', { session: false }),
  generateUserToken);

Here we don’t need to specify the scopes that we want to use, because the default set are already good enough. Otherwise, the configuration between Google and Facebook is almost identical.

Summary

The use of social login providers makes it very quick and easy to add user login and registration to your application. The fact that this uses browser redirects to send the user to the social login provider and then back to your application can make this tricky to integrate into a single page application, even though it’s relatively easy to integrate into a more traditional application.

This article has shown a way to integrate these social login providers into your single page application in a way that is hopefully both easy to use, and is easy to extend for future providers that you may wish to work with.
Passport has a large number of modules to work with different providers, and it is a case of finding the right one and configuring it in the same way that we did above for Google and Facebook.

How To Create Authentication in Angular with Nodejs and Passport.js

How To Create Authentication in Angular with Nodejs and Passport.js

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

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

The tutorial assumes the reader to be familiar with creating a basic application using Angular and Node.js Express framework. You'll implement the Authentication using Passport on top of an Angular Sales Dashboard application covered in a previous tutorial.

The source code from this tutorial is available on GitHub.

Why Authentication?

Why do you need authentication? Well, adding some kind of authentication makes your application secure and prevents unauthorized access.

Authentication can be done with a username and password or it can be 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 username and password, 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 support authentication using a username and password, Facebook, Twitter and more.

Getting Started

Let' 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

To set up the authentication API, you need to create a Node project.

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 basic Express server with an endpoint. You now need to add a custom middleware to the /authenticate route.

What is a Middleware?

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

Let's add a 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 auth middleware, you'll authenticate the user using Passport.

To use 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 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 a number of strategies when it comes to authentication. You'll be using the local strategy in this tutorial and so we need to define it as below.

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 authenticate 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 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 method to facilitate user data storage in the session and retrieving 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 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 which 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 the 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 component. The LoginComponent will handle the login functionality and 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 from 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 is 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 login, AuthService saves the user information. It exposes a method called isAuthenticated which can be utilized by the AuthGuardService service to authenticate the route.

Let's create 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.

Let's 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 a number of other Passport strategies for authentication.

**Finally, don't forget to pay special attention if you're developing commercial Angular apps that contain sensitive logic.

Thank you for reading !

Javascript Testing Selenium Automation Nightwatch js Nodejs

Javascript Testing Selenium Automation Nightwatch js Nodejs

Simpliv offers solid learning on the basics of Selenium Automation Scripts and how they help automate the browser. By the end of this highly practical course, you will be able to build a Testing Framework from scratch. All at just $9! Enroll today!

Description
We will go over of basics such as what is selenium and how it help automate the browser.

To complete Setup and Installation of Nightwatch js Testing framework and we will create Test plan and test case, we will manually test a real website and then take those test case and we will automate it.

As we build our framework we will see how page object model/pattern help us re-use our code and how scale our test cases with ease

Who is the target audience?

Manual QA, SDET,Developer, Devops and anyone Interested in Learning Automation Testing
Basic knowledge
Beginner Level understanding on Software Testing
What will you learn
Basics of Selenium Automation Scripts, by the end build a Testing Framework from scratch

JavaScript Testing using Selenium WebDriver, Mocha and NodeJS

JavaScript Testing using Selenium WebDriver, Mocha and NodeJS

In case you are looking to write a functional test in JavaScript, the following tutorial provides UI automation engineers with the perfect structural reference material for JavaScript testing with Selenium WebDriver 3, Mocha and NodeJS.

In case you are looking to write a functional test in JavaScript, the following tutorial provides UI automation engineers with the perfect structural reference material for JavaScript testing with Selenium WebDriver 3, Mocha and NodeJS.

These days, JavaScript is a ubiquitous web language which seems to overcome its ‘notorious’ past and has become a more solid platform not only for client-side, but for server domains too. Mocha.js, or simply Mocha, is a feature-rich JavaScript test framework running on Node.js, which provides the platform and the API for building standalone applications server-side using Google’s V8 JavaScript engine at its base.

*Note: to get started with this JavaScript tutorial, you’ll need to be familiar with the basics of NodeJS and the JavaScript programming language.

Tutorial Overview:

1. Mocha Test Construction
  • Introduction
  • Installation
  • Installing Chai Assertion Module
  • Test suite and Test Case Structure
  • Constructing Tests with Mocha
  • Running Mocha’s Test Suite and Test Cases
  • Managing Syncing of Async Testing Code
2. Using Javascript Selenium 3 API Integrated with MochaJS
  • Selenium Introduction
  • Selenium Installation
  • WebDriver Construction
  • Integrating MochaJS with Selenium WebDriver 3

Versions used:

  • Node version used: 6.10.1 (LTS)
  • Mocha: 2.5.3
  • WebDriverJS: 3.3.0
1. Constructing Tests with Mocha

Introduction to Mocha

As mentioned, Mocha is a JavaScript test framework that runs tests on Node. Mocha comes in the form of a Node package via npm, allowing you to use any library for assertions as a replacement to Node’s standard ‘assert’ function, such as ChaiJS.

Mocha provides an API, which specifies a way to structure the testing code into test suites and test case modules for execution, and later on to produce a test report. Mocha provides two modes for running: either by command line (CLI) or programmatically (Mocha API).

Install Mocha

If Mocha is to be used in CLI, then it should be installed globally as Node.js.

npm install -g mocha 

Install Chai Assertion Module

npm install --save chai 

The –save option is used to install the module in the project’s scope and not globally.

Test Suite and Test Case Structure

In Mocha, a test suite is defined by the ‘describe’ keyword which accepts a callback function. A test suite can contain child / inner test suites, which can contain their own child test suites, etc. A test case is denoted by the ‘it’ function, which accepts a callback function and contains the testing code.

Mocha supports test suite setup and test case setup functions. A test suite setup is denoted by before while a test case setup applies beforeEach. beforeEach is actually a common setup for every case in the suite, and will be executed before each case.

As with the setup, Mocha supports test suite and test case teardown functions. A test suite teardown is denoted by after, while a test case teardown is implemented with afterEach, functions that are executed after a test suite and after each test case respectively.

Create a file that will ‘host’ the test suite, e.g. test_suite.js, and write the following to it;

describe("Inner Suite 1", function(){

    before(function(){

        // do something before test suite execution
        // no matter if there are failed cases

    });

    after(function(){

        // do something after test suite execution is finished
        // no matter if there are failed cases

    });

    beforeEach(function(){

        // do something before test case execution
        // no matter if there are failed cases

    });

    afterEach(function(){

        // do something after test case execution is finished
        // no matter if there are failed cases

    });

    it("Test-1", function(){

        // test Code
        // assertions

    });

    it("Test-2", function(){

        // test Code
        // assertions

    });

    it("Test-3", function(){

        // test Code
        // assertions

    });

});

Running Mocha Test Suite and Test Cases

Mocha supports execution of tests in three ways: Whole Test Suite file, tests filtered by “grep” patterns and tests grep filtering looking in a directory tree (recursive option)

Run whole Test Suite file:

mocha /path/to/test_suite.js 

Run a specific suite or test from a specific suite file.

If a suite is selected then all the child suites and/or tests will be executed.

mocha -g “Test-2” /path/to/test_suite.js 

Run a specific suite or test file by searching recursively in a directory tree.

mocha --recursive -g “Test-2” /directory/ 

For extensive CLI options:

mocha –-help 

Managing Syncing of Async Testing Code

In case async functions are used with Mocha and not handled properly, you may find yourself struggling. If asyncing code (e.g. http requests, files, selenium, etc.) is to be used in a test case, follow these guidelines to overcome unexpected results:

1. **done** Function

In your test function (it) you need to pass the done function down the callback chain — this ensures it is executed after your last step.

The example below emphasizes the done functionality. In this case three seconds of timeout will occur at the end of the test function.

it(‘Test-1’, function(done){

    setTimeout(function(){

        console.log(“timeout!”);

  // mocha will wait for done to be called before exiting function.
        done();     
    }, 3000);

});

2. Return Promise

Returning a promise is another way to ensure Mocha has executed all code lines when async functions are used (‘done’ function is not needed in this case.)

it(‘Test-1’, function(done){

    var promise;
    promise = new Promise(function(resolve, reject){
        setTimeout(function(){

            console.log("Timeout");
            resolve();

        }, 3000);

    });
    // mocha will wait for the promise to be resolved before exiting
    return promise;  
});

2. Javascript Selenium 3 Integration with MochaJS

Selenium Introduction

Selenium is a library that controls a web browser and emulates the user’s behavior. More specifically, Selenium offers specific language library APIs called ‘bindings’ for the user. These ‘bindings’ act as a client in order to perform requests to intermediate components and acting as servers in order to finally control a Browser.

The intermediate components could be the actual webdriver, found natively in each Selenium package, the selenium-standalone-server, as well as vendor native browser controlling drivers — such as Geckodriver for Mozilla, chromedriver for Chrome, etc. Moreover, Selenium webdriver communicates with browser drivers via ‘JsonWired Protocol’ and becomes a W3C Web Standard.

Selenium Installation

Before diving any deeper into Selenium integration with MochaJS, we will take a quick look into Selenium implementation with NodeJS.

In order to use the Selenium API for JavaScript (or Selenium JavaScript bindings), we should install the appropriate module:

npm install selenium-webdriver 

At this point, it should be clarified that Javascript Selenium WebDriver can also be referred to as Webdriverjs (although not in npm). Webdrivejs is different than other libs/modules, such as WebdriverIO, Protractor, etc. selenium-webdriver is the official open-source base JavaScript Selenium library while the others are wrapper libraries/frameworks that are built on top of webdriverjs API, claiming to enhance usability and maintenance.

In NodeJS code, the module is used by:

require(‘selenium-webdriver’) 

WebDriver Construction

In order to be able to use Selenium, we should build the appropriate ‘webdriver’ object which will then control our browser. Below, we can see how we use the “Builder” pattern to construct a webdriver object by chaining several functions.

Builder with Options

var webdriver = require('selenium-webdriver')
var chrome = require('selenium-webdriver/chrome'),
var firefox = require('selenium-webdriver/firefox');

var driver = new webdriver.Builder()
    .forBrowser(‘firefox’)
    .setFirefoxOptions( /* … */)
    .setChromeOptions( /* … */)
    .build();

In the code above, we have managed to build a WebDriver object which aggregates configuration for more than one browser (notice the ‘options’ methods), despite the fact that the forBrowser() method explicitly sets firefox.

The user can set the SELENIUM_BROWSER environmental variable on runtime to set the desired browser. It will override any option set by forBrowser, since we have already configured multiple browser capabilities by set Options.

The browser properties can have several types of information depending on the browser under test. For example, in Mozilla’s properties we can set the desired ‘profile’ configuration as follows:

var profile = new firefox.Profile( /* … path to firefox local profile … */);
var firefoxOptions = new firefox Options().setProfile(profile);

Then, in the above Builder snippet we can add:

‘setFirefoxOptions( firefoxOptions )’ 

Builder with Capabilities

Selenium WebDriver JavaScript API documents several ways that a webdriver could be built. One more possible way is by setting all the required driver configurations in capabilities:

var driver = new webdriver.Builder().
    .withCapabilities( { ‘browserName’ : ‘firefox’ } )
    .build();

Note that if setOptions are set after withCapabilities, the configurations will be overridden (e.g. proxy configurations).

Selenium WebDriver Control Flow and Promise Management

Since JavaScript and NodeJS are based on asynchronous principles, Selenium WebDriver behaves in a similar way. In order to avoid callback pyramids and to assist a test engineer with the scripting experience as well as code readability and maintainability, Selenium WebDriver objects incorporate a promise manager that uses a ‘ControlFlow’. ‘ControlFlow’ is a class responsible for the sequential execution of the asynchronous webdriver commands.

Practically, each command is executed on the driver object and a promise is returned. The next commands do not need to be nested in ‘thens’, unless there is a need to handle a promise resolved value as follows:

driver.get("http://www.google.com");
driver.getTitle().then(function( title ) {

    // google page title should be printed 
    console.log(title)

});

driver.quit();

Pointers for JavaScript Testing with Selenium WebDriver and Mocha

  1. driver is a webdriver object, not a promise object
  2. driver.getTitle() or driver.get(url), or any other Selenium command, returns a promise object!

This means that we can perform the following:

var titlePromise = driver.getTitle();
titlePromise.then(function(title){

    console.log(title);

});
  1. Additionally, since driver is asyncing in its base, the following will not work:
var title = driver.getTitle();
expect (title).equals("Google");

Note: title is a promise object and not an actual resolved value.

MochaJS + Selenium WebDriver

Generally speaking, Selenium WebDriver can be integrated with MochaJS since it is used in any plain NodeJS script. However, since Mocha doesn’t know when an asynchronous function has finished before a done() is called or a promise is returned, we have to be very careful with handling.

Promise Based

Selenium commands are registered automatically, to assure webdriver commands are executed in the correct sequential order a promise should be returned.

The code below shows Mocha’s (before, beforeEach, after, afterEach) or test case body it hooks.

describe( 'Test Suite' , function(){

    before(function(){

        driver.get( my_service );
        driver.findElement(webdriver.By.id(username)).sendKeys(my_username);

        // a promise is returned while ‘click’ action
        // is registered in ‘driver’ object
        return driver.findElement(webdriver.By.id(submit)).click();
    });

    after(function(){

        return driver.quit();

    });

    it( 'Test Case', function(){

        driver.getTitle().then(function(title){
            expect(title).equals(my_title);
        })

The following actions will be executed:

  1. Browser page of “my_service” is loaded
  2. Text Field with id ‘username’ is located
  3. Text Field with id ‘username’ is filled with ‘my_username’
  4. Page title is retrieved and checked for equality against ‘my_title’
  5. WebDriver quits and browser window is closed. Browser process is terminated.

Selenium Webdriver Support for MochaJS

In order to perform JavaScript testing with Selenium WebDriver and Mocha in a simple way, WebDriver facilitates usage with MochaJS by wrapping around MochaJS test functions (before, beforeEach, it, etc.) with a test object. This creates a scope that provides awareness that WebDriver is being used. Therefore, there is no need for promise returns.

First, the corresponding module should be loaded:

var test = require('selenium-webdriver/testing'); 

All the function of Mocha are preceded by ‘test.’ as follows:

test.before()
test.describe()

And so on. Then, the above code is fully re-written as:

test.describe( 'Test Suite' , function(){

    test.before(function(){

        driver.get( my_service );
        driver.findElement(webdriver.By.id(username)).sendKeys(my_username);
        driver.findElement(webdriver.By.id(submit)).click();
    });

    test.after(function(){
        driver.quit();
    });

    test.it( 'Test Case' , function(){

        driver.getTitle().then(function(title){
            expect(title).equals(my_title);
        })

        driver.sleep();
    });

});
Conclusion

In this tutorial we got a chance to experience JavaScript testing with Selenium WebDriver and MochaJS. We should keep in mind the main difference when comparing to other programming language bindings, due to the asynchronous nature of NodeJS, MochaJS and Selenium WebDriver.

As long as we keep returning promises in any function which creates a promise (either a custom test lib function or a MochaJS hook/testcase), Mocha will execute them in the correct order.

Other frameworks such as WebdriverIO, Protractor and CodeseptJS provide wrapper solutions that hide some configurations from the user, and provide some promise-enhanced handling for a better scripting experience that many test automation experts might find helpful.