Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implementing passport-http-bearer token with sails.js

I am trying to implement passport's passport-http-bearer strategy, but it found no user with info Bearer realm="Users".

My request is a post request:

{'token':'simple_access_token',} 

Any one has any idea why this error occurs? Also I know here req should be https or ssl instead of http. How do I do that?

The code I am using is:

bearerPassportToken: function(req,res){
        passport.authenticate('bearer', function(err, user, info){
          if ((err) || (!user)) {
            if (err) return;
            if (!user)  
                console.log("info");//Info: Bearer realm="Users"
            res.redirect('/login');
            return;
          }
          req.logIn(user, function(err){
            if (err){
                res.redirect('/login');
            }
            //Need to write code for redirection
            ;
          });
        })(req, res);
    },
like image 941
Muhammad Raihan Muhaimin Avatar asked Jan 30 '14 03:01

Muhammad Raihan Muhaimin


1 Answers

We had to implement securing the Sails-based API with bearer tokens recently, and here's what we did (tested with 0.9.x):

1) Connect passport as a custom middleware in config/passport.js (or it can be config/express.js, depending on your taste):

/**
 * Passport configuration
 */
var passport = require('passport');

module.exports.express = {
  customMiddleware: function(app)
  {
    app.use(passport.initialize());
    app.use(passport.session());
  }
};

2) Secure necessary controllers/actions with a policy in config/policies.js:

module.exports.policies = {
  // Default policy for all controllers and actions
  '*': 'authenticated'
};

3) Create the policy that checks the bearer in api/policies/authenticated.js:

/**
 * Allow any authenticated user.
 */
var passport = require('passport');

module.exports = function (req, res, done) {
  passport.authenticate('bearer', {session: false}, function(err, user, info) {
    if (err) return done(err);
    if (user) return done();

    return res.send(403, {message: "You are not permitted to perform this action."});
  })(req, res);
};

4) Define the bearer strategy for passport in services/passport.js (or wherever else you find it more appropriate for your specific application):

var passport = require('passport'),
  BearerStrategy = require('passport-http-bearer').Strategy;

/**
 * BearerStrategy
 *
 * This strategy is used to authenticate either users or clients based on an access token
 * (aka a bearer token).  If a user, they must have previously authorized a client
 * application, which is issued an access token to make requests on behalf of
 * the authorizing user.
 */
passport.use('bearer', new BearerStrategy(
  function(accessToken, done) {
    Tokens.findOne({token: accessToken}, function(err, token) {
      if (err) return done(err);
      if (!token) return done(null, false);
      if (token.userId != null) {
        Users.find(token.userId, function(err, user) {
          if (err) return done(err);
          if (!user) return done(null, false);
          // to keep this example simple, restricted scopes are not implemented,
          // and this is just for illustrative purposes
          var info = { scope: '*' }
          done(null, user, info);
        });
      }
      else {
        //The request came from a client only since userId is null
        //therefore the client is passed back instead of a user
        Clients.find({clientId: token.clientId}, function(err, client) {
          if (err) return done(err);
          if (!client) return done(null, false);
          // to keep this example simple, restricted scopes are not implemented,
          // and this is just for illustrative purposes
          var info = { scope: '*' }
          done(null, client, info);
        });
      }
    });
  }
));

This way you'll be able to access the API by having your bearer in the Authorization header: Bearer 8j4s36....

In this example a separate server was used to request/issue tokens, but you might as well do it within the same app (then you'll have to apply the policy to selected controllers only).

like image 162
bredikhin Avatar answered Nov 19 '22 05:11

bredikhin