Overriding Node.js Module Dependencies

colony

The modular nature of Node.js is great for maintainability, but have you ever been in a situation where you need to change or add functionality of a module that another module requires?

For instance, you might want to implement sign-on with Google Plus and use the jsonwebtoken library to verify that the id_token was signed by Google. However, you might soon find that it uses the jws library, which expects a PEM-encoded public key, and not the JWK set that Google provides. Here is the relevant source code:

var jws = require('jws');

try {  
  valid = jws.verify(jwtString, secretOrPublicKey);
} catch (e) {
  return done(e);
}

And, from the jws documentation:

jws.verify(signature, secretOrKey)

(Synchronous) Returns true or false for whether a signature matches a secret or key.

signature is a JWS Signature. secretOrKey is a string or buffer containing either the secret for HMAC algorithms, or the PEM encoded public key for RSA and ECDSA.

Thankfully, there is a drop-in replacement for jws, but how do we get jsonwebtoken to load it without modifying the source code?

Here's one way:

var module = require('module');  
var jws = require('jws');

module._cache[require.resolve('jws')].exports = require('jws-jwk').shim();

var jwt = require('jsonwebtoken');  

When Node.js loads a module, it is read from the filesystem once, and stored in the internal _cache object, which is keyed by the full path to the module. Subsequent require() calls that resolve to the same path are loaded directly from the cache.

We can take advantage of this behavior by requiring the underlying library, jws, to ensure that it is loaded into the cache. We then access the module cache directly and override the exports property of the loaded module with its replacement. Any subsequent loads of the same module will use the new version. Voila!

Note that this approach is somewhat of a hack, as it uses a private API that could change in future versions. It is certainly not a best practice, but can be a quick and dirty way to mock up nested dependencies.

Valentyn Boginskey
Valentyn Boginskey

Valentyn is a system administrator turning web developer. He is passionate about privacy and virtual currencies. In his spare time, he enjoys mountain biking, skiing, backpacking, and racing go-karts.