Search code examples
node.jsapiexpressauthenticationmicroservices

Authenticate Microservice-based API endpoints in Express/Node Js


I am making a simple microservice-based backend server using express / MongoDB / Node js for ToDo application.

I have one MongoDB database and two separate collections (tables) users and todos

First Microservice is for users with add user, delete user, login (returns JWT Token to the client and store in MongoDB for future verification of private routes), and logout API endpoint (remove JWT token from database).

My second ToDo microservice consists of three routes add, edit, and delete todo and these all are private routes mean they should not be accessible without user authentication.

Following are abstract from both microservices code

USER Microservice

Auth middleware code (decodes token and look in user collection to revalidate the token )

const auth = async (req, res, next) => {
    try {
        const token = req.header('Authorization').replace('Bearer ', '')

        const decoded_token = jwt.verify(token, process.env.JWT_SECRET)
        const user = await Users.findOne({ _id: decoded_token._id, 'tokens.token': token })

        if (!user) {
            throw new Error()
        }

        req.token = token
        req.user = user

        next()
    } catch (e) {
        console.log(e)
        res.status(401).send({ error: 'Please login first.' })
    }
} 

Delete current logged in user endpoing

routes.delete('/users/me', auth, async (req, res) => {
    try {
        await req.user.remove()

        res.send(req.user)

    } catch (e) {
        res.status(500).send()
    }
})

Everything above is fine as auth middleware, users schema/model, and user delete endpoint is in my first microservice

Problem comes below

ToDo Microservice

Add ToDo endpoint

routes.post('/add', auth, async (req, res) => {
     try {
        const todo = new ToDo({
            ...req.body,
            user_id: req.user._id
        })

        await todo.save()

        res.send({ todo })
    }
    catch (e) {
        res.status(400).send(e)
    }
})

I wanted to use auth middleware on all todo microservice endpoint as I used at delete user endpoint in users microservice.

Now my question: How would I auth any endpoint in any microservice other than user microservice which has all the required stuff but others don't have

Is it good to rewrite auth middleware code again in todo microservice as it will redundant the code and secondly even I redundant the code there is no User schema/model in todo microservice?

Or do I create an auth API endpoint in users microservice which validates token from the database and returns user object which can be called from any other microservice for user authentication?


Solution

  • You should try to make use of API Gateway in your micro-service architecture.

    For example:- you can make use of Kong - https://konghq.com/kong . It comes with it's own PostgreSQL DB as well.

    Now let's look at the flow of how requests would work in case of your scenario.

    Client           |        Middleware          |  User Service             | ToDo Service
    
    1. Logs in ------------------------------------>Authenticates user
                                                    generates token
                        <------------------------- saves token in postgres
            <--------------------------------------send token to client
    
    2.Now user hits
      any endpoint ---------->verify the token 
                              with the saved token -------------------------------> GET, POST
                               If yes then hit
                               any service
    

    So in short by making use of API gateway, you can implement the JWT authentication structure easily.

    Hope this helps!