Facebook-passport with JWT

放肆的年华 提交于 2020-07-31 07:50:26

问题


I've been using Passport on my server for user authentication. When a user is signing in locally (using a username and password), the server sends them a JWT which is stored in localstorage, and is sent back to server for every api call that requires user authentication.

Now I want to support Facebook and Google login as well. Since I began with Passport I thought it would be best to continue with Passport strategies, using passport-facebook and passport-google-oauth.

I'll refer to Facebook, but both strategies behave the same. They both require redirection to a server route ('/auth/facebook' and '/auth/facebook/callback' for that matter). The process is successful to the point of saving users including their facebook\google ids and tokens on the DB.

When the user is created on the server, a JWT is created (without any reliance on the token received from facebook\google).

     ... // Passport facebook startegy
     var newUser = new User();
     newUser.facebook = {};
     newUser.facebook.id = profile.id; 
     newUser.facebook.token = token; // token received from facebook
     newUser.facebook.name  = profile.displayName;   
     newUser.save(function(err) {
          if (err)
               throw err;
          // if successful, return the new user
          newUser.jwtoken = newUser.generateJwt(); // JWT CREATION!
          return done(null, newUser);
     });

The problem is that after its creation, I don't find a proper way to send the JWT to the client, since I should also redirect to my app.

app.get('/auth/facebook/callback',
    passport.authenticate('facebook', {
        session: false,
        successRedirect : '/',
        failureRedirect : '/'
    }), (req, res) => {
        var token = req.user.jwtoken;
        res.json({token: token});
    });

The code above redirects me to my app main page, but I don't get the token. If I remove the successRedirect, I do get the token, but I'm not redirected to my app.

Any solution for that? Is my approach wrong? Any suggestions will do.


回答1:


The best solution I found for that problem would be to redirect to the expected page with a cookie which holds the JWT.

Using res.json would only send a json response and would not redirect. That's why the other suggested answer here would not solve the problem I encountered.

So my solution would be:

app.get('/auth/facebook/callback',
passport.authenticate('facebook', {
    session: false,
    successRedirect : '/',
    failureRedirect : '/'
}), (req, res) => {
    var token = req.user.jwtoken;
    res.cookie('auth', token); // Choose whatever name you'd like for that cookie, 
    res.redirect('http://localhost:3000'); // OR whatever page you want to redirect to with that cookie
});

After redirection, you can read the cookie safely and use that JWT as expected. (you can actually read the cookie on every page load, to check if a user is logged in)

As I mentioned before, it is possible to redirect with the JWT as a query param, but it's very unsafe. Using a cookie is safer, and there are still security solutions you can use to make it even safer, unlike a query param which is plainly unsecure.




回答2:


Adding to Bar's answer.

I prepared a landing component to extract the cookie, save it to local storage, delete the cookie, then redirect to an authorized page.

class SocialAuthRedirect extends Component {
  componentWillMount() {
    this.props.dispatch(
      fbAuthUser(getCookie("auth"), () => {
        document.cookie =
          "auth=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";
        this.props.history.push("/profile");
      })
    );
  }

  render() {
    return <div />;
  }
}



回答3:


A propre solution would be to implement the redirection on the client side.

Simply use:

app.get('/auth/facebook/callback',
  passport.authenticate('facebook', {
    session: false,
    failureRedirect: '/login'
  }), (req, res) => {
    res.json({
      token: req.user.jwtoken
    })
  }
)

If you're client side receives the token, then redirect from there to home page, and in the case the login wasn't successful, it would be redirected by the server directly.

Or you can go for the full client side management as I would:

app.get('/auth/facebook/callback',
  passport.authenticate('facebook', {
    session: false
  }), (req, res) => {
    if (req.user.jwtoken) {
      res.json({
        success: true,
        token: req.user.jwtoken
      })
    } else {
      res.json({
        success: false
      })
    }
  }
)

If success === true, store JWT in LocalStorage, else redirect to login page.



来源:https://stackoverflow.com/questions/42508640/facebook-passport-with-jwt

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!