From: Willy Tarreau Date: Tue, 22 Sep 2026 20:16:59 +0000 (+0000) Subject: BUG/MINOR: sample: return the decoded JWT part when no path is given X-Git-Tag: v3.5-dev8~78 X-Git-Url: https://git.kaiwu.me/?a=commitdiff_plain;h=3649a130ee650478448a4b057688f8a1a051aa52;p=haproxy.git BUG/MINOR: sample: return the decoded JWT part when no path is given jwt_header_query() and jwt_payload_query() are documented to return the decoded header or payload of the token when they are called without any argument. sample_conv_jwt_member_query() does fill the sample in that case, but it jumps to its exit label while still holds the zero it was initialized with, so the converter reports a failure and the expression yields nothing at all. Only the form taking a JSON path worked, which is the one the reg-test used, hence the bug going unnoticed. The test now reads both parts of the token without any argument as well. The issue arrived in 2.5 with the original commit 0a72f5ee7c ("MINOR: jwt: jwt_header_query and jwt_payload_query converters") so this fix can be backported to all stable branches. --- diff --git a/reg-tests/jwt/jws_verify.vtc b/reg-tests/jwt/jws_verify.vtc index 724c60c89..466109aa9 100644 --- a/reg-tests/jwt/jws_verify.vtc +++ b/reg-tests/jwt/jws_verify.vtc @@ -62,6 +62,15 @@ haproxy h1 -conf { http-response set-header x-jwt-token %[var(txn.bearer)] http-response set-header x-jwt-alg %[var(txn.jwt_alg)] + # both query converters return the decoded part they are named + # after when they are called without any argument, and perform a + # json_query on it otherwise + http-response set-header x-jwt-header %[var(txn.bearer),jwt_header_query] + http-response set-header x-jwt-payload %[var(txn.bearer),jwt_payload_query] + http-response set-header x-jwt-sub %[var(txn.bearer),jwt_payload_query('$.sub')] + http-response set-header x-jwt-iat %[var(txn.bearer),jwt_payload_query('$.iat',"int"),add(1)] + http-response set-header x-jwt-nokey %[var(txn.bearer),jwt_payload_query('$.nokey')] + http-response set-header x-jwt-verify-HS256 %[var(txn.bearer),jwt_verify(txn.jwt_alg,"hmac key hs256")] if { var(txn.jwt_alg) -m str "HS256" } http-response set-header x-jwt-verify-HS384 %[var(txn.bearer),jwt_verify(txn.jwt_alg,"hmac key hs384")] if { var(txn.jwt_alg) -m str "HS384" } http-response set-header x-jwt-verify-HS512 %[var(txn.bearer),jwt_verify(txn.jwt_alg,"hmac key hs512")] if { var(txn.jwt_alg) -m str "HS512" } @@ -165,6 +174,13 @@ client c1 -connect ${h1_mainfe_sock} { expect resp.status == 200 expect resp.http.x-jwt-alg == "HS256" expect resp.http.x-jwt-verify-HS256 == "1" + # the two parts of that token are {"alg":"HS256","typ":"JWT"} and + # {"sub":"1234567890","name":"John Doe","iat":1516239022} + expect resp.http.x-jwt-header ~ "\"alg\":\"HS256\"" + expect resp.http.x-jwt-payload ~ "\"name\":\"John Doe\"" + expect resp.http.x-jwt-sub == "1234567890" + expect resp.http.x-jwt-iat == "1516239023" + expect resp.http.x-jwt-nokey == "" } -run client c2 -connect ${h1_mainfe_sock} { diff --git a/src/sample.c b/src/sample.c index d110ff7b7..c34f143a8 100644 --- a/src/sample.c +++ b/src/sample.c @@ -5083,6 +5083,7 @@ static int sample_conv_jwt_member_query(const struct arg *args, struct sample *s if (args[0].type != ARGT_STR) { smp->data.u.str = *decoded_header; smp->data.type = SMP_T_STR; + retval = 1; goto end; }