node.jsreactjspassport.jsmernpassport-google-oauth

node.js react Error [ERR_HTTP_HEADERS_SENT] when trying to send token using jwtToken with passport google oath2.0


I am currently trying to implement a google authentication using passport google oath2.0 on my node.js react web application with mongodb as database. I am struggling on passing token from google passport to jwtToken.

I tried a remedy by inserting the sendToken(use, 200, res) on the route parameter. I apologize for not so clear explanation but to make it easier to understand, here is my code.

backend/utils/sendToken.js

const sendToken = (user, statusCode, res) => {
    // Create Jwt token
    const token = user.getJwtToken();

    // Options for cookie
    const options = {
        expires: new Date(
            Date.now() + process.env.COOKIE_EXPIRES_TIME * 24 * 60 * 60 * 1000
        ),
httpOnly: true
    }
    res.status(statusCode).cookie('token', token, options).json({
        success: true,
        token,
        user
    })
}
module.exports = sendToken;

backend/passport.js

...
passport.use(new GoogleStrategy({
    clientID: process.env.CLIENT_ID,
    clientSecret: process.env.CLIENT_SECRET,
    callbackURL: "/api/v1/google/callback",
    scope: ["profile", "email"],
},
function (accessToken, refreshToken, profile, cb) {
    const googleEmail = profile._json.email;
    const googlePassword = profile._json.family_name;
    User.findOne({
        'google.google_id': profile.id 
    }, function(err, user) {
        if (err) {
            return cb(err);
        }
        if (!user) {
            user = new User({
                  google: {
                      google_id: profile.id,
                      google_mail: googleEmail,
                  } ,
                    name: profile.displayName ,
                    email: googleEmail ,
                     password: googlePassword ,
                     avatar: { url: profile._json.picture }
            });
            user.save(function(err) {
                if (err) console.log(err);
                console.log(profile, "Register Successful, 'Access Token: '", accessToken, 'Refresh Token: ',refreshToken);
                return cb(err, user);
            });
        } else {
            console.log(profile, "Login Successful, 'Access Token: '", accessToken, 'Refresh Token: ',refreshToken);
            return cb( err, user);
        }
    });
}
));
...

backend/routes/auth.js

const express = require('express');
const router = express.Router();
const passport = require("passport");
const sendToken = require('../utils/jwtToken');
...
router.get("/google", passport.authenticate("google", { scope: ["profile", "email"] }));
router.get(
    "/google/callback",
    passport.authenticate('google', { failureRedirect: '/' }),
  function( req, res) {
    // Successful authentication

    //send user object to sendToken via jwtToken
    sendToken(req.user, 200, res)

    //this is where I trying to redirect after sending token to jwtToken
    redirect(`http://localhost:3000/dashboard`);
  });
...

Solution

  • You cannot redirect after you have already send a response

    // you are sending a response inside sendToken function
    sendToken(req.user, 200, res); // (res.status(statusCode).cookie(...).json(...)
    
    // so you cannot redirect after response was sent
    res.redirect(`http://localhost:3000/dashboard`);
    

    If you want to redirect, you can do something like:

    res.cookie('token', token, options).redirect(...);