0

I'm running a nodejs/reactjs app on heroku. I implemented google login using Passport. I'm getting an error "Unable to verify authorization state" when people try to login.

I see here NodeJS Express Session isn't being restored between routes in kubernetes that I need to set the X-Forwarded-SSL header. How do I do that according to what the question says?

The solution outlined on that page also mentions Apache, but Heroku doesn't make use of Apache to forward requests to apps' web dynos.

Is anyone running into the same issue on Heroku?

So the weird thing is when I try to login, it works the second time but the first time, I get the error "Unable to verify authorization state".

here's my index.js

const session = require("express-session");
app.use (
    session ({
        secret: "ddd",
        resave: false,
        saveUninitialized: true,
        cookie: {
            expires: 60 * 60 * 24,
            secure: (app.get('env') === 'production')
        }
    })
);

if (app.get('env') === 'production') {
    app.set('trust proxy', 1); // trust first proxy
}
Chris Hansen
  • 7,813
  • 15
  • 81
  • 165
  • Hey there, sorry for the late response! It might not be an issue with the request headers because, in my issue, the session never persisted, and I got that error no matter how many times I tried. Can you verify that, when you login the first time, a cookie is being set and that a session is created in your sessions table (make sure to not have cookies when testing this)? Have you tried logging all the parameters in your verify function and your serializeUser function? – Victor Feb 19 '22 at 17:58
  • Also, I'm assuming you're talking about deployed code that you're accessing through https, is that correct? Or are you on localhost? – Victor Feb 19 '22 at 19:06
  • I'm running on heroku in production in a secure environment. So yes (https) – Chris Hansen Feb 19 '22 at 19:22
  • The cookie is not being set the first time I login. – Chris Hansen Feb 19 '22 at 19:22
  • What should my serializeUser function do? – Chris Hansen Feb 19 '22 at 19:23
  • @Victor What was your solution? Can you paste your code? – Chris Hansen Feb 19 '22 at 22:16
  • I'll post my code as an answer – Victor Feb 20 '22 at 16:55

1 Answers1

0

So as I mentioned your issue might not be related to the request headers because in my issue, session never persisted, whereas yours does in your second attempt. It might be an issue with your verify function or your deserializeUser function.

Here's an example. I don't use Google auth personally, but something else. My code looks similar, but I got some of the Google auth code from https://github.com/jaredhanson/passport-google/blob/master/examples/signon/app.js. Fill in your stuff where appropriate and debug/log what's coming in to see how your functions are being called.

passport.use(new GoogleStrategy({
    returnURL: 'http://localhost:3000/auth/google/return', // replace with yours
    realm: 'http://localhost:3000/' // replace with yours
}, function (identifier, profile, done) { 
    // console.log identifier and profile, or even better, use your debugger on this line and see what's happening

    // Do whatever you need to do with identifier and then..
    return done(null, profile);
}));

passport.serializeUser(async (user, done) => {
    // console.log user or use your debugger on this line and see what's happening

    const userInDb = await db.getUser(user) // Find your user in your db using based on whatever is in the user object 
    const  serializedSessionUser = {id: userInDb.id, username: userInDb.username} // this is the object that'll appear in req.user. Customize it like you want
    return done(null, serializedSessionUser); // Commit it to the session
});

passport.deserializeUser((user, done) => {
    done(null, user);
});

Edit: Apparently there's 2 ways to use Google for passport. The first is OAuth / OAuth 2.0. The second is OpenID. I used OpenID in this example. Adjust accordingly!

Edit 2: Here's my own equivalent to your index.js:

app.use(session({
    cookie: {
        sameSite: 'lax',
        secure: !['development', 'test'].includes(process.env.NODE_ENV),
        maxAge: 1000 * 60 * 60 * 24 * 30, // 30 days
    },
    proxy: true,
    resave: false,
    saveUninitialized: true,
    secret: process.env.COOKIE_SECRET,
    store: 'your store',
    rolling: true,
}));
Victor
  • 578
  • 7
  • 12
  • This answer may also help you: https://stackoverflow.com/questions/53813544/nodejs-app-hosted-on-heroku-dont-set-client-side-cookie – Victor Feb 20 '22 at 17:54