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 }
...