function Authenticator() { this._key = 'passport'; this._strategies = {}; this._serializers = []; this._deserializers = []; this._infoTransformers = []; this._framework = null; this._userProperty = 'user'; this.init(); }
n/a
class KoaPassport extends Passport { constructor() { super() this.framework(framework) } }
n/a
function Authenticator() { this._key = 'passport'; this._strategies = {}; this._serializers = []; this._deserializers = []; this._infoTransformers = []; this._framework = null; this._userProperty = 'user'; this.init(); }
n/a
function Strategy() { }
n/a
function SessionStrategy() { Strategy.call(this); this.name = 'session'; }
n/a
function Authenticator() { this._key = 'passport'; this._strategies = {}; this._serializers = []; this._deserializers = []; this._infoTransformers = []; this._framework = null; this._userProperty = 'user'; this.init(); }
n/a
_strategy = function (name) { return this._strategies[name]; }
n/a
authenticate = function (strategy, options, callback) { return this._framework.authenticate(this, strategy, options, callback); }
...
## 0.4.0
- Add support for custom authentication methods, e.g.:
```js
public.post('/login', function*(next) {
var ctx = this
yield* passport.authenticate('local', function*(err, user, info) {
if (err) throw err
if (user === false) {
ctx.status = 401
ctx.body = { success: false }
} else {
yield ctx.login(user)
ctx.body = { success: true }
...
authorize = function (strategy, options, callback) { options = options || {}; options.assignProperty = 'account'; var fn = this._framework.authorize || this._framework.authenticate; return fn(this, strategy, options, callback); }
n/a
deserializeUser = function (fn, req, done) { if (typeof fn === 'function') { return this._deserializers.push(fn); } // private implementation that traverses the chain of deserializers, // attempting to deserialize a user var obj = fn; // For backwards compatibility if (typeof req === 'function') { done = req; req = undefined; } var stack = this._deserializers; (function pass(i, err, user) { // deserializers use 'pass' as an error to skip processing if ('pass' === err) { err = undefined; } // an error or deserialized user was obtained, done if (err || user) { return done(err, user); } // a valid user existed when establishing the session, but that user has // since been removed if (user === null || user === false) { return done(null, false); } var layer = stack[i]; if (!layer) { return done(new Error('Failed to deserialize user out of session')); } function deserialized(e, u) { pass(i + 1, e, u); } try { var arity = layer.length; if (arity == 3) { layer(req, obj, deserialized); } else { layer(obj, deserialized); } } catch(e) { return done(e); } })(0); }
n/a
framework = function (fw) { this._framework = fw; return this; }
...
connect.__monkeypatchNode = function() {}
// load passport and add the koa framework
const passport = require('passport')
const Passport = require('passport').Passport
const framework = require('./framework/koa')()
passport.framework(framework)
class KoaPassport extends Passport {
constructor() {
super()
this.framework(framework)
}
}
...
init = function () { this.framework(require('./framework/connect')()); this.use(new SessionStrategy()); }
n/a
initialize = function (options) { options = options || {}; this._userProperty = options.userProperty || 'user'; return this._framework.initialize(this, options); }
...
// Sessions
const convert = require('koa-convert') // necessary until koa-generic-session has been updated to support koa@2
const session = require('koa-generic-session')
app.keys = ['secret']
app.use(convert(session()))
const passport = require('koa-passport')
app.use(passport.initialize())
app.use(passport.session())
```
[Example Application](https://github.com/rkusa/koa-passport-example)
Passport's values and methods are exposed as follows:
...
serializeUser = function (fn, req, done) { if (typeof fn === 'function') { return this._serializers.push(fn); } // private implementation that traverses the chain of serializers, attempting // to serialize a user var user = fn; // For backwards compatibility if (typeof req === 'function') { done = req; req = undefined; } var stack = this._serializers; (function pass(i, err, obj) { // serializers use 'pass' as an error to skip processing if ('pass' === err) { err = undefined; } // an error or serialized object was obtained, done if (err || obj || obj === 0) { return done(err, obj); } var layer = stack[i]; if (!layer) { return done(new Error('Failed to serialize user into session')); } function serialized(e, o) { pass(i + 1, e, o); } try { var arity = layer.length; if (arity == 3) { layer(req, user, serialized); } else { layer(user, serialized); } } catch(e) { return done(e); } })(0); }
n/a
session = function (options) { return this.authenticate('session', options); }
...
const convert = require('koa-convert') // necessary until koa-generic-session has been updated to support koa@2
const session = require('koa-generic-session')
app.keys = ['secret']
app.use(convert(session()))
const passport = require('koa-passport')
app.use(passport.initialize())
app.use(passport.session())
```
[Example Application](https://github.com/rkusa/koa-passport-example)
Passport's values and methods are exposed as follows:
```js
...
transformAuthInfo = function (fn, req, done) { if (typeof fn === 'function') { return this._infoTransformers.push(fn); } // private implementation that traverses the chain of transformers, // attempting to transform auth info var info = fn; // For backwards compatibility if (typeof req === 'function') { done = req; req = undefined; } var stack = this._infoTransformers; (function pass(i, err, tinfo) { // transformers use 'pass' as an error to skip processing if ('pass' === err) { err = undefined; } // an error or transformed info was obtained, done if (err || tinfo) { return done(err, tinfo); } var layer = stack[i]; if (!layer) { // if no transformers are registered (or they all pass), the default // behavior is to use the un-transformed info as-is return done(null, info); } function transformed(e, t) { pass(i + 1, e, t); } try { var arity = layer.length; if (arity == 1) { // sync var t = layer(info); transformed(null, t); } else if (arity == 3) { layer(req, info, transformed); } else { layer(info, transformed); } } catch(e) { return done(e); } })(0); }
n/a
unuse = function (name) { delete this._strategies[name]; return this; }
n/a
use = function (name, strategy) { if (!strategy) { strategy = name; name = strategy.name; } if (!name) { throw new Error('Authentication strategies must have a name'); } this._strategies[name] = strategy; return this; }
...
- update custom authentication callback arguments to `err, user, info, status` (e.g. `passport.authenticate('local', function
(err, user, info, status) { ... })(ctx, next)`)
## Usage
```js
// body parser
const bodyParser = require('koa-bodyparser')
app.use(bodyParser())
// Sessions
const convert = require('koa-convert') // necessary until koa-generic-session has been updated to support koa@2
const session = require('koa-generic-session')
app.keys = ['secret']
app.use(convert(session()))
...
function Strategy() { }
n/a
authenticate = function (req, options) { throw new Error('Strategy#authenticate must be overridden by subclass'); }
...
## 0.4.0
- Add support for custom authentication methods, e.g.:
```js
public.post('/login', function*(next) {
var ctx = this
yield* passport.authenticate('local', function*(err, user, info) {
if (err) throw err
if (user === false) {
ctx.status = 401
ctx.body = { success: false }
} else {
yield ctx.login(user)
ctx.body = { success: true }
...
function authenticate(passport, name, options, callback) { // normalize arguments if (typeof options === 'function') { callback = options options = {} } options = options || {} if (callback) { // When the callback is set, neither `next`, `res.redirect` or `res.end` // are called. That is, a workaround to catch the `callback` is required. // The `passportAuthenticate()` method below will therefore set // `callback.resolve` and `callback.reject`. Then, once the authentication // finishes, the modified callback calls the original one and afterwards // triggers either `callback.resolve` or `callback.reject` to inform // `passportAuthenticate()` that we are ready. const _callback = callback callback = function(err, user, info, status) { try { Promise.resolve(_callback(err, user, info, status)) .then(() => callback.resolve(false)) .catch(err => callback.reject(err)) } catch (err) { callback.reject(err) } } } const middleware = promisify(_authenticate(passport, name, options, callback)) return function passportAuthenticate(ctx, next) { // this functions wraps the connect middleware // to catch `next`, `res.redirect` and `res.end` calls const p = new Promise((resolve, reject) => { // mock the `req` object const req = createReqMock(ctx, options.assignProperty || passport._userProperty || 'user') // mock the `res` object const res = { redirect: function(url) { ctx.redirect(url) resolve(false) }, setHeader: ctx.set.bind(ctx), end: function(content) { if (content) ctx.body = content resolve(false) }, set statusCode(status) { ctx.status = status }, get statusCode() { return ctx.status } } // update the custom callback above if (callback) { callback.resolve = resolve callback.reject = reject } // call the connect middleware middleware(req, res).then(resolve, reject) }) return p.then(cont => { // cont equals `false` when `res.redirect` or `res.end` got called // in this case, call next to continue through Koa's middleware stack if (cont !== false) { return next() } }) } }
...
## 0.4.0
- Add support for custom authentication methods, e.g.:
```js
public.post('/login', function*(next) {
var ctx = this
yield* passport.authenticate('local', function*(err, user, info) {
if (err) throw err
if (user === false) {
ctx.status = 401
ctx.body = { success: false }
} else {
yield ctx.login(user)
ctx.body = { success: true }
...
function authorize(passport, name, options, callback) { options = options || {} options.assignProperty = 'account' return authenticate(passport, name, options, callback) }
n/a
function initialize(passport) { const middleware = promisify(_initialize(passport)) return function passportInitialize(ctx, next) { // koa <-> connect compatibility: const userProperty = passport._userProperty || 'user' // check ctx.req has the userProperty if (!ctx.req.hasOwnProperty(userProperty)) { Object.defineProperty(ctx.req, userProperty, { enumerable: true, get: function() { return ctx.state[userProperty] }, set: function(val) { ctx.state[userProperty] = val } }) } // create mock object for express' req object const req = createReqMock(ctx, userProperty) // add Promise-based login method const login = req.login ctx.login = ctx.logIn = function(user, options) { return new Promise((resolve, reject) => { login.call(req, user, options, err => { if (err) reject(err) else resolve() }) }) } // add aliases for passport's request extensions to Koa's context ctx.logout = ctx.logOut = req.logout.bind(req) ctx.isAuthenticated = req.isAuthenticated.bind(req) ctx.isUnauthenticated = req.isUnauthenticated.bind(req) return middleware(req, ctx).then(function() { return next() }) } }
...
// Sessions
const convert = require('koa-convert') // necessary until koa-generic-session has been updated to support koa@2
const session = require('koa-generic-session')
app.keys = ['secret']
app.use(convert(session()))
const passport = require('koa-passport')
app.use(passport.initialize())
app.use(passport.session())
```
[Example Application](https://github.com/rkusa/koa-passport-example)
Passport's values and methods are exposed as follows:
...
function SessionStrategy() { Strategy.call(this); this.name = 'session'; }
n/a
function SessionStrategy() { Strategy.call(this); this.name = 'session'; }
n/a
function Strategy() { }
n/a
authenticate = function (req, options) { if (!req._passport) { return this.error(new Error('passport.initialize() middleware not in use')); } options = options || {}; var self = this, su; if (req._passport.session) { su = req._passport.session.user; } if (su || su === 0) { // NOTE: Stream pausing is desirable in the case where later middleware is // listening for events emitted from request. For discussion on the // matter, refer to: https://github.com/jaredhanson/passport/pull/106 var paused = options.pauseStream ? pause(req) : null; req._passport.instance.deserializeUser(su, req, function(err, user) { if (err) { return self.error(err); } if (!user) { delete req._passport.session.user; self.pass(); if (paused) { paused.resume(); } return; } var property = req._passport.instance._userProperty || 'user'; req[property] = user; self.pass(); if (paused) { paused.resume(); } }); } else { self.pass(); } }
...
## 0.4.0
- Add support for custom authentication methods, e.g.:
```js
public.post('/login', function*(next) {
var ctx = this
yield* passport.authenticate('local', function*(err, user, info) {
if (err) throw err
if (user === false) {
ctx.status = 401
ctx.body = { success: false }
} else {
yield ctx.login(user)
ctx.body = { success: true }
...