jaredhanson / passport

Simple, unobtrusive authentication for Node.js.
https://www.passportjs.org?utm_source=github&utm_medium=referral&utm_campaign=passport&utm_content=about
MIT License
22.92k stars 1.24k forks source link

Req.user does not appear when reloading the page #728

Open farisdewantoro opened 5 years ago

farisdewantoro commented 5 years ago

I use Express-sessions and express-mysql-sessions.

Passport.js for authentication : LocalStrategy, GoogleStrategy,FacebookStrategy

I have problem with Google authenticate and Facebook authenticate, this 2 have same problem.

I cant get req.user after redirect to my website.

I am looking to find out what caused it and i got this :

  1. When user click login with google its generate new sessionID for example 222220
  2. After success login its will store in this sessionID 222220
  3. Redirect to my backend server /api/auth/google/redirect
  4. When i check i got req.user but if i redirect or reload the page it will gone and back to my previous SessionID. req.user is Undefined

So the data in req.user it saved to new SessionID and if i reload the page or redirect i got previous SessionID and req.user is undefined

Did I make mistake? I try this on the local server in production mode it works fine. but when I tried it on my web hosting server with production mode its not working

Routes

routes.get('/auth/google',passport.authenticate("google",{
    scope: ["profile", "email"]
}));

routes.get('/auth/google/redirect', passport.authenticate("google"),AuthController.googleRedirect);
routes.post('/auth/logout',AuthController.logout);

routes.get('/auth/facebook', passport.authenticate('facebook',{
    scope: ["email"]
}));
routes.get('/auth/facebook/redirect', passport.authenticate('facebook'), AuthController.facebookRedirect);

Callback Redirect

export const googleRedirect = (req,res)=>{
 //req.user is true
        if (req.user) { 

        if (req.session.carts) {
            console.log('I CAN SEE HERE');
            return res.redirect(keys.origin.redirect);
        }
            console.log('I CAN SEE HERE');
        return res.redirect(keys.origin.redictProfile);
    }
    else{
        return res.status(400).json('INVALID');
    }

}

Server.js

   import express from "express";
    import bodyParser from "body-parser";
    import compression from "compression";
    import morgan from "morgan";
    import Loadable from "react-loadable";
    import cookieParser from "cookie-parser";
    import passport from "passport";
    import session from "express-session";
    import cors from "cors";
    import passportSetup from "./config/passport-setup";
    import keys from "./config/keys";
    import uuidv4 from "uuid/v4";
    import UAparser from "ua-parser-js";
    import { ensureSession } from "./config/sessionCheck";
    import sess from "express-mysql-session";
    import csrf from 'csurf';

    // // Our loader - this basically acts as the entry point for each page load
    import loader from "./loader";

    // SESSION
    const MySQLStore = sess(session);
    const optionSession = {
      host: keys.database.host,
      user: keys.database.user,
      password: keys.database.password,
      database: keys.database.database,
      clearExpired: true,
      checkExpirationInterval: 900000,
      expiration: 86400000,
      schema: {
        tableName: "session",
        columnNames: {
          session_id: "id",
          expires: "expires",
          data: "data"
        }
      }
    };

    var sessionStore = new MySQLStore(optionSession);

    // Create our express app using the port optionally specified
    const app = express();
    const PORT = process.env.PORT || 5000;

    // Express Session
    app.use(
      session({
        genid: function(req) {
          return uuidv4(); // use UUIDs for session IDs
        },
        name: keys.session.name,
        secret: keys.session.secret,
        resave: false,
        saveUninitialized: true,
        store: sessionStore,
        rolling: true,
        cookie: {
          secure: false,
          httpOnly: true,
          maxAge: keys.session.maxAge, // satu hari,
        }
      })
    );

    // Passport
    app.use(passport.initialize());
    app.use(passport.session());

    app.disable("x-powered-by");

    app.use(cors({ origin: keys.origin.url, credentials: true }));

    // Compress, parse, log, and raid the cookie jar

    app.use(bodyParser.json());
    app.use(bodyParser.urlencoded({ extended: false }));
    app.use(morgan("dev"));
    app.use(cookieParser());

    if(process.env.NODE_ENV === 'production'){
      app.use(compression());
      app.use(csrf());
      app.use(function (err, req, res, next) {
        if (err.code !== 'EBADCSRFTOKEN') return next(err)

        // handle CSRF token errors here
        res.status(403)
        res.send('INVALID TOKEN')
      })
    }

    app.use((req, res, next) => {
      res.header("X-XSS-Protection", "1; mode=block");
      res.header("X-Frame-Options", "deny");
      res.header("X-Content-Type-Options", "nosniff");
      res.header("Access-Control-Allow-Origin", keys.origin.url);
        console.log(req.sessionID)
      next();
    });

    app.use("/api/", ensureSession, [
      AuthRoutes,
    ]);

    app.use("/v1/", [v1Routes]);

    // Production Mode
    if (process.env.NODE_ENV === "production") {
      // Set up homepage, static assets, and capture everything else
      app.use(express.Router().get("/", loader));
      app.use(express.static(path.resolve(__dirname, "../build")));
      app.use(loader);
      Loadable.preloadAll().then(() => {
        app.listen(PORT, console.log(`App listening on port ${PORT}!`));
      });
    }

Passport Setup

  passport.serializeUser((user, done) => {
        let tokenValue = {
        }
        if (user.providerId) tokenValue.providerId = user.providerId;
        if (user.token) tokenValue.token = user.token;
        if (user.provider) tokenValue.provider = user.provider;
        if (user.id) tokenValue.user_id = user.id;

        if (user.email) tokenValue.email = user.email;
        console.log('serializeUser-data',user);
           console.log('serializeUser-token',tokenValue);
        done(null, tokenValue)
    })
    passport.deserializeUser((data, done) => {
        console.log('DESERIALIZEUSER-data',data);
        let querySelect = `SELECT 
        us.id,
        us.displayName,
        us.email,
        us.gender,
        up.providerId,
        up.token,
        up.provider,
        us.firstname,
        us.lastname,
        ui.birthday,
        ui.phone_number from user as us 
        left join user_provider as up on us.id = up.user_id 
        left join user_information as ui on us.id = ui.user_id
        where us.id = ? `;
        db.query(querySelect, [data.user_id], (err, ress) => {
            if (ress.length > 0) {
                console.log('DESERIALIZEUSER',ress[0]);
                done(null, ress[0])
            }

        });

    })

    passport.use('local-signup', new LocalStrategy(

        {
            usernameField: 'email',
            passwordField: 'password',
            passReqToCallback: true // allows us to pass back the entire request to the callback
        },
        function (req, email, password, done) {

            let queryFindUser = `SELECT email from user_account where email = ?;SELECT email from user where email = ? and is_provider = 1;`;
            db.query(queryFindUser, [req.body.email, req.body.email], (err, result) => {

                if (err) return done(null,false, { error: true, message: "ERROR FROM REGISTER" }); 
                if (result[0].length > 0) {
                    return done(null, false,{ error: true, message: "Email is already registered" });

                }
                if (result[1].length > 0) {
                    return done(null, false, { error: true, message: "Email is already registered using social media" }); 
                }
                if(result[0].length === 0 && result[1].length === 0){
                    let queryInsert = 'INSERT into user set ?; INSERT into user_account set user_id = (select u.id from user as u order by u.id desc limit 1), ?;';
                    // let querySelectUser = `INSERT `

                    bcrypt.genSalt(10, (err, salt) => {
                        //10 adalah berapa banyak karakter
                        bcrypt.hash(req.body.password, salt, (err, hash) => {
                            if (err) {
                                throw err;
                            }
                            if (hash) {
                                db.query(queryInsert, [{ displayName: req.body.displayName, email: req.body.email }, { email: req.body.email, password: hash }], (err, result) => {
                                    if (err) return done(null, false, { error: true, message: "ERROR FROM REGISTER" });
                                    if (result) {
                                        let querySelect = `SELECT 
        us.id,
        us.displayName,
        us.email,
        us.gender,
        up.providerId,
        up.token,
        up.provider,
        us.firstname,
        us.lastname,
        ui.birthday,
        ui.phone_number from user as us 
        left join user_provider as up on us.id = up.user_id 
        left join user_information as ui on us.id = ui.user_id
        where us.id = ? `;
                                        db.query(querySelect, [result[0].insertId], (err, ress) => {
                                            if (ress.length > 0) {
                                                return done(null, ress[0])
                                            } else {
                                                return done(null, false, { error: true, message: "error from register" });
                                            }

                                        })
                                    }
                                })
                            }

                        });
                    });
                }
            }

        }

    ));

    passport.use(new LocalStrategy(
        function (email, password, done) {

            let querySelect = `SELECT 
        us.id,
        us.displayName,
        us.gender,
        us.firstname,
        us.lastname,
        ui.birthday,
        ui.phone_number,
        ua.email,
        ua.password,
        ua.email_confirm_token
        from user as us 
        left join user_account as ua on us.id = ua.user_id
        left join user_information as ui on us.id = ui.user_id
        where ua.email = ?
        `
            db.query(querySelect, [email], (err, result) => {

                if (err) return done(err, null);
                if (result.length > 0) {
                    let data = result[0];
                    bcrypt.compare(password, data.password)
                        .then(isMatch => {
                            if (isMatch) {
                                return done(null, data);
                            } else {
                                return done(null, false, { message: 'Incorrect password.' });
                            }

                        })

                }
                if (result.length === 0) {
                    return done(null, false, { message: 'Incorrect email.' });
                }

            })

        }
    ));

    passport.use(
        new GoogleStrategy({
            //options for the google strategy
            callbackURL: keys.origin.redirectProvider + '/api/auth/google/redirect',
            clientID: keys.google.clientID,
            clientSecret: keys.google.clientSecret,
            userProfileURL: 'https://www.googleapis.com/oauth2/v3/userinfo'

        }, (accessToken, refreshToken, profile, done) => {     
            let queryInsert = `INSERT INTO user set is_provider = 1, ?; INSERT INTO user_provider set user_id = (SELECT u.id from user as u order by id desc limit 1), ?;`;
            let queryUpdate = `update user_provider set token = ? where providerId = '${profile.id}'`;
            let queryFind = `SELECT 
            us.id,
            us.displayName,
            us.email,
            us.gender,
            up.providerId,
            up.token,
            up.provider,
            us.firstname,
            us.lastname,
            ui.birthday,
            ui.phone_number
            from user as us 
            left join user_provider as up on us.id = up.user_id 
            left join user_information as ui on us.id = ui.user_id
            where up.providerId = '${profile.id}' and up.provider = '${profile.provider}' and us.is_provider = 1`;

            let querySelect = `SELECT 
        us.id,
        us.displayName,
        us.email,
        us.gender,
        up.providerId,
        up.token,
        up.provider,
        us.firstname,
        us.lastname,
        ui.birthday,
        ui.phone_number from user as us 
        left join user_provider as up on us.id = up.user_id 
        left join user_information as ui on us.id = ui.user_id
        where us.id = ? and up.provider = ? and up.providerId = ?  and us.is_provider = 1`;
        const querySelectAfterUpdate = `SELECT 
        us.id,
        us.displayName,
        us.email,
        us.gender,
        up.providerId,
        up.token,
        up.provider,
        us.firstname,
        us.lastname,
        ui.birthday,
        ui.phone_number from user as us 
        left join user_provider as up on us.id = up.user_id 
        left join user_information as ui on us.id = ui.user_id
        where up.provider = ? and up.providerId = ?  and us.is_provider = 1`;
            let user = {
                email: profile.emails[0].value,
            }
            if (profile.gender) user.gender = profile.gender;
            if (profile.displayName) user.displayName = profile.displayName;
            if (Object.keys(profile.name).length > 0) {
                if (profile.name.familyName) user.lastname = profile.name.familyName;
                if (profile.name.givenName) user.firstname = profile.name.givenName;
            }

            let user_provider = {
                provider: profile.provider,
                providerId: profile.id,
                token: refreshToken ? refreshToken : accessToken
            }
            db.query(queryFind, (error, result) => {

                if (error) return done(error);
                if (result.length > 0) {
                    console.log('user', result);

                    db.query(queryUpdate, [user_provider.token], (err, ress)=>{
                        console.log('res',ress);
                        if (err) return done(err);
                        if (ress.affectedRows > 0) {
                            db.query(querySelectAfterUpdate, [profile.provider, profile.id], (err, ress) => {
                                if (err) return done(err);
                                if (ress.length > 0) {
                                    return done(null, ress[0]);
                                }

                            })
                        }
                        if (ress.affectedRows === 0){
                            return done(null, result[0]);
                        }
                    })

                } else {

                    db.query(queryInsert, [user, user_provider], (err, ress, fields) => {
                        if (err) return done(err);
                        if (ress) {
                            db.query(querySelect, [ress[0].insertId, profile.provider, profile.id], (err, ress) => {
                                if (err) return done(err);
                                if (ress.length > 0) {
                                    return done(null, ress[0]);
                                }

                            })
                        }
                    })
                }
            })

        })

    );
ajj-siraj commented 4 years ago

I had a similar issue. Long story short it was solved by removing the cookie option when passing the options to app.use(session()). I have no idea why this happens though. I hope someone can shed some light on this. For now it simply seems an inflexibility from passport (or maybe you need to pass the cookie options to passport somewhere else, but the docs don't really explain anything about that unfortunately).

dan-goyette commented 10 months ago

I had a similar issue. Long story short it was solved by removing the cookie option when passing the options to app.use(session()). I have no idea why this happens though. I hope someone can shed some light on this. For now it simply seems an inflexibility from passport (or maybe you need to pass the cookie options to passport somewhere else, but the docs don't really explain anything about that unfortunately).

In case anyone else is in the same situation, I also found that removing the cookie resolved the issue. So I looked a bit deeper. At least in my case, it's because the "domain" of the cookie was being set to a value that was appropriate in production (i.e., the domain of the actual website), but which wasn't appropriate in a test environment. By setting the cookie's "domain" property to ".localhost", that seems to correct this issue in my local environment. (Obviously assign an appropriate domain name for the cookie in prod, though.)