Skip to content

Commit 43680f7

Browse files
Robin de Rooijcanbican
authored andcommitted
jwt_io: parse header for key id
The key id should not be in the body, but in the header. This is also the default case for auth0.
1 parent 1c2e3a4 commit 43680f7

File tree

2 files changed

+51
-15
lines changed

2 files changed

+51
-15
lines changed

prolog/jwt_io.pl

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2727
*/
2828

29-
:- module(jwt_io, [jwt_encode/3, jwt_decode/3]).
29+
:- module(jwt_io, [jwt_encode/3, jwt_decode/3, jwt_decode_head/2]).
3030
/** <module> Json Web Tokens implementation
3131
3232
Generates and verifies Json Web Tokens.
@@ -44,7 +44,7 @@
4444
* =kid=: key id for identifying the key to use
4545
* =type=: type of the key, one of HMAC, RSA or ECDSA.
4646
* =algorithm=: algorithm to use, one of HS256, HS384, HS512, RS256, RS384, RS512, ES256, ES384 or ES512.
47-
* =key=: private key to use - string for HMAC, private key file for RSA and private PEM file for ECDSA.
47+
* =key=: private key to use - string for HMAC, private key file for RSA and private PEM file for ECDSA. Optional for decoding, mandatory for encoding.
4848
* =public_key=: public key to use - irrelevant for HMAC, public key file for RSA and public PEM file for ECDSA.
4949
5050
RSA keys can be generated by:
@@ -102,9 +102,9 @@
102102
claims_with_aud(Claims, ClaimsWithAud),
103103
claims_with_iat(ClaimsWithAud, ClaimsWithIat),
104104
claims_with_iss(ClaimsWithIat, Key, ClaimsWithIss),
105-
ClaimsNew = ClaimsWithIss.put(_{kid: Kid, jti: Jti}),
105+
ClaimsNew = ClaimsWithIss.put(_{jti: Jti}),
106106
atom_json_dict(Data,ClaimsNew,[as(atom)]),
107-
jwt_encode_from_string(Data, Token, Key.key, Key.algorithm).
107+
jwt_encode_from_string(Data, Token, Key.key, Key.algorithm, Kid).
108108

109109
%! jwt_decode(+Data: atom, -Payload:dict, +Options:options) is semidet
110110
%
@@ -126,18 +126,22 @@
126126
% @arg Options options
127127
%
128128
jwt_decode(Data, Payload, Options) :-
129-
jwt_decode_from_string(Data, PayloadFirst, _, ''),
130-
atom_json_dict(PayloadFirst, PayloadDict, [as(string)]),
131-
atom_string(Kid, PayloadDict.kid),
129+
jwt_decode_head(Data, PayloadFirst),
130+
atom_json_dict(PayloadFirst, PayloadHeader, [as(string)]),
131+
atom_string(Kid, PayloadHeader.kid),
132132
get_key_from_settings(Kid, KeyDict),
133133
jwt_decode_from_string(Data, Payload, KeyDict),
134+
atom_json_dict(Payload, PayloadDict, [as(string)]),
134135
jwt_jti_valid(PayloadDict),
135136
jwt_exp_valid(PayloadDict),
136137
jwt_nbf_valid(PayloadDict),
137138
jwt_iss_valid(PayloadDict, Options),
138139
jwt_aud_valid(PayloadDict, Options),
139140
jwt_iat_valid(PayloadDict).
140141

142+
jwt_decode_head(Data, Payload) :-
143+
jwt_parse_head(Data, Payload).
144+
141145
get_jti(Jti) :-
142146
setting(jti_generator, Generator),
143147
call(Generator, Jti).
@@ -203,6 +207,7 @@
203207

204208
jwt_decode_from_string(Data, Payload, Key) :-
205209
member(Key.type, ['RSA', 'ECDSA']),
210+
!,
206211
jwt_decode_from_string(Data, Payload, Key.algorithm, Key.public_key),
207212
!.
208213

@@ -268,12 +273,21 @@
268273
!.
269274
read_key_file(Key,KeyRead) :-
270275
member(Key.type, ['RSA', 'ECDSA']),
271-
read_file_to_string(Key.key, KeyStr, []),
276+
get_dict('key', Key, PrivateKeyFile),
277+
!,
278+
read_file_to_string(PrivateKeyFile, KeyStr, []),
272279
read_file_to_string(Key.public_key, PublicKeyStr, []),
273280
atom_string(KeyAtom, KeyStr),
274281
atom_string(PublicKeyAtom, PublicKeyStr),
275282
KeyRead = Key.put(_{key: KeyAtom, public_key: PublicKeyAtom}),
276283
!.
284+
read_key_file(Key, KeyRead) :-
285+
member(Key.type, ['RSA', 'ECDSA']),
286+
read_file_to_string(Key.public_key, PublicKeyStr, []),
287+
atom_string(PublicKeyAtom, PublicKeyStr),
288+
KeyRead = Key.put(_{public_key: PublicKeyAtom}),
289+
!.
290+
277291

278292
get_key_file(File, Key) :-
279293
read_file_to_string(File, KeyStr, []),

src/jwt_io.c

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,19 @@ get_pl_arg_str(char *predicate_name, char *term_name, term_t term, char **out)
1919
}
2020

2121
static foreign_t
22-
pl_jwt_encode(term_t in, term_t out, term_t key_term, term_t algorithm)
22+
pl_jwt_encode(term_t in, term_t out, term_t key_term, term_t algorithm, term_t key_id)
2323
{
2424
jwt_t *jwt;
25-
char *result, *grants, *alg_str, *key;
25+
char *result, *grants, *alg_str, *key, *kid;
2626
int rval;
2727

28-
get_pl_arg_str("jwt_encode_from_string/4", "in", in, &grants);
29-
get_pl_arg_str("jwt_encode_from_string/4", "key", key_term, &key);
30-
get_pl_arg_str("jwt_encode_from_string/4", "algorithm", algorithm, &alg_str);
28+
get_pl_arg_str("jwt_encode_from_string/5", "in", in, &grants);
29+
get_pl_arg_str("jwt_encode_from_string/5", "key", key_term, &key);
30+
get_pl_arg_str("jwt_encode_from_string/5", "kid", key_id, &kid);
31+
get_pl_arg_str("jwt_encode_from_string/5", "algorithm", algorithm, &alg_str);
3132
jwt_new(&jwt);
3233
jwt_add_grants_json(jwt, grants);
34+
jwt_add_header(jwt, "kid", kid);
3335
jwt_set_alg(jwt, jwt_str_alg(alg_str), (const unsigned char *)key, strlen(key));
3436
result = jwt_encode_str(jwt);
3537
rval = PL_unify_atom_chars(out, result);
@@ -38,6 +40,26 @@ pl_jwt_encode(term_t in, term_t out, term_t key_term, term_t algorithm)
3840
return rval;
3941
}
4042

43+
static foreign_t
44+
pl_jwt_parse_head(term_t in, term_t head_term) {
45+
char *input, *head_payload;
46+
jwt_t *jwt;
47+
int jwt_result;
48+
get_pl_arg_str("jwt_encode_from_string/4", "in", in, &input);
49+
50+
jwt_result = jwt_decode(&jwt, input, NULL, 0);
51+
if (!jwt_result) {
52+
head_payload = jwt_get_headers_json(jwt, NULL);
53+
(void) PL_unify_atom_chars(head_term, head_payload);
54+
free(head_payload);
55+
jwt_free(jwt);
56+
PL_succeed;
57+
}
58+
else {
59+
PL_fail;
60+
}
61+
}
62+
4163
static foreign_t
4264
pl_jwt_decode(term_t in, term_t out_payload, term_t out_algorithm, term_t in_key)
4365
{
@@ -62,14 +84,14 @@ pl_jwt_decode(term_t in, term_t out_payload, term_t out_algorithm, term_t in_key
6284
jwt_free(jwt);
6385
PL_succeed;
6486
} else {
65-
PL_warning("cannot decode jwt: %s", strerror(jwt_result));
6687
PL_fail;
6788
}
6889
}
6990

7091
install_t
7192
install(void)
7293
{
73-
PL_register_foreign("jwt_encode_from_string", 4, pl_jwt_encode, 0);
94+
PL_register_foreign("jwt_parse_head", 2, pl_jwt_parse_head, 0);
95+
PL_register_foreign("jwt_encode_from_string", 5, pl_jwt_encode, 0);
7496
PL_register_foreign("jwt_decode_from_string", 4, pl_jwt_decode, 0);
7597
}

0 commit comments

Comments
 (0)