strongloop / loopback-component-passport

LoopBack passport integration to support third party logins and account linking
Other
139 stars 228 forks source link

enable state in oauth2 #248

Closed regevbr closed 6 years ago

regevbr commented 6 years ago

OAuth2 supports passing a state so it can be passed back to the callback. This is very useful if you are using for example facebook signup on your web page and want to pass utm data for example so you can understand how the user came about your site.

The way to achieve this flow, there is a need to be able to configure a method that will read the authPath query params from the request and extract a single string that represents the state, and pass it to the authenticate method. For example:

    app.get(conf.authPath, (req, res, next) => {
      passport.authenticate(name, _.defaults({
        scope: conf.scope,
        session: !!conf.session,
        state: req.query.passedstate
      }, conf.authOptions))(req, res, next);
    });

Then we can use that data (which is sent back to the callback route) in the loginCallback by accessing req.query.state

A better option is to make a change that will cause the state to be passed to the profileToUser method so the user model can be created using that state

I already hacked solved it and it is working well but that is not the way this needs to be used. Example of my solution:

  function createAuthRoute(conf, name) {
    app.get(conf.authPath, (req, res, next) => {
      passport.authenticate(name, _.defaults({
        scope: conf.scope,
        session: !!conf.session,
        state: req.query.aidmail
      }, conf.authOptions))(req, res, next);
    });
  }

  function overideVerifyCallback(strategy, conf, name) {
    strategy._verify = (req, accessToken, refreshToken, profile, done) => {
      if (conf.link) {
        if (req.user) {
          passportConfigurator.userCredentialModel.link(
            req.user.id, conf.provider || name, conf.authScheme, profile,
            {
              accessToken: accessToken,
              refreshToken: refreshToken,
            }, conf, done);
        } else {
          done('No user is logged in');
        }
      } else {
        const confCopy = _.defaults({
          profileToUser: profileToUser(req)
        }, conf);
        passportConfigurator.userIdentityModel.login(conf.provider || name, conf.authScheme, profile,
          {accessToken: accessToken, refreshToken: refreshToken},
          confCopy, confCopy.loginCallback(req, done));
      }
    };
  }
  const conf = ...
   createAuthRoute(conf, name);
   const strategy = passportConfigurator.configureProvider(name, conf);
   overideVerifyCallback(strategy, conf, name);
stale[bot] commented 6 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale[bot] commented 6 years ago

This issue has been closed due to continued inactivity. Thank you for your understanding. If you believe this to be in error, please contact one of the code owners, listed in the CODEOWNERS file at the top-level of this repository.

mufsir commented 5 years ago

Hi @regevbr,

Can you please tell me how can I do this in Facebook/Google sign in?