This blog post is part of the Mixmax 2016 Advent Calendar. The previous post on December 4th was about CORs headers.
Microservice-based architectures have a lot of server-to-server communication. Some non-trivial portion of that communication will be with APIs that are considered “internal”. To secure this communication, people will often just lock these services away in private networks with strong subnet access controls. However, it’s often much nicer if you also provide some manner of authenticating requests between servers, or at least a mechanism for verifying that the request is coming from a trusted source. This approach will also let you secure services that aren’t fully internal and so can’t be put inside a private network.
Enter JSON web tokens (JWTs). In short, JWT is a standard for generating tokens that assert a claim and whose legitimacy can be easily verified. We wanted a simple way of generating JWTs for our internal communication. Furthermore we wanted to be easily able to rotate the shared secret used to sign and verify the tokens. So we wrote rewt - a simplified wrapper for signing JWTs with a shared secret sourced from Redis, that automatically rotates the secret on a predefined interval.
Initializing rewt
Initializing an instance of root is as simple as telling it where to source the shared secret from.
|
By default, rewt will namespace the secret key under the rewt:
namespace with a default TTL of a day. To have the key rotate on a faster interval, or you use a different namespace, you can provide alternate parameters to the constructor:
let rewt = new Rewt({
redisConn: redis.createClient('redis://localhost:6379'),
redisNamespace: 'foobar',
ttl: 60 * 60 // One hour in seconds
});
Using rewt
Signing a payload with rewt is extremely simple, just provide the payload to sign and a callback to receive the signed payload:
Note that the first parameter to
|
Worked Example using rewt
It may not be immediately obvious of how to use rewt, so in this quick example we will sign a payload with rewt, add it as an authorization header and then verify that payload and extract the relevant information.
Signing an HTTP request with rewt
Signing the request simply uses the sign
functionality to create the token and then embed it as an HTTP Authorization header (as a Bearer
token).
|
Verifying a request using rewt
We can easily build an express middleware component that extracts the userId
from the signed payload above and places it on the incoming request object.
|
Voila! We now have a mechanism for ensuring that an incoming request was sent from a trusted source.
Notes
One thing to note is that since the key is in Redis and rewt handles rotating it for you, if you ever need to rotate the key manually you can simply remove the key from Redis yourself and rewt will generate a new one to use on the next query.
Careful readers will also have noted that we spoke about the key having a TTL. This does mean that there is the miniscule chance that the key may be rotated while a request is in flight. We do not consider this as a large drawback since one should already be using appropriate retry policies for specific error classes and because this time window is very small.
Enjoy infrastructure security? Drop us a line.