16 Jul 2012 Using passport with flatiron (or - strictly - union).
So, few days ago I tried using passport authenticating middleware with flatiron framework and found out it doesn’t really want to come along.
It’s not really about flatiron, but about it’s middleware framework, called union.
The main problem is, it doesn’t use standard http.IncomingMessage
prototype, passing it’s own union.RoutingStream
instead. Luckily for us, there’s a #flatiron branch available with a quick hack to work around it. Also, according to the #24 issue there should be native support for different frameworks in passport, soon. So, first thing to do for now is to add following line to our package.json
:
1 2 3 |
"dependencies": { "passport": "git://github.com/jaredhanson/passport.git#flatiron" } |
After npm install
we should be able to create a simple authentication:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
app = flatiron.app LocalStrategy = require('passport-local').Strategy passport.use new LocalStrategy (email, password, done) -> # usual auth logic here app.use flatiron.plugins.http, before: [ connect.cookieParser() connect.session secret: 'passport-flatiron' passport.initialize() passport.session() ] passport.serializeUser (user, done) -> done null, user passport.deserializeUser (obj, done) -> User.findOne email: obj, (err, user) -> # change to our db query done err, user routes = '/login': get: # render login form here post: -> res = @res passport.authenticate('local') @req, @res, -> res.emit 'next' app.router = new director.http.Router(routes) app.start 8080 |
But this will just tell us ‘Unauthorized’ or… ‘Not found’.
To make it useful let’s redirect the user on success/failure using passport’s standard options, successRedirect
and failureRedirect
: (Note: for other ways, see this gist and comments)
1 2 3 4 5 6 7 |
routes = '/login': post: res = @res passport.authenticate('local', successRedirect: '/members', failureRedirect: '/login' ) @req, @res, -> res.emit 'next' |
And it explodes:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
node_modules/mongoose/lib/utils.js:413 throw err; ^ TypeError: Object [object Object] has no method 'redirect' at Context.module.exports.delegate.fail (node_modules/passport/lib/passport/middleware/authenticate.js:119:20) at Context.actions.fail (node_modules/passport/lib/passport/context/http/actions.js:35:22) at verified (node_modules/passport-local/lib/passport-local/strategy.js:81:30) at Promise.app.use.before.stylus.middleware.src (test1.coffee:87:16) at Promise.addBack (node_modules/mongoose/lib/promise.js:120:8) at Promise.EventEmitter.emit (events.js:88:17) at Promise.emit (node_modules/mongoose/lib/promise.js:59:38) at Promise.complete (node_modules/mongoose/lib/promise.js:70:20) at Query.findOne (node_modules/mongoose/lib/query.js:856:30) at exports.tick (node_modules/mongoose/lib/utils.js:408:16) |
It turns out that union doesn’t provide res.redirect
method :( (see #34 and #36 for references). The way to get around this is to hack res.redirect
in manually:
1 2 3 4 5 6 |
app = flatiron.app app.before.push (req, res) -> res.redirect = (path) -> res.writeHead 302, 'Location': path res.end() res.emit 'next' |
This way passport should be able to actually redirect the user to specified location.