jwt

jwt
Login

jwt

jwt - JSON Web Tokens


Synopsis

Sign and verify JSON Web Tokens in the JWS Compact Serialization, the header.payload.signature form that RFC 7519 and RFC 7515 define.

The package (package jwt) is pure Tcl and has two main commands. Create a token with ::jwt::sign, check one with ::jwt::verify:

package require jwt

set header  {{"alg":"HS256","typ":"JWT"}}
set payload {{"sub":"alice","exp":1893456000}}
set secret  0123456789abcdef0123456789abcdef

set token [::jwt::sign $header $payload $secret]

::jwt::verify $token $secret                      ;# signature only
::jwt::verify $token $secret -claims              ;# also exp and nbf
::jwt::verify $token $secret -claims -leeway 60   ;# with clock skew
::jwt::verify $token $secret -alg HS256           ;# restrict the algorithm

Without options ::jwt::verify returns a boolean and checks the signature only, which means an expired token verifies as true. The time claims exp and nbf are evaluated with -claims alone, -leeway adds a tolerance in seconds against clock skew and works together with -claims only.

-alg names the algorithms the caller accepts, for instance -alg HS256 or -alg {HS256 HS512}. A token whose header asks for anything else then fails, no matter what it claims. Without the option every implemented algorithm is accepted.

With -json the result is an rl_json document holding verify, header and payload, the latter two as raw re-parsable JSON text. Together with -claims it also carries reason, one of ok, malformed, alg, crit, signature, notbefore, expired or payload, so a forged token can be told apart from one that merely ran out of time:

set res [::jwt::verify $token $secret -claims -json]
rl_json::json get $res verify                     ;# 1 or 0
rl_json::json get $res reason                     ;# ok, expired, ...
set claims [rl_json::json get $res payload]
rl_json::json get $claims sub                     ;# alice

::jwt::base64url_encode and ::jwt::base64url_decode are public as well, because callers need base64url for salts, keys and binary blobs of their own.

For working code covering all of this, see the examples at this site.


Algorithms

The algorithm is taken from the alg field of the header, which RFC 7515 section 4.1.1 makes mandatory - there is no default.

alg MAC Tag Minimum key
HS256 HMAC-SHA-256 32 bytes 32 bytes
HS384 HMAC-SHA-384 48 bytes 48 bytes
HS512 HMAC-SHA-512 64 bytes 64 bytes
NaCl Poly1305 onetime authentication 16 bytes 32 bytes, fixed

The three HS* algorithms are RFC 7518 section 3.2 as written. The secret is used at whatever length it has, prepared as RFC 2104 section 2 requires, so a client secret goes in unchanged - no padding and no hashing beforehand, either would produce a different tag. The lower bound in the table is the one RFC 7518 section 3.2 sets, namely the size of the hash output.

NaCl is not a registered JWS algorithm and interoperates with this package only. It has a fixed 32 byte key, which is why a secret for it, and only for it, is NUL-padded or truncated.


Dependencies

Both are C extensions and are loaded lazily on the first sign or verify call, so sourcing the package costs nothing while it stays unused.


Conformance

Implemented as the specifications require, each covered by a regression test: the mandatory alg including the rejection of the unsecured none, the crit header, canonical base64url without padding, UTF-8 encoding of header and payload, both of them JSON objects, the minimum key size, and -alg so the caller decides which algorithms are acceptable.

One deviation is deliberate: validation of the time claims is opt-in. Without -claims an expired token verifies as true, which keeps the signature-only contract existing callers rely on.

Characters beyond the BMP, above U+FFFF, cannot be converted to UTF-8 by Tcl 8.6 - it substitutes U+FFFD and the character is lost. Tcl 9 encodes them correctly. Everything within the BMP, umlauts and CJK included, is identical on both.


Wiki Pages


See Also


Copyright (C) 2022-2026 Alexander Schoepe, Bochum, DE

Tcl package: BSD-3 license