Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NodeJS REST authentication using Passport and OAuth2 + social network

Tags:

I'm working on REST api using NodeJS. For authentication I decided to use Passport. I want truly RESTful api. So it means I have to use tokens instead of sessions.

I want to let users login using username and password, or using social networks like Facebook, Google and Twitter.

I make my own OAuth2.0 server for issuing Access and Refresh tokens using oauth2orize module. So now I can register new user and then issue them tokens. I followed this tutorial:

http://aleksandrov.ws/2013/09/12/restful-api-with-nodejs-plus-mongodb/

Verifying user for route:

// api ------------------------------------------------------------------------------------     app.get('/api/userInfo',         passport.authenticate('bearer', { session: false }),         function(req, res) {             // req.authInfo is set using the `info` argument supplied by             // `BearerStrategy`.  It is typically used to indicate scope of the token,             // and used in access control checks.  For illustrative purposes, this             // example simply returns the scope in the response.             res.json({ user_id: req.user.userId, name: req.user.username, scope: req.authInfo.scope })         }     ); 

All this works quite well. Unfortunately I don't know how to implement social authentication.

I was reading this tutorial:

http://scotch.io/tutorials/javascript/easy-node-authentication-facebook  

But in this tutorial they are not making a truly RESTful api. I already implemented user schema according this tutorial where tokens for local user are stored in separated models.

// define the schema for our user model var userSchema = mongoose.Schema({     local: {         username: {             type: String,             unique: true,             required: true         },         hashedPassword: {             type: String,             required: true         },         created: {             type: Date,             default: Date.now         }     },     facebook: {         id: String,         token: String,         email: String,         name: String     },     twitter: {         id: String,         token: String,         displayName: String,         username: String     },     google: {         id: String,         token: String,         email: String,         name: String     } }); 

But now, how can I verify user?

passport.authenticate('bearer', { session: false }), 

this is verifying only bearer token against to my db, but how can I verify social tokens? Am I missing something?

like image 782
Stepan Sanda Avatar asked Oct 09 '14 18:10

Stepan Sanda


People also ask

Does Passport use OAuth2?

Introduction. Laravel Passport provides a full OAuth2 server implementation for your Laravel application in a matter of minutes. Passport is built on top of the League OAuth2 server that is maintained by Andy Millington and Simon Hamp.

Should I use Passport js for authentication?

Passport is a popular, modular authentication middleware for Node. js applications. With it, authentication can be easily integrated into any Node- and Express-based app. The Passport library provides more than 500 authentication mechanisms, including OAuth, JWT, and simple username and password based authentication.

What is passport authentication in Node JS?

Authentication entails matching users credential to file or database which could be in a local file system or an authentication server and if they exist, they are given access to protected resources. Passport is the most popular user authentication external library for Node.js applications.

What is the best external authentication library for nodejs?

Passport is the most popular user authentication external library for Node.js applications. It currently has 17.4k stars on GitHub and provides middleware for over 480 strategies such as simple username and password, social media login such as facebook, twitter, google and many more.

Which authentication scheme does passport support for social login?

Social login mostly relies on an authentication scheme such as OAuth 2.0. To learn more about the different login flows OAuth supports, read this article. We choose Passport to handle social login for us, as it provides different modules for a variety of OAuth providers, be it Facebook, Twitter, Google, GitHub, etc.

How to use passport as middleware in NodeJS projects?

This use as middleware in NodeJs projects. First, create the base folder (authentication-project) which contains all the project-related files and directories. Our project will have the server.js which has the server code, the .env file which has all environmental variables, passport-setup.js will have the code setting up different strategies.


1 Answers

I am using Facebook login for my own RESTful API for my Notepads app here. I started the application as one that will be used as a web page but still the communication after the login will be through the API.

Then I decided to create a mobile version of the same app that will use the API. I decided to make it that way: The mobile app logs in through Facebook and sends the facebook user id and FB access token to the API, the API calls Facebooks's API to verify these params and if successful registers a new user(or logs in an existing one) in my app's DB, creates a custom token for this user and returns it to the mobile app. From here the mobile app sends this custom token to authenticate the app with the API.

Here's some code:

The auth in the API (uses the fbgraph npm module):

var graph = require('fbgraph'), Promise = require('bluebird') ... Promise.promisify(graph.get); ... var postAuthHandler = function (req, res) {     var fbUserId = req.body.fbId,     fbAccessToken = req.body.fbAccessToken,     accessToken = req.body.accessToken;     ...     graph.setAppSecret(config.facebook.app.secret);     graph.setAccessToken(fbAccessToken);      var graphUser;     var p = graph.getAsync('me?fields=id,name,picture')         .then(function (fbGraphUser) {             //when the given fb id and token mismatch:             if (!fbGraphUser || fbGraphUser.id !== fbUserId) {                 console.error("Invalid user from fbAccessToken!");                 res.status(HttpStatus.FORBIDDEN).json({});                 return p.cancel();             }              graphUser = fbGraphUser;              return User.fb(fbUserId);         })         .then(function (user) {             if (user) {                 //user found by his FB access token                 res.status(HttpStatus.OK).json({accessToken: user.accessToken});                 //stop the promises chain here                 return p.cancel();             }             ...create the user, generate a custom token and return it as above... 

https://github.com/iliyan-trifonov/notepads-nodejs-angularjs-mongodb-bootstrap/blob/6617a5cb418ba8acd6351ef9a9f69228f1047154/src/routes/users.js#L46 .

The User model:

var userSchema = new mongoose.Schema({     facebookId: { type: String, required: true, unique: true },     accessToken: { type: String, required: true, unique: true },     name: { type: String, required: true },     photo: { type: String, required: true },     categories: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Category' }],     notepads: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Notepad' }] }); 

https://github.com/iliyan-trifonov/notepads-nodejs-angularjs-mongodb-bootstrap/blob/master/src/models/user.js#L9 .

The Facebook auth in the mobile app:

               auth: function(fbId, fbAccessToken) {                 return $http({                     url: apiBase + '/users/auth',                     data: {                         fbId: fbId,                         fbAccessToken: fbAccessToken                     },                     method: 'POST',                     cache: false                 });             },             ... 

https://github.com/iliyan-trifonov/notepads-ionic/blob/master/www/js/services.js#L33 .

The mobile app sends the token with the request:

  notepads: {             list: function() {                 return $http({                     url: apiBase + '/notepads?insidecats=1' + '&token=' + User.get().accessToken/*gets the token from the local storage*/,                     method: 'GET',                     cache: false                 });             }, 

It's an Ionic/Angular/Cordova app. The Facebook login from the mobile app starts the Facebook app installed on your phone or opens a popup to login in Facebook. Then a callback returns the Facebook user's id and access token to my mobile app.

The fbgraph npm module: https://github.com/criso/fbgraph

like image 93
Iliyan Trifonov Avatar answered Jan 08 '23 17:01

Iliyan Trifonov