From 80d6cd31cdf12f37831f5da1895d93f25ebb79da Mon Sep 17 00:00:00 2001 From: Juri Leino Date: Mon, 12 Jan 2026 20:47:09 +0100 Subject: [PATCH 1/3] fix: signatures are now verifiable The return of crypto:hmac#4 cannot be passed to util:base64-encode-url-safe() as that will double-encode the base64 encoded value. A simple translate operation will turn the base64 encoded value into a url-safe one that is suitable for use here. As a result JWTs are now externally verifiable by other tools as jwt.io's token debugger. --- src/content/jwt.xqm | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/content/jwt.xqm b/src/content/jwt.xqm index 83e0bd3..765d929 100644 --- a/src/content/jwt.xqm +++ b/src/content/jwt.xqm @@ -84,8 +84,13 @@ declare function jwt:read ($token as xs:string, $secret as xs:string, $lifetime }; declare function jwt:sign ($data as xs:string, $secret as xs:string) as xs:string { + (: + : This is a band-aid for the output of crypto:hmac being cast to a base64 encoded xs:string + : which uses + and / characters. Since util:base64-encode-url-safe cannot operate on binary data, + : we do a manual replacement here. + :) crypto:hmac($data, $secret, "HMAC-SHA-256", "base64") - => util:base64-encode-url-safe() + => translate("+/=", "-_") }; (:~ From 56392ca09242dc0db0818470609b66459fa884a0 Mon Sep 17 00:00:00 2001 From: Juri Leino Date: Mon, 12 Jan 2026 21:05:18 +0100 Subject: [PATCH 2/3] ci: adapt test-matrix Since exist@latest cannot pass until the crypto lib is available I marked it as experimental. --- .github/workflows/semantic-release.yml | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/.github/workflows/semantic-release.yml b/.github/workflows/semantic-release.yml index 2b1fd47..4ff69c2 100644 --- a/.github/workflows/semantic-release.yml +++ b/.github/workflows/semantic-release.yml @@ -8,9 +8,16 @@ on: [push, pull_request] jobs: build: runs-on: ubuntu-latest + continue-on-error: ${{ matrix.experimental }} strategy: - matrix: - exist-version: [release, latest] + fail-fast: true + matrix: + exist-version: [release, 6.0.1] + experimental: [false] + # latest might contain breaking changes + include: + - exist-version: latest + experimental: true services: # Label used to access the service container exist: From e11447edc087dd3778af9818d8f2904fc338ad8e Mon Sep 17 00:00:00 2001 From: Juri Leino Date: Mon, 12 Jan 2026 23:05:21 +0100 Subject: [PATCH 3/3] chore: do not indent payloads The spec does not care but why have extra bytes in memory as this is never read by users directly. --- src/content/jwt.xqm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/jwt.xqm b/src/content/jwt.xqm index 765d929..b2c840c 100644 --- a/src/content/jwt.xqm +++ b/src/content/jwt.xqm @@ -121,7 +121,7 @@ declare function jwt:epoch-to-dateTime($ts as xs:integer) as xs:dateTime { declare function jwt:encode ($data as item()) as xs:string { util:base64-encode-url-safe( - serialize($data, map { "method": "json" })) + serialize($data, map { "method": "json", "indent": false() })) }; declare