Over the past month or so I’ve been using my free time for a very silly project: writing the same web server in C, Zig, C++, and Rust. While working on the Zig version I found myself wanting a JWT library, but none quite fit the experience I wanted. After sitting down to read the spec, I decided to roll my own. It only took a day and a half, and what came out was jwt.zig.
Source: GitHub - BrainBlasted/jwt.zig
Docs: Zig Documentation
The result, in my opinion, is a very easy-to-use and well-documented API. Encoding and decoding both have thorough usage examples, and there are additional unit tests for both the public facing API and the compile-time checks. It supports arbitrary claims structs while also providing type correctness and validation for standard claims. This in turn makes it incredibly flexible. A developer’s claims struct can look like this:
const Claims = struct {
// non-standard claim
name: []const u8,
};
or:
const Claims = struct {
iat: i64,
nbf: i64,
};
But compile-time checks will prevent a mistake like this:
const Claims = struct {
iat: []const u8,
};
The type checking happens as soon as you pass a type to the encoding or decoding functions, and if you provide an incorrect type you’ll get a decriptive compiler error.
Would be interested in some code review and general opinions on the API. Other JWT implementations seem to hard-code the claims struct or make providing arbitrary claims harder. I’m not sure if this usage of compile-time reflection is a bad pattern, or if I’m just the first to do it for a jwt library.
Some potential improvements:
- Supporting more signing algorithms
- More test coverage
- Support checking the
aud
claim as describe in the RFC: RFC 7519: JSON Web Token (JWT)