Building OAuth Facebook Strategies with Vue.js , passport.js and node.js

0

OAuth is an authentication protocol that lets users log in via different external services. 
For example, logging in to an application via Facebook or Twitter does not require a user to provide their username and password if the user is already logged in to Facebook or Twitter
It saves the user from setting up a new account in an application, which makes the login process smooth. This makes logging in to an app easier; otherwise, a user first needs to register to our application and then log in using those credentials.
Passport's OAuth strategies allow users to log in to our application with a single click if the browser remembers the account. Everything else is done automatically and is handled by the strategy itself.

passport.js provides a simpler way to integrate all these strategies in a very flexible way and also makes it easier to implement.

Passport's Facebook Strategy

Passport's Facebook Strategy is easy to integrate. As always, let's start with the installation of this strategy.

Installing the Passport's Facebook Strategy

We can install the passport's Facebook Strategy by running the following command:

$ npm install passport-facebook --save

The following code should add the package to your package.json file:

...
"node-sass": "^4.7.2",
"nodemon": "^1.14.10",
"passport": "^0.4.0",
"passport-facebook": "^2.1.1",
...


Configuring Passport's Facebook Strategy

There are a few steps to configure the Passport's Facebook Strategy. We will discuss each step in detail:

1. Create and set up a Facebook app. This will provide us with an App ID and an App Secret.
2. Add a button to our login page that allows our users to log in via Facebook.
3. Add the necessary routes for Facebook authentication.
4. Add a middleware method to check whether authentication is successful.

Let's dive into the details for each of the preceding steps.

Creating and setting up a Facebook app

To be able to use the Facebook Strategy, you have to build a Facebook application first.
The developers, portal for Facebook is at https://developers.facebook.com/.

After logging in, click on the Get Started button and then click on Next.

Then, you will see a drop-down menu in the top-right corner of the screen called My Apps, where you can find the option to create a new application.

Choose a display name that you want to name your application. In this case, we will name it movie_rating_app:



Click on Create App ID. If you go to the settings page, you will see the App ID and App Secret for your application:




Adding a button to our login page that allows users to log in via Facebook

The next step is to add a LOGIN WITH FACEBOOK button on your login page, which you will be linking to your Facebook application. Replace the contents of Login.vue, with the following:

<template>
<div class="login">
<a class="btn facebook" href="/login/facebook"> LOGIN WITH FACEBOOK</a>
</div>
<v-form v-model="valid" ref="form" lazy-validation>
<v-text-field
label="Email"
v-model="email"
:rules="emailRules"
required>
</v-text-field>
<v-text-field l
label="Password"
v-model="password"
:rules="passwordRules"
required>
</v-text-field>
<v-btn
@click="submit"
:disabled="!valid" >
submit
</v-btn>
<v-btn @click="clear">clear</v-btn>
</v-form>
</div>
</template>


Let's also add some styling to these buttons. 
In src/assets/stylesheets/home.css, add the following code:
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
width: 100%;
}

#inspire {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
}

.container.fill-height {
align-items: normal;
}

a.side_bar_link {
text-decoration: none;
}

.card__title--primary,
.card__text {
text-align: left;
}

.card {
height: 100% !important;
}

.btn.facebook {
background-color: #3b5998 !important;
border-color: #2196f3;
color: #fff !important;
}

.btn.twitter {
background-color: #2196f3 !important;
border-color: #2196f3;
color: #fff !important;
}

.btn.google {
background-color: #dd4b39 !important;
border-color: #dd4b39;
color: #fff !important;
}

.btn.linkedin {
background-color: #4875B4 !important;
border-color: #4875B4;
color: #fff !important;
}


The preceding code will add a LOGIN WITH FACEBOOK button:



Adding configurations for Facebook app

Let's configure the Facebook Strategy just as we did for the local strategy. We will create a separate file to handle Facebook login so that the code is simpler. Let's create a file called facebook.js inside the controllers folder and add the following contents to it:

const User=require('../models/User.js');
const passport=require('passport');
const config=require('./../config/Config');
const Strategy=require('passport-facebook').Strategy;

module.exports.controller=(app)=> {
    // facebook strategy 
    passport.use(new Strategy({
        clientID: config.FACEBOOK_APP_ID, c
        lientSecret: config.FACEBOOK_APP_SECRET, 
        callbackURL: '/login/facebook/return', 
        profileFields: ['id', 'displayName', 'email']
    },(accessToken, refreshToken, profile, cb)=> {
        // Handle facebook login 
    })); 
};


In the preceding code, the first line inside the export method imports the Facebook Strategy. 
The configuration takes three parameters: clientID, clientSecret, and callback URL
clientID and clientSecret are the App ID and App Secret for your Facebook app, respectively.

Let's add those secrets to our config file. 
In config/Config.js, let's add our Facebook keys, the facebook_client_id and facebook_client_secret:

module.exports = { 
    DB: 'mongodb://localhost/movie_rating_app', 
    SECRET: 'movieratingappsecretkey', 
    FACEBOOK_APP_ID: 'facebook_client_id', 
    FACEBOOK_APP_SECRET: 'facebook_client_secret' 
}

The callback URL is the URL that you want to route your application to after a successful transaction with Facebook.

The callback we have defined here is http://127.0.0.1:8081/login/facebook/return, which we have to define. 
The configuration is followed by a function that takes the following four parameters:
  • accessToken 
  • refreshToken 
  • profile 
  • cb (callback)
Upon a successful request, our application will get redirected to the home page.

Adding necessary routes for Facebook login

Now, let's go ahead and add the necessary routes for when we click on the login button and when we receive the callback from Facebook. In the same file, facebook.js, add the following routes:

const User = require("../models/User"); 
const passport = require('passport'); 
const config = require('./../config/Config');

module.exports.controller = (app) => {
    // facebook strategy 
    const Strategy = require('passport-facebook').Strategy;

    passport.use(
        new Strategy({ 
            clientID: config.FACEBOOK_APP_ID,
            clientSecret: config.FACEBOOK_APP_SECRET,
            callbackURL: '/api/login/facebook/return',
            profileFields: ['id', 'displayName', 'email'] 
        }, 
        function(accessToken, refreshToken, profile, cb) { 
            // your code
        })
    );

    app.get('/login/facebook',
        passport.authenticate('facebook', { 
            scope: ['email'] 
        })
    );

    app.get('/login/facebook/return',
        passport.authenticate('facebook', { 
            failureRedirect: '/login' 
        }
    ),

    (req, res) => {
        res.redirect('/'); 
    });
}

In the preceding code, we have added two routes. 
If you remember, in Login.vue, we have added a link to http://127.0.0.1:8081/login/facebook, which will be served by the first route that we defined here.

Also, if you recall, in the configuration setting, we have added a callback a function that will be served by the second route, which we have defined here as well.

Now, the final thing to do is to actually log in the user using the strategy. 
Replace the contents of facebook.js with the following:

const User = require('../models/User.js'); 
const passport = require('passport'); 
const config = require('./../config/Config');
const Strategy = require('passport-facebook').Strategy;

module.exports.controller = (app) => {
    // facebook strategy 
    passport.use(new Strategy(
        {
            clientID: config.FACEBOOK_APP_ID,
            clientSecret: config.FACEBOOK_APP_SECRET,
            callbackURL: '/login/facebook/return',
            profileFields: ['id', 'displayName', 'email'], 
        }, (accessToken, refreshToken, profile, cb) => {

            const email = profile.emails[0].value; 
            User.getUserByEmail(email, (err, user) => { 
                if (!user) { 
                    const newUser = new User({ 
                        fullname: profile.displayName, 
                        email, 
                        facebookId: profile.id, 
                    }); 
                    User.createUser(newUser, (error) => { 
                        if (error) { 
                            // Handle error 
                        } 
                        return cb(null, user); 
                    }); 
                } else { 
                    return cb(null, user); 
                } return true; 
            }); 
        })
    );

    app.get('/login/facebook', 
        passport.authenticate('facebook', { 
            scope: ['email'] 
        }));

    app.get('/login/facebook/return', 
    passport.authenticate('facebook', { 
        failureRedirect: '/login' 
    }),

    (req, res) => {
        res.redirect('/'); 
    });
};

While logging in with the Facebook login, if the user already exists in our database, the user simply gets logged in and saved in the session. The session data is not stored in the browser cookies but on the server-side itself.
If the user doesn't exist in our database, then we create a new user with the provided email from Facebook.

The last thing to configure here is to add the return URLs or the redirect URL from Facebook to our application.
For this, we can add the URLs in the App Settings page on Facebook.
In the app Settings page, under the Valid OAuth Redirect URIs, add the redirect URLs to our application from Facebook.

Now, we should be able to log in via Facebook. When the login function is successful, it will redirect the user to the home page. 
If you notice, Facebook redirects us to http://localhost:8081/#= instead of just http://localhost:8081
This is because of a security vulnerability. 
We can remove the # from the URL by adding the following piece of code in the main file, which is index.html:

<!DOCTYPE html> 
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700|Material+Icons" rel="stylesheet">
<link href="https://unpkg.com/vuetify/dist/vuetify.min.css" rel="stylesheet">
<title>movie_rating_app</title>
</head>
<body>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>

<script type="text/javascript">
if (window.location.hash == '#_=_'){
history.replaceState ?
history.replaceState(
null,
null,
window.location.href.split('#')[0]
) : window.location.hash = '';
}
</script>
</html>

This will remove the # symbol from the preceding URL.
When you are successfully logged in, we should see your email in the top bar view similar to this:




Tags

Post a Comment

0Comments
Post a Comment (0)