How to convert standard json into prolog json?

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 the Jose implementation

>>> 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