jrajp2184
jrajp2184

Reputation: 320

Does passport.js require session affinity when deployed on multiple node.js instances

Does passport.js require session affinity when deployed on multiple Node.js instances? When I am employing session affinity the authentication works properly with multiple instances (behind a load balancer). I am using redis as session store. However, when not using session affinity the passport.js is failing with the error given below. With a single instance it always works. Is there any way to make passport.js work without session affinity.

    500 Failed to verify assertion (message: Invalid association handle)

    at Strategy.authenticate.identifier (node_modules/passport-google/node_modules/passport-openid/lib/passport-openid/strategy.js:184:36)
    at _verifyAssertionData (node_modules/passport-google/node_modules/passport-openid/node_modules/openid/openid.js:1053:12)
    at _verifyAssertionAgainstProvider (node_modules/passport-google/node_modules/passport-openid/node_modules/openid/openid.js:1178:14)
    at _checkSignatureUsingAssociation (node_modules/passport-google/node_modules/passport-openid/node_modules/openid/openid.js:1229:14)
    at Object.openid.loadAssociation (node_modules/passport-google/node_modules/passport-openid/node_modules/openid/openid.js:111:5)
    at _checkSignatureUsingAssociation (node_modules/passport-google/node_modules/passport-openid/node_modules/openid/openid.js:1221:10)
    at _checkSignature (node_modules/passport-google/node_modules/passport-openid/node_modules/openid/openid.js:1211:5)
    at _verifyAssertionAgainstProvider (node_modules/passport-google/node_modules/passport-openid/node_modules/openid/openid.js:1174:3)
    at _verifyDiscoveredInformation node_modules/passport-google/node_modules/passport-openid/node_modules/openid/openid.js:1145:16)
    at openid.discover (node_modules/passport-google/node_modules/passport-openid/node_modules/openid/openid.js:668:7)

The code snippet using passport:

app.set('port', process.env.PORT || 8080);
app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.query());
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(express.cookieParser()); 
app.use(express.session({ key: 'JSESSIONID', secret: '****', cookie : {httpOnly:false, 
   maxAge: 5*60*1000, path: '/'},
    store: new RedisStore({ prefix: 'sid:', client: redisClient })
                    }));
app.use(passport.initialize());
app.use(passport.session());
app.use(app.router);
app.use(express.static(path.join(__dirname, 'public')));
app.get('/auth/google', passport.authenticate('google'));
app.get('/auth/google/return', 
      passport.authenticate('google', { successRedirect: '/success',
                                        failureRedirect: '/login' }));

I also have serializeUser and deserializeUser that uses redis store to store/retrieve user object - but this error is happening when the identity provider redirects back to the callback URI. I am deploying my app in AppFog and setting the session affinity using JSESSIONID cookie key (that's how cloudfoundry load balancers work). If I use any other key (that means session affinity is off) then the error is thrown by passport.js.

Upvotes: 6

Views: 1952

Answers (1)

jrajp2184
jrajp2184

Reputation: 320

I think I have fixed it. There is an option: 'stateless' that can be passed to GoogleStrategy. I figured it out by looking at the source: https://github.com/jaredhanson/passport-openid/blob/master/lib/passport-openid/strategy.js. Therefore the GoogleStrategy instantiation must be:

new GoogleStrategy({
   returnURL: BASE + '/auth/google/return',
   realm: BASE + "/",
   stateless: true
}

Thanks to Jared Hanson for implementing such an option! (hopefully it will get documented at the main site).

Upvotes: 7

Related Questions