Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PassportJS callback switch between http and https

Right now, when I visit my page at https://example.com and click login, it goes to https://example.com/auth/facebook, which then does the facebook stuff and ends up calling back http://example.com/auth/facebook/callback. I can't seem to get it to call back using the https scheme (but only when the request cycle started in https).

right now, when viewed through an https iframe (facebook canvas app), I get the error

[blocked] The page at 'https://apps.facebook.com/example/?fb_source=notification&ref=notif&notif_t=app_notification' was loaded over HTTPS, but ran insecure content from 'http://example.com/auth/facebook/callback?code=AQD5TUeTP…yXC0ZM8S45V2iTta629IaquCpAqVUbhAvNCFveaDBlbKg4J4#=': this content should also be loaded over HTTPS.

passport.use(new FacebookStrategy({
    clientID: process.env.FB_CLIENT,
    clientSecret: process.env.FB_SECRET,
    callbackURL: "/auth/facebook/callback",
    profileFields: ['id']
},...

app.get('/auth/facebook',
  passport.authenticate('facebook', {
    scope: ["read_stream"]
  })
);

app.get('/auth/facebook/callback',
  passport.authenticate('facebook', {
  failureRedirect: '/#'
}),
function(req, res) {
  res.redirect('/#');
});

I'm running this on heroku, where it handles the details on https.

EDIT Apparently node provides req.connection.encrypted with information as to whether the request is https. Since I am running on heroku behind nginx where that handles all of the https before node, req.connection.encrypted will always be undefined.

Still don't know how to solve this though.

like image 583
Eli White Avatar asked Dec 23 '13 08:12

Eli White


3 Answers

I looked into the Passport Oauth2 strategy code and checked that it uses req.connection.encrypted to check if it is in a secure connection. It also checks for proxies in case the server code runs behind one. It is possible to tell passport to trust a proxy if you know that you are behind one.

It seems that since SSL is handled by nginx on Heroku, req.connection.encrypted is always "undefined". (groups.google.com/forum/#!topic/express-js/Bm6yozgoDSY) Nginx handles all of the HTTPS on Heroku so node never sees req.connection.encrypted being anything other than "undefined".

To solve the problem you have to tell passport to trust the proxy adding the line

app.enable("trust proxy");

to your express server.

like image 85
Jonas Avatar answered Nov 16 '22 02:11

Jonas


I've also learned that we can accomplish the same thing by adding another property called "proxy:true" to the googleStrategy such as below:

passport.use(new GoogleStrategy({ clientID: keys.googleClientID, clientSecret: keys.googleClientSecret, callbackURL: '/auth/google/callback', proxy: true }

like image 33
Armando Musto Avatar answered Nov 16 '22 02:11

Armando Musto


Nginx handles all of the HTTPS on Heroku so node never sees req.connection.encrypted being anything other than undefined. By digging through the passportjs repositories I found that there is a check for the app to have "trust proxy" enabled. To solve this problem, add the line

app.enable("trust proxy");

to your express server.

like image 40
Eli White Avatar answered Nov 16 '22 03:11

Eli White