15

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);
    },
Muhammad Raihan Muhaimin
  • 5,559
  • 7
  • 47
  • 68

1 Answers1

23

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).

bredikhin
  • 8,875
  • 3
  • 40
  • 44
  • Thank you very much Any idea what last (req res) parameters are after passport.authenticate? – Muhammad Raihan Muhaimin Jan 31 '14 at 18:35
  • 1
    @VampireCoder Those are current request/response. It's like `passport.authenticate` is a function returning a function which is being called with `(req, res)`. – bredikhin Jan 31 '14 at 18:43
  • 1
    When I define ```passport.use('bearer', new BearerStrategy...``` the ```function(accessToken, done)``` is never triggered.. Any idea why? – Carlos Ricardo May 01 '14 at 00:13
  • @CarlosRicardo Check if the policy is in place, in `config/policies.js`, as well as in `api/policies/authenticated.js`. – bredikhin May 01 '14 at 14:12
  • @bredikhin, sorry, the Bearer Authoorization header was not correct, missed the "Beared" before token :D thanks anyway – Carlos Ricardo May 02 '14 at 15:27
  • @CarlosRicardo No prob. – bredikhin May 02 '14 at 15:28
  • passport.session() is unnecessary since you're not using sessions when using the Bearer (token) strategy. – Chetan Shenoy Jan 11 '15 at 16:36
  • @bredikhin I am following the above instructions but my requests are timing out as I never hit some of the callbacks. Putting logs throughout, I see that I am getting into policy evaluation in `authenticated.js`, but the `function(token, cb)` callback in `services/passport.js` is never triggered. I've double checked that I'm spelling "Bearer" correctly in the request and that my app is using the middleware that initializes passport. Any ideas what may be going wrong? I'm using Sails `0.11.2`, passport `0.3.0`, and passport-http-bearer `1.0.2`. – hunteros Sep 25 '15 at 21:27
  • @bredikhin the basic idea for me was to send Authorization header with Bearer prefix word! – 1nstinct Oct 22 '15 at 08:12