docs: 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')
  
        function setBodyAndResolve(content) {
          if (content) ctx.body = content
          resolve(false)
        }
  
        // mock the `res` object
        const res = {
          redirect: function(url) {
            ctx.redirect(url)
            resolve(false)
          },
          set: ctx.set.bind(ctx),
          setHeader: ctx.set.bind(ctx),
          end: setBodyAndResolve,
          send: setBodyAndResolve,
          set statusCode(status) {
            ctx.status = status
          },
          get statusCode() {
            return ctx.status
          }
        }
  
        req.res = res
  
        // 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()
        }
      })
    }
  }