Ah lol did not realize that was bidirectional. Thanks on both counts.
I feel like I’m close here but still not quite working. It’s not the prettiest thing in the world but here’s what I have so far
:- use_module(library(http/json)).
:- use_module(library(sha)).
jwt(encode,[Payload,Key,Headers,Algorithm]) :-
atom_json_term(Payload,_,[]),%syntax_check.
encoded_header(Algorithm,Headers,Enc_header),
encoded_payload(Payload,Enc_payload),
signed_output(Enc_header,Enc_payload,Algorithm,Key,Token),
writeln(Token).
encoded_header(Algorithm,Additional_headers,Enc_header) :-
( Additional_headers == null
-> Headers0 = [typ='JWT',alg=Algorithm]
; Headers = [typ='JWT',alg=Algorithm],
update(Headers,Additional_headers,Headers0) ),
sort(Headers0,Headers1),
atom_json_term(Headers_json,json(Headers1),[]),
base64url(Headers_json,Enc_header).
encoded_payload(Payload,Enc_payload) :-
base64url(Payload,Enc_payload).
signed_output(Enc_header,Enc_payload,Algorithm,Key,Token) :-
atomic_list_concat([Enc_header,Enc_payload],'.',Signing_input),
Algorithm = 'HS256',%temp.
sign(Key,Signing_input,Signature),
base64url(Signature,Signature64),
atomic_list_concat([Enc_header,Enc_payload,Signature64],'.',Token).
sign(Key,Signing_input,Signature) :-
hmac_sha(Key,Signing_input,Signature,[algorithm(sha256)]).
update(L,[],L).
update(L,[K=V|R],O) :-
select(K=_,L,K=V,L0),
update(L0,R,O), !.
update(L,[K=V|R],O) :-
append(L,[K=V],L0),
update(L0,R,O).
>>> from jose import jwt
>>> jwt.encode({'key': 'value'}, 'secret', algorithm='HS256')
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJ2YWx1ZSJ9.FG-8UppwHaFp1LgRYQQeS6EDQF7_6-bMFegNucHjmWg'
which is correct, validated on https://jwt.io/ .
My implementation
?- jwt(encode,['{"key":"value"}',secret,null,'HS256']).
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJ2YWx1ZSJ9.FG_CvFLCmnAdwqFpw5TCuBFhBB5LwqEDQF7Dv8Orw6bDjBXDqA3CucOBw6PCmWg=
So my headers and payload are correct but signature is wrong. I’m missing something in my signed_output/5
and/or sign/3
. Can somebody give me a hint?
As an aside - shouldn’t the !/0 be immediately after the select/3, to be logically correct when e.g. O
is nonvar?
1 Like