docs: async function facebook(router, config = {}) {
    const {
      client_id,
      client_secret,
      path = '/auth/facebook',
      scope,
      finish = /* async */ (ctx, token, user, /* next */) => {
        ctx.session.token = token
        ctx.session.user = user
        ctx.redirect('/')
        // await next()
      },
    } = config
    if (!client_id) {
      console.warn('No client id - the dialog won\'t work.')
    }
    if (!client_secret) {
      console.warn('No client secret - the redirect won\'t work.')
    }
  
    router.get(path, async (ctx) => {
      const state = Math.floor(Math.random() * 10000)
      ctx.session.state = state
      const redirect_uri = getRedirect(ctx, path)
      const u = facebookDialogUrl({
        redirect_uri,
        client_id,
        scope,
        state,
      })
      ctx.redirect(u)
    })
    router.get(`${path}/redirect`, async (ctx, next) => {
      const redirect_uri = getRedirect(ctx, path)
      const state = ctx.query.state
      if (state != ctx.session.state) {
        throw new Error('The state is incorrect.')
      }
      ctx.session.state = null
      if (!ctx.query.code) throw new Error('Code Not Found.')
  
      const token = await exchange({
        client_id,
        client_secret,
        redirect_uri,
        code: ctx.query.code,
      })
      const data = await graphGet('/me', token, {}, true)
      await finish(ctx, token, data, next)
    })
  }