JWT woes - crypto issues?

Igor Clark igor.clark@REDACTED
Fri Feb 5 20:40:00 CET 2021

Hi folks,

I'm trying to use the jwerl library (https://github.com/G-Corp/jwerl) to sign JWTs using the ES384 algorithm, which is required by the system for which I'm generating the token.

It seems to work fine internally; I sign something with my private key, verify the result straight back and it works:

> 30> Claims = #{ blah => <<"load of blah">>, exp => 1612639232 }.
> #{blah => <<"load of blah">>,exp => 1612639232}
> 31> jwerl:sign( Claims, es384, PrivateKey ).
> <<"eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9.eyJibGFoIjoibG9hZCBvZiBibGFoIiwiZXhwIjoxNjEyNjM5MjMyfQ.MGYCMQCSNwgjw_i4EVxhRxox"...>>
> 32> jwerl:verify( jwerl:sign( Claims, es384, PrivateKey ), es384, PublicKey ).
> {ok,#{blah => <<"load of blah">>,exp => 1612639232}}

However when the Python code at the other end tries to decode it, using the same public key, it says "Signature verification failed".

I try it the other way round, using the same private key to encode it on the Python side, and the same internal consistency check in the Python library works fine:

> >>> claims
> {'blah': 'load of blah', 'exp': 1612639232}
> >>> jwt.encode( claims, private_key, algorithm="ES384" )
> 'eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzM4NCJ9.eyJibGFoIjoibG9hZCBvZiBibGFoIiwiZXhwIjoxNjEyNjM5MjMyfQ.FxPVtSx0R8JjgYhoDYmuJKOyE7bY[...]f'
> >>> jwt.decode( jwt.encode( claims, private_key, algorithm="ES384" ), public_key, algorithms=["ES384"] )
> {'blah': 'load of blah', 'exp': 1612639232}

But when I copy the token from the Python output and try to decode it in Erlang/jwerl with the same public key:

> 38> jwerl:verify( PythonJwt, es384, PublicKey ).
> {error,invalid_signature}

So they both can encode and decode the JWT using ECDSASHA384 without problem, but when either of them tries to decode a JWT encoded by the other one, *using the same keys*, it fails.

The reason I'm posting this here rather than on a Python forum is that when I paste the Python-generated JWT into the debuggger at jwt.io, and paste in the public key, I get "Signature Verified". When I paste in the Erlang/jwerl-generated JWT into the same box, with the same key in there, I get "Invalid Signature".

It could obviously be a problem with the jwerl library, but it seems reasonably recently maintained, lots of downloads on hex.pm, etc, etc, and it seems at least internally consistent.

So I'm wondering if it's something to do with the underlying crypto or related packages, or their setup, in my Erlang/OTP? I'm running Erlang/OTP 23 [erts-11.1.7] on MacOS Catalina 10.15.7, and although jwerl compiles and runs, rebar3 shell shows a warning:

> _build/default/lib/jwerl/src/jwerl_hs.erl:7: Warning: crypto:hmac/3 is deprecated and will be removed in OTP 24; use use crypto:mac/4 instead

I've tried several other Erlang JWT libraries, which won't even seem to build because the compile fails with that same warning (I guess this is something to do with warnings as errors, maybe, but I don't know how to switch that off in rebar3) - I've even tried importing Elixir libs but I got nowhere quickly with that. The jwerl library seems to work and is apparently in decently wide use, so there must be something off about my setup or *something*, given that interoperability is pretty much the point of JWT, and this is falling at the first hurdle.

Anyone got any ideas? Would really appreciate a pointer on how to track down what's going wrong!


More information about the erlang-questions mailing list