Signing a JSON Web Token in Erlang

9 Feb 2023 16:52 erlang cryptography jwt

About 8 years ago, I wrote a post about verifying JSON Web Tokens (JWT) in Erlang. 3 years later, I wrote another post about signing a JWT in bash. This is a post combining the two: here’s how you sign a JWT using Erlang.

A JWT needs a header, which is base64url-encoded:

Header = base64url:encode(
    jsx:encode(
        #{<<"alg">> => <<"RS256">>,
          <<"typ">> => <<"JWT">>}
    )).

Then you need a payload with some claims; the list of required vs. optional claims depends on the particular implementation. I’ll use the initial list from the jwt.io debugger.

This is also base64url-encoded.

Payload = base64url:encode(
    jsx:encode(
        #{<<"sub">> => <<"1234567890">>,
          <<"name">> => <<"John Doe">>,
          <<"iat">> => 1516239022}
    )).

The iat (issued at) value is from 2018, in case you were wondering, per date --date=@1516239022.

We then combine the two:

Message = <<Header/binary, ".", Payload/binary>>.

The RS256 algorithm requires an RSA key, so we’ll need to generate one:

SigningKey = public_key:generate_key({rsa, 2048, 65537}).

And then we can sign the token, which needs to be base64url-encoded again:

Signature = base64url:encode(
    public_key:sign(Message, sha256, SigningKey)).

We append that to the header and payload, and we’ve got our final JSON Web Token:

JWT = <<Header/binary, ".", Payload/binary, ".", Signature/binary>>.