Authentication using Google's oAuth api with node.js

author-avatar
Paul Shan Thu Mar 10 2016

OAuth authentications are pretty popular now a days and another thing which is popular is JavaScript. This article shows how to plugin google’s oAuth api for authentication in your own node application. The github repo is also available.

A background of oAuth

OAuth is an authentication technique which provides you a secure and delegate access to some server resources on behalf of the resource owner. This is a very commonly used technique in third party websites to authenticate a user via his/her facebook, twitter or google account, without disclosing the password and also without taking the headache of storing user credentials in their websites.

Get the client-id and client-secret

To use oAuth (or any other api) of google you need to create an app in google developers console. Follow the steps below, described in the images and you will be able to generate the client-id and client-secret.

google-app-id-secret-gen1
google-app-id-secret-gen2
google-app-id-secret-gen3
google-app-id-secret-gen4
google-app-id-secret-gen5
google-app-id-secret-gen6
google-app-id-secret-gen7

Code in node for OAuth

I am describing things here with a small node/express application which has few routes and returns normal html with some links. However you can implement the same thing may be in a popup window or wherever you needed.

Install express and googleapis modules

npm install express
npm install googleapis

Let us also install express’s session plugin which I will describe later on, why it was necessary.

npm install express-session

I will be using only one file, that is server.js. All the codes below will go into that only.

Setup the basic app

var http = require('http');
var express = require('express');
var Session = require('express-session');
var google = require('googleapis');
var OAuth2 = google.auth.OAuth2;
var plus = google.plus('v1');
const ClientId = "YourGoogleAppClientId";
const ClientSecret = "YourGoogleAppClientSecret";
const RedirectionUrl = "http://localhost:1234/oauthCallback";

//starting the express app
var app = express();

//using session in express
app.use(Session({
    secret: 'your-random-secret-19890913007',
    resave: true,
    saveUninitialized: true
}));

//this is the base route
app.use("/", function (req, res) {
    res.send(`
        <h1>Authentication using google oAuth</h1>
    `)
});

var port = 1234;
var server = http.createServer(app);
server.listen(port);
server.on('listening', function () {
    console.log(`listening to ${port}`);
});

create oAuth url

function getOAuthClient () {
    return new OAuth2(ClientId ,  ClientSecret, RedirectionUrl);
}

function getAuthUrl () {
    var oauth2Client = getOAuthClient();
    // generate a url that asks permissions for Google+ and Google Calendar scopes
    var scopes = [
      'https://www.googleapis.com/auth/plus.me'
    ];

    var url = oauth2Client.generateAuthUrl({
        access_type: 'offline',
        scope: scopes // If you only need one scope you can pass it as string
    });

    return url;
}

The function getOAuthClient() creates an oAuth client and the getAuthUrl() function creates the url to be hit for authentication.

Let’s link that url to our base route.

app.use("/", function (req, res) {
    var url = getAuthUrl();
    res.send(`
        <h1>Authentication using google oAuth</h1>
        <a href=${url}>Login</a>
    `)
});

If you run the node server.js now, it will look like the following image.

google-auth-output1

Things you need to know about scopes

Scopes are like permissions. What kind of permissions do you want from the user? Is it just the identity and basic details of him (for which I am using the plus.me scope), or calendar (‘https://www.googleapis.com/auth/calendar‘) or drive or something else. Just remember to enable that scope from developers console. How to enable is shown in the images below.
google-app-permission1 google-app-permission2

The callback route

If you remember, while creating the client id and secret in google’s developer console, we provided the callback link. So now it’s time to actually develop that route.

app.use("/oauthCallback", function (req, res) {
    var oauth2Client = getOAuthClient();
    var session = req.session;
    var code = req.query.code; // the query param code
    oauth2Client.getToken(code, function(err, tokens) {
      // Now tokens contains an access_token and an optional refresh_token. Save them.

      if(!err) {
        oauth2Client.setCredentials(tokens);
        //saving the token to current session
        session["tokens"]=tokens;
        res.send(`
            <h3>Login successful!!</h3>
            <a href="/details">Go to details page</a>
        `);
      }
      else{
        res.send(`
            <h3>Login failed!!</h3>
        `);
      }
    });
});

So, we are creating a route oauthCallback which is used as a callback in out google app where we are receiving the code which is being provided by google as a query parameter; and using that we are fetching the access token and saving that token to the current user session.

A successful login will redirect you to the following page.

google-auth-output2

Fetch user data

So if the login is successful, let us fetch some details of that user using google apis. Below is the code for the /details route.

app.use("/details", function (req, res) {
    var oauth2Client = getOAuthClient();
    oauth2Client.setCredentials(req.session["tokens"]);

    var p = new Promise(function (resolve, reject) {
        plus.people.get({ userId: 'me', auth: oauth2Client }, function(err, response) {
            resolve(response || err);
        });
    }).then(function (data) {
        res.send(`
            <img src=${data.image.url} />
            <h3>Hello ${data.displayName}</h3>
        `);
    })
});

We’re just getting the saved token back from session and using that we’re fetching the user details. If things run good, you will see a details page like following.

google-auth-output3

Entire server.js

var http = require('http');
var express = require('express');
var Session = require('express-session');
var google = require('googleapis');
var plus = google.plus('v1');
var OAuth2 = google.auth.OAuth2;
const ClientId = "YourGoogleAppClientId";
const ClientSecret = "YourGoogleAppClientSecret";
const RedirectionUrl = "http://localhost:1234/oauthCallback";

var app = express();
app.use(Session({
    secret: 'raysources-secret-19890913007',
    resave: true,
    saveUninitialized: true
}));

function getOAuthClient () {
    return new OAuth2(ClientId ,  ClientSecret, RedirectionUrl);
}

function getAuthUrl () {
    var oauth2Client = getOAuthClient();
    // generate a url that asks permissions for Google+ and Google Calendar scopes
    var scopes = [
      'https://www.googleapis.com/auth/plus.me'
    ];

    var url = oauth2Client.generateAuthUrl({
        access_type: 'offline',
        scope: scopes // If you only need one scope you can pass it as string
    });

    return url;
}

app.use("/oauthCallback", function (req, res) {
    var oauth2Client = getOAuthClient();
    var session = req.session;
    var code = req.query.code;
    oauth2Client.getToken(code, function(err, tokens) {
      // Now tokens contains an access_token and an optional refresh_token. Save them.
      if(!err) {
        oauth2Client.setCredentials(tokens);
        session["tokens"]=tokens;
        res.send(`
            <h3>Login successful!!</h3>
            <a href="/details">Go to details page</a>
        `);
      }
      else{
        res.send(`
            <h3>Login failed!!</h3>
        `);
      }
    });
});

app.use("/details", function (req, res) {
    var oauth2Client = getOAuthClient();
    oauth2Client.setCredentials(req.session["tokens"]);

    var p = new Promise(function (resolve, reject) {
        plus.people.get({ userId: 'me', auth: oauth2Client }, function(err, response) {
            resolve(response || err);
        });
    }).then(function (data) {
        res.send(`
            <img src=${data.image.url} />
            <h3>Hello ${data.displayName}</h3>
        `);
    })
});

app.use("/", function (req, res) {
    var url = getAuthUrl();
    res.send(`
        <h1>Authentication using google oAuth</h1>
        <a href=${url}>Login</a>
    `)
});


var port = 1234;
var server = http.createServer(app);
server.listen(port);
server.on('listening', function () {
    console.log(`listening to ${port}`);
});

Conclusion

So, why we saved the token in session? The reason is, if we didn't save the token in session and just set it to the oauth2Client, it would have been gone by next request as every router hit creates the oauth2Client again. If you set oauth2Client globally, than if a person A logs in, it will automatically reflect to person B's computer.

Google apis are not just for authentication, they are for many more. You can check them in their github repo. Just like a very similar approach to google’s OAuth, you can also integrate facebook, twitter oAuth apis too with their respective node modules.

GoogleNode.jsoAuth

Written By

Paul Shan

Collections

  • E

    ES6

  • R

    React JS

  • C

    CSS

    Cascading style sheets only

  • S

    SEO

    Search engine optimization

  • E

    ES7

  • C

    CMS

    wordpress, drupal, jumla, magento and more


Show All

Tags

vue-js
advanced js
youtube
Web development
vue css
social share buttons
real-life-example
react datetime picker
progra
Online
MathJax
jsfiddle
jquery chart library
instant search using vue
handlebars
event loop
Design
console.log
best practices
imorph

Show All