Shane Jeffery
Compli Engineering
Published in
3 min readMar 27, 2017

--

[gRPC + NodeJS] Using JWT Authentication

At Compli, we just made the swap from using PHP 5.6, Laravel 5.4, and mySQL to using NodeJS, gRPC, and MongoDB to further build out our microservice architecture. During original proof of concept, we were just looking at using Express (REST API) for our application routing, but decided that gRPC was a much better way to go given our infrastructure and the fact that all of our APIs were internal-facing.

The Problem

As it stands, there is not a lot of help out there for how you work with gRPC, especially with authentication that does not follow a standard, like Google’s authentication or OAuth.

Instead of going with a pre-existing authentication system, we decided to build our own and the result was a Authentication microservice that relies on JWT (Json Web Token). Our service will take in a key and secret that are base64 encoded together and sends that over along with some other data specific to the client and the user making the request. If the request is a valid one and passes verification, then a JWT is provisioned and sent back to the requester.

Now, with having the JWT, we had no idea how to make this work with gRPC considering the fact that gRPC is hijacking the request and response, which is very different from how Express does things. It turns out that gRPC has HTTP headers already exposed in the call.

The Solution

In the code for one of your gRPC functions, do a simple console.log(call.request). Hit your function with something like Postman or CURL and ensure that you have a Authorization token in the headers (Authorization: Bearer: <token>). In the console, you will see that there is a metadata object that has all of the HTTP headers and more!

To the get the token out, do:

call.metadata._internal_repr.authorization.toString();

Now that we have the token, we want to validate it and get the information out of the payload before we do any other actions within the function. For this, we will need a Promise.

const jwtAuth = require('../middlewares/jwt_auth');// Server will crash if we call toString() on null (no auth header sent).
if (call.metadata._internal_repr.authorization == null) {
callback(new Error("Unauthorized"), null);
return;
}
let bearerHeader = call.metadata._internal_repr.authorization.toString();
let promise = jwtAuth(bearerHeader);

promise.then(jwtDecoded => {
<the_rest_of_your_code_here>
}).catch(err => {
callback(err, null);
});

As you can see by the above code, I am requiring middleware (this is the part that verifies the token and decodes the payload) and then passing over the Authorization Bearer token to the middleware function I defined in that file expecting a response back from the promise that will include my payload.

As for the middleware function that I wrote, here it is:

const jwt = require('jsonwebtoken');

module.exports = function(bearerHeader) {

return new Promise(function(resolve, reject) {
let bearerToken;

if (typeof bearerHeader !== 'undefined') {

let bearer = bearerHeader.split(" ");
bearerToken = bearer[1];

jwt.verify(bearerToken, process.env.JWT_SECRET, function(err, decoded) {

if (err) {
reject(err)
}

resolve(decoded);
});
} else {
reject("No authorization bearer token was found or the token was formatted improperly.");
}
});
};

Here we are using the jsonwebtoken npm package to handle the verification of the token and the decoding of the payload. The resolve(decoded) line will give me back the payload of the JWT as expected in the calling file that started the Promise.

That is everything! I hope this helps someone else!

--

--