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