Auth Claims to Go

Life with JWT as a full stack developer

TLDR: Moving to JWT often makes scaling and security sense, but can complicate life for feature developers. Abstracting away the auth system with generated tokens can simplify your development environment.

Your organization, growing quickly and trying to support an ever-larger gang of software engineers, has been busy devolving subsystems out of it’s crusty old monolithic application and into a swarm of restful web services.

With any luck, this has gone well at the edges. Relatively uncoupled systems with few (or no) downstream dependencies can be low hanging fruit. Likewise, totally new features are great candidates to get their own service.

But, the Council of Neckbeards has decided it’s time to break off something meatier. The http session based authentication system that is twisted around the stone heart of your monolith has got to go. In it’s place you’re getting a shiny, stateless authorization and authentication system that shares claims in JSON Web Tokens.

{
"sub": "miley"
"roles": [ "singer", "actress", "cautionarytale" ]
"iss": "gatekeeper.yourjob.com",
"aud": "valubleservice.yourjob.com",
...
]
}

Stateless, token based auth has operational and architectural advantages that will give your org room to scale up total users, data and engineering teams. This paradigm reduces coupling across your data models, is more portable outside the monolith and improves performance by cutting down on calls to the user database.

But what has JWT done for me lately?

Fig. 1: Full Production Architecture

The switch to a stateless auth regiment generally adds another layer or two to your network architecture. Replicating this in your development environment can be a pain. However, since your user authorization claims are no longer tied to a session, you can leverage the flexibility of the token to actually simplify your life as a developer.

In particular, JWT offers a common set of goodies for engineers who are working across multiple layers in the architecture.

Lets imagine that we’re working on a website for a Chinese restaurant and we want to add support for including custom fortune cookies with each meal.

  1. Anyone can Add random fortune cookies to an Order.
  2. Employees and customers who’s birthday is today can Edit a fortune cookie (to say whatever they want).

An important thing to note about this architecture is the single point of token validation at the Gateway. This makes security sense since access to the signing key can be limited to the Gateway and the signing service. Similarly, any sensitive token fields can be encrypted in public and sent as clear text in the private network.

Easily generate claims in Dev

First, we need to get out from under that monolith. Under a session based system, this would require building a mock service or just running the whole damn stack in your development environment.

With JWT, we just need to generate a JSON object and encode it in a cookie. This could be done by hand, but you should consider building a simple utility to produce tokens that are consistent with your claims schema. For reference, here’s a chrome extension I wrote to author generic JWTs. Once again, I’d encourage you to customize it with your own schema.

Fig. 2: Generating JWTs for Development

Shorten your development stack

One thing to notice about the above diagram is that the only remaining element with access to the signing key is the Gateway . Since the Fortune Cookie Service is expecting pre-validated tokens, we can often completely ignore that step in our development environment.

Fig. 3: Minimal Dev Stack — Client, Server and custom Tokens!

Phew. That’s a lot better, right? Building features across layers in SOA is hard enough. The last thing we want is to stand up a bunch of services we have no intention of touching.

It’s not all roses, Buttercup (things to watch out for)

The environment I’ve outlined here makes for a low friction development process. That said, there are some limitations to this approach:

  1. Valid Sessions Only: By starting with the assumption that the token is valid and non-expired, we’re ignoring situations like unauthenticated users and refreshes for expired JWTs. Depending on your architecture, this could be completely valid, but often it’s not. At the very least, most UIs need to be able to redirect to a login page if necessary.
  2. Effecting the Token is Harder: If the feature you’re working on can potentially modify the user’s Auth state, generating tokens this way can get cumbersome. In those cases, it may make more sense to build a more robust mock service.

This isn’t really different from the way you want to approach SOA programming in general. Run the systems you need, and abstract/mock/fake everything else. The idea is to scale up what the organization can handle by scaling down what each individual member of the team needs to deal with.