PassportJS callback switch between http and https

facebook, javascript, node.js, passport.js

Solution

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.

Problem

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.

Original source