Search code examples
node.jsjwtbasic-authenticationkoa

How can I use Basic authentication or JWT to the same route in Node?


Is there any way to use Basic Authentication or JWT to the same route in Node, using Koajs?

I tried 2 approachs:

  1. Using Koa middleware, call next() when it have had a Bearer token or when have had a Basic authentication, create a token and set to ctx.headers, but it didn't work

  2. Using getToken from koa-jwt, but I can't return a promise to load user information in order to create a token.


Solution

  • I found the error. I forgot to use await when call next()

    Thx @shanks for your time!

    Here is the working code:

    route.js

    'use strict'
    
    import Koa from 'koa'
    import mount from 'koa-mount'
    import jwt from 'koa-jwt'
    import basicAuth from './basic-auth'
    import HomeRouter from './home/router'
    import projectRouter from './v1/project/router'
    
    export default new Koa().
      use(mount('/', HomeRouter.routes())).
      use(basicAuth).
      use(jwt({ secret: process.env.JWT_SECRET })).
      use(mount('/v1/projects', projectRouter.routes()))
    

    basic-auth.js

    'use strict'
    
    import { chain } from 'lodash'
    import jwt from 'jsonwebtoken'
    import User from 'app/v1/user/model'
    
    function _createAccessToken(user) {
    
      return jwt.sign({
        id: user.id,
        email: user.email
      }, process.env.JWT_SECRET)
    }
    
    export default async function basicAuth(ctx, next) {
    
      const header = ctx.headers.authorization
      if (/basic/i.test(header)) {
    
        const password = chain(header).
          split(' ').
          last().
          value()
    
        const user = await User.findOne({
          where: {
            apiPassword: Buffer.from(password, 'base64').toString()
          }
        })
    
        if (!user) return ctx.throw(401)
        const token = _createAccessToken(user)
        ctx.headers.authorization = `Bearer ${token}`
      }
      await next()
    }