angular-fullstack / generator-angular-fullstack

Yeoman generator for an Angular app with an Express server
https://awk34.gitbook.io/generator-angular-fullstack
6.13k stars 1.24k forks source link

Can't get access token in req from passport.js #1028

Closed dvirhazout closed 9 years ago

dvirhazout commented 9 years ago

I'm trying to achieve a multi-social-profiles account. currently just facebook and local. I can't get the req.user \ object in passport.js

here're some peaces of code i'm using: passport.js:

  passport.use(new FacebookStrategy({
      clientID: config.facebook.clientID,
      clientSecret: config.facebook.clientSecret,
      callbackURL: config.facebook.callbackURL,
      passReqToCallback: true
    },
    function(req, accessToken, refreshToken, profile, done) {

auth.service:

function appendUser() {
  return compose()
    .use(function(req, res, next) {

      if(req.query && req.query.hasOwnProperty('access_token')) {
        req.headers.authorization = 'Bearer ' + req.query.access_token;
      }
      validateJwt(req, res, next);
    })
    .use(function(req, res, next) {
      User.findById(req.user._id, function (err, user) {
        if (err) return next(err);
        if (!user) return next(err);

        req.user = user;
        next();
      });
    });
}

auth/index.js

router
  .get('/', auth.appendUser(), passport.authorize('facebook', { scope : 'email' }))

  .get('/callback', auth.appendUser(), passport.authorize('facebook', {
        successRedirect : '/settings',
        failureRedirect : '/'
    }));

I'm a little lost with this one. struggeling with it for couple days. What am I missing?

Awk34 commented 9 years ago

I've got it working for my app, take a gander here: https://github.com/Awk34/aksite/tree/master/server/auth/facebook

dvirhazout commented 9 years ago

@Awk34 - does it cover the state when i'm registered with local strategy and want to connect that same account to facebook profile?

Awk34 commented 9 years ago

Yeah the way I have mine set up is if you're logged in with one account, it will add the new account's stuff to your existing one.

simondelorean commented 9 years ago

@Awk34 This is great, thank you very much for this solution! I'm new to Passport and Express and spent a whole day trying to figure out why the user is not in the request object. To be honest, I still don't know why the appendUser function is needed.

Awk34 commented 9 years ago

Express has nothing to do with users and authentication, just the HTTP server part. The appendUser function is a middleware, meaning that the flow goes:

Express gets the request with all its data (containing the request body, headers, and cookie)

 | V

auth.addAuthHeaderFromCookie() will take a token from the cookie if it exists, and set the Authorization header from it. If there's no token on the cookie, this middleware does nothing.

 | V

It goes through the middleware, which takes the Authorization header from the request, passes it to the JSON Web Token validator. If the validation passes, validateJwt's callback will be called without an error and req.user will contain the JWT data (which in our case is the user's ID). We then get the rest of the user data from MongoDB and attach it to req and pas the request on. If any part of this step failed, req.user will be undefined

 | V

Now the request is passed on to Passport, as defined in index.js. From inside the Passport handler we define in passport.js, if the User is already logged in, req.user will be defined, which probably means that the user is attempting to add additional login avenues. If req.user is undefined, it means the user is either trying to log in to his/her existing account that is linked to the OAuth avenue, or he/she is a new user.

simondelorean commented 9 years ago

Thanks a lot for the detailed explanation! What I still don't get: When I'm logged in using Passport local, I can see req.user in every request. But when I try to add my Google+ account, req.user is not available within the Passport strategy. Since Passport just piggybacks on express-session how come it's not available?

Awk34 commented 9 years ago

@simonbogarde Can I see your code?

kingcody commented 9 years ago

@simonbogarde simple answer is because only routes that have been authenticated using auth.isAuthenticated() or similar will have the user object attached. Your Google auth route is open.

kingcody commented 9 years ago

@Awk34 instead of using cookies, in my implementation I send the client to the oauth provider with a JWT embedded in the callback url. Once they return I verify it and match them to a user account if needed.

kingcody commented 9 years ago

@dvirhazout I believe @Awk34's code/examples should be enough to resolve this issue, but if you still have problems then feel free to reopen.