Note that there are some explanatory texts on larger screens.

plurals
  1. POHow do I use node-openid on Heroku with more than one dyno?
    text
    copied!<p>I'm trying to use <a href="https://github.com/havard/node-openid" rel="nofollow">node-openid</a> (via <a href="https://github.com/jaredhanson/passport-google" rel="nofollow">passport-google</a>) to authenticate my users with their Google credentials. It works fine on my development machine but when I deploy it to Heroku with 2 dynos, it works when one dyno handles the entire OpenID conversation and fails when the conversation is started on one dyno and completed on the second. In that case I get the following error:</p> <pre><code>2013-01-15T15:18:24+00:00 app[web.2]: Failed to verify assertion (message: Invalid association handle) 2013-01-15T15:18:24+00:00 app[web.2]: at Strategy.authenticate.identifier (/app/node_modules/passport-google/node_modules/passport-openid/lib/passport-openid/strategy.js:143:36) ... </code></pre> <p>What's the right way to handle this? Should I be saving the conversation state in a database somehow so that both dynos have access to it?</p> <p><strong>Update:</strong></p> <p>Here's the code I used to solve the problem by storing the assocation in MongoDB.</p> <pre><code>var GoogleStrategy = require('passport-google').Strategy; // We have to save the OpenID state in the database so it's available to both // dynos. db.collection('OpenID').ensureIndex({expires: 1}, {expireAfterSeconds: 0}, function(err, result) { if (err) { throw new Error('Error setting TTL index on OpenID collection.'); } }); // Use the GoogleStrategy within Passport. // Strategies in passport require a `validate` function, which accept // credentials (in this case, an OpenID identifier and profile), and invoke a // callback with a user object. strategy = new GoogleStrategy({ returnURL: 'http://localhost:3000/auth/google/return', realm: 'http://localhost:3000/' }, function(identifier, profile, done) { // asynchronous verification, for effect... process.nextTick(function () { // To keep the example simple, the user's Google profile is returned to // represent the logged-in user. In a typical application, you would want // to associate the Google account with a user record in your database, // and return that user instead. profile.identifier = identifier; return done(null, profile); }); } ); strategy.saveAssociation(function(handle, provider, algorithm, secret, expiresIn, done) { db.collection("OpenID").insert({ handle: handle, provider: provider, algorithm: algorithm, secret: secret, expires: new Date(Date.now() + 1000 * expiresIn) }, done); }); strategy.loadAssociation(function(handle, done) { db.collection("OpenID").findOne({handle: handle}, function (error, result) { if (error) return done(error); else return done(null, result.provider, result.algorithm, result.secret); }); }); </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload