(This is an English version of my article on my employer’s blog)
tl;dr; Yes, I know other libraries for JOSE in Go already exist. But for various reasons I created go-jwx. I believe it’s a pretty good library, and now I have a much much better understanding of the specification, so even if I have to go back to using other libraries, all is not lost.
How It Came To Be
I had been writing some code for an OpenID server using Go. First I read the specs. “JW- what?” You see, OAuth2/OpenID uses these things called JWT’s to transfer tokens amongst interested parties. These are signed using JWS’s, using JWK’s, using one of the algorithms described in JWA, and they can also be optionally encrypted using JWE’s. Enough JWx for you?
Well, at first I was lost in jargon, so I started digging around both documentation and code. Soon I had something working, but it just didn’t feel right: See, I was writing the server side which requires us to work with pretty much the whole specification, not just parts of it. Unfortunately, because most libraries only implment parts of the specification that they deem most importat (for a good reason, too. I just needed more), I ended up having to use multiple libraries for this application.
This lead to asymmetric code — it worked, but I could already tell the nightmare it would bring with it had it been released into production and there was a problem.
I thought hard about proposing changes to existing libraries, but in the end I came to the conclusion that what I wanted to do would require pretty big API changes, and nobody likes breaking existing user base’s code. At the same time I was feeling that my understanding of the specification was not up to par yet. Well, what better way to do this than to write it yourself?
So I wrote go-jwx:
The main problem I had with many of the existing libraries were that they only implemented parts of the specification. For example, github.com/golang/oauth2/jws is elegant in its simplicity, but being a client library, it can only create a limited set of JWS, and cannot verify signatures. github.com/square/go-jose was *almost* there, except I needed complete control over the contents of JWT tokens and other JWS/JWK headers.
- JWA (RFC 7518) : JSON Web Algorithms
- JWT (RFC 7519) : JSON Web Token
- JWK (RFC 7517) : JSON Web Key
- JWS (RFC 7515) : JSON Web Signature
- JWE (RFC 7516) : JSON Web Encryption
They are related but independent from each other. For example, JWS can sign arbitrary payload, not just JWT’s. But most Go libraries just dumped all of this in one package and made a general mess. This making it really hard for me to understand how the whole thing fit together.
With go-jwx, we have created packages for each of the above components and came up with a very neatly streamlined top-level API. Underneath that API, there are components that can be composed on top of each other so that you get maximum flexibility configuring according to you needs. Please see the README for examples.
The library is being used on an OpenID server (not published, sorry) which passes most of the OpenID Certification Tests.
So yes, this was your classical reinvention the wheel. As the author I have gotten to understand the specification in its entirety, so the whole effort has already paid off. I also believe the by-product, go-jwx, is a great library and I hope you consider it as an alternative.
If you are comfortable with your current choice of library, that’s totally fine, and you should not need to consider go-jwx. Buf if you are still shopping around for that JOSE library, I hope you consider using it and give us feedback so we can make it even better.
Enjoy! And let us know if there are any feedback!