node.jsexpressaxios

How to pass client req object from node server to an Express route via an axios request?


I have created a Websocket (using ws package) server that receives messages from the user. When a message is sent, it goes directly to the server that handles it like this:

const WSS = new WebSocketServer({noServer: true});

WebServer.on('upgrade', async (req, socket, head) => {
// original 'req' has the data required for authentication
try {
       await authenticateUser(req.headers); // Contains JWT token
    } catch (error) {
           console.log(`onupgrade error: ${error}`)
           socket.write('HTTP/1.1 401 Unauthorized\r\n\r\n');
           socket.destroy();
           return;
        }

  WSS.on('connection', (ws, req) => {

     ws.on('message', async (data, isBinary) => {
    
     if(data.sentevent === 'Delivered') { 
     // Make an axios request but need to attach the req object from above
     axios.post(`/api/v1/messagetracker`,{
       messageid: 1234
     });
     }
  })

  });
});

The Express route /api/v1/messagetracker uses middleware to authenticate a user like this:

ExpressRouter.post('/api/v1/messagetracker',
    Middlewares.authenticateUser,
    async function (req, res, next) {
    ...
});

The authenticateUser just decodes the JWT token:

async function authenticateUser(req, res, next) {
    try {
        req.UserDetails = await getUserData(req);
    } catch (error) {
        return res.status(error.code).json(error);
    }
    next();
}

If the route was POST by the client then the req exists with cookies that contain the JWT token. However when a request is made from the node server, there are obviously no JWT tokens.

I therefore need to pass the req that was sent to node server (via a websocket connection) from the client on to the Express router.

Is there any way to achieve this?


Solution

  • Extract the JWT token from the websocket request since the initial websocket connection (this is the req object in the on('upgrade') callback function) contains the JWT token in the header, you can then extract this token and store it for use in subsequent WebSocket messages.

    Attach the token to the axios request when making the request from the websocket server by manually attaching the JWT token as an authorization header.

    For example:

    const WSS = new WebSocketServer({ noServer: true });
    let jwtToken = null; // Store JWT token for the connection
    
    WebServer.on('upgrade', async (req, socket, head) => {
        try {
            // Authenticate the user during the WebSocket upgrade
            await authenticateUser(req.headers);
            jwtToken = req.headers['authorization']; // Store the JWT token from the initial request
        } catch (error) {
            console.log(`onupgrade error: ${error}`);
            socket.write('HTTP/1.1 401 Unauthorized\r\n\r\n');
            socket.destroy();
            return;
        }
    
        WSS.on('connection', (ws, req) => {
            ws.on('message', async (data, isBinary) => {
                if (data.sentevent === 'Delivered') {
                    // Make an axios request and attach the JWT token as a bearer token in the authorization header
                    axios.post(`/api/v1/messagetracker`, {
                        messageid: 1234
                    }, {
                        headers: {
                            'Authorization': jwtToken // Attach JWT token
                        }
                    })
                    .then(response => {
                        console.log('Message tracking success:', response.data);
                    })
                    .catch(error => {
                        console.error('Message tracking error:', error.response?.data || error.message);
                    });
                }
            });
        });
    });
    

    Then check for the Authorization header in your middleware on your express route and decode your JWT token