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: