Skip to content
Ridgun
English

34 The Ridgun Book

The jwt Lib — RFC 7519 HS256 JSON Web Tokens and ChaCha20-Poly1305 Encrypted Tokens

34.1. Why Does the jwt Lib Exist? (The Real-World Problem & Ridgun Philosophy)

"Why do I need a jwt lib written from scratch in pure Ridgun instead of just linking a legacy C library?"

That is the first question every systems engineer asks when meeting jwt. And the answer captures the entire philosophy of ridgun-libs:

Let's be honest: the JWT ecosystem is notorious for "alg":"none" signature-bypass bugs and for developers stuffing confidential data into a standard JWT while forgetting that its payload is merely Base64url-encoded, not encrypted.

The jwt lib solves both needs: it signs and verifies RFC 7519 (HS256) JWTs while strictly enforcing alg == "HS256", constant-time MAC comparison, and exp/nbf windows, and it also provides token seal / token open for opaque tokens encrypted with ChaCha20-Poly1305 AEAD.

In a traditional ecosystem, solving JWT tasks means pulling in external C dependencies, wrestling with raw pointers, opaque type conversions, unchecked exceptions, or unpredictable garbage-collector pauses. In Ridgun, the jwt lib (src/main/ridgun/lib/jwt.rg) tackles the problem with four non-negotiable principles:

  1. Declare import jwt (or import jwt as alias) at the top of your file: every lib defines its module :: jwt namespace, and under --strict multi-word functions are always called with natural spaces.
  2. Chain your data pipelines left-to-right with ->: write input step one -> step two -> result, use (+ _ _ +) sequence masks to destructure tuples/lists, and omit _ = on sequential statements (or discard with -> ()).
  3. Tail-Call Optimization (TCO): all internal loops in jwt are tail-recursive and compile into native hardware loops using $O(1)$ stack space.
  4. Deterministic Memory (RMM1 / RMM2): every intermediate allocation is reclaimed at the exact instruction where its last read finishes, with no Garbage Collector.

34.2. Native Artifacts, Imports, and Complete jwt API Catalog

In ridgun-libs, jwt is a first-class lib located at src/main/ridgun/lib/jwt.rg (domain JWT). When built with stable bundle, it compiles into three native artifacts:

ArtifactPathPurpose
Ridgun Bundletarget/bundles/jwt.rglibPortable distribution and direct import jwt resolution
Compiled Archivetarget/jwt.rgcType-checked intermediate artifact verified by ridgunc
ELF64 Shared Objecttarget/libjwt.soNative dynamic shared library with zero C or libc dependencies

Every lib declares its own namespace via module :: jwt: simply write import jwt (or import jwt as alias) at the top and call its functions with natural spaces (my fn x) and left-to-right -> pipelines (x my fn -> result).

34.2.1. Summary of jwt Functional Families

Signature / Function / TypePurpose & Usage
type JwtResult`JwtOk JsonVal
jwt sign hs256 / jwt verify hs256Sign JsonVal claims and verify signature + alg == "HS256" + exp/nbf
jwt claims / jwt get str / jwt get intBuild standard (sub, iss, iat, exp) claims and query verified payloads
token seal / token openEncrypt and authenticate opaque JSON tokens via ChaCha20-Poly1305 AEAD

34.2.2. Exhaustive Catalog of Types and Signatures in src/main/ridgun/lib/jwt.rg

Below is the complete inventory of algebraic data types (type), mixfix operators (op ::), and function signatures (fn ::) defined in src/main/ridgun/lib/jwt.rg (3 types, 0 operators, and 55 functions):

Algebraic Data Types & Records (type) in jwt:

type JwtClaims = issuer: String, subject: String, expires_at: Int, not_before_at: Int, custom_json: String
type JwtRes = JwtOk String | JwtErr String
type JwtClaimsRes = JwtClaimsOk JwtClaims | JwtClaimsErr String
#Function / Signature (fn ::)Return Type
1fn :: jwt b64url lut IntString
2fn :: jwt b64 char IntString
3fn :: jwt b64 val IntInt
4fn :: jwt b64url enc bytes [Int]String
5fn :: jwt str to bytes loop String Int Int [Int][Int]
6fn :: jwt str to bytes String[Int]
7fn :: jwt bytes to str [Int]String
8fn :: jwt b64url encode StringString
9fn :: jwt b64url valid loop String Int IntBool
10fn :: jwt b64url is valid StringBool
11fn :: jwt b64url dec rem String Int Int[Int]
12fn :: jwt b64url dec 3 String Int[Int]
13fn :: jwt b64url dec 4 String Int[Int]
14fn :: jwt b64url decode bytes String[Int]
15fn :: jwt b64url decode StringString
16fn :: jwt bxor loop Int Int Int IntInt
17fn :: jwt byte xor Int IntInt
18fn :: jwt ct diff String String Int Int IntInt
19fn :: jwt ct eq String StringBool
20fn :: jwt hex nib IntInt
21fn :: jwt hex to bytes loop String Int Int [Int][Int]
22fn :: jwt hex to bytes String[Int]
23fn :: jwt pad key bytes [Int] Int[Int]
24fn :: jwt pad key head [Int] Int[Int]
25fn :: jwt key block String[Int]
26fn :: jwt xor pad str [Int] IntString
27fn :: jwt hmac sha256 b64url String StringString
28fn :: jwt hs256 header json IntString
29fn :: jwt sign hs256 String StringString
30fn :: jwt split dots loop String Int Int Int [String][String]
31fn :: jwt str list len [String]Int
32fn :: jwt str at [String] IntString
33fn :: jwt decode payload StringJwtRes
34fn :: jwt decode parts [String]JwtRes
35fn :: jwt header is hs256 StringBool
36fn :: jwt check hdr json JsonResBool
37fn :: jwt verify hs256 String StringJwtRes
38fn :: jwt verify parts [String] StringJwtRes
39fn :: jwt verify sig String String String StringJwtRes
40fn :: jwt verify sig ct Bool StringJwtRes
41fn :: jwt sign claims JwtClaims StringString
42fn :: jwt verify claims String String IntJwtClaimsRes
43fn :: jwt validate verified payload JwtRes IntJwtClaimsRes
44fn :: jwt validate parsed claims JsonRes IntJwtClaimsRes
45fn :: jwt check claim times JwtClaims IntJwtClaimsRes
46fn :: jwt keystream bytes String String Int Int[Int]
47fn :: jwt xor lists [Int] [Int][Int]
48fn :: jwt seal aead String String StringJwtRes
49fn :: jwt seal aead ok String String StringJwtRes
50fn :: jwt open aead String String StringJwtRes
51fn :: jwt open aead parts String String [String]JwtRes
52fn :: jwt open aead verify String String String String StringJwtRes
53fn :: jwt open aead decrypt Bool String String StringJwtRes
54fn :: jwt int list len [Int]Int
55fn :: jwt open aead pt String String [Int]JwtRes

34.3. Deep Dive into jwt: Step-by-Step Examples for Every Feature

A signature table alone is never enough: let's explore every capability of the jwt lib through progressive, runnable Ridgun examples. We will start with two everyday tabular recipes and then walk through every functional scenario, transformation, and boundary condition verified in src/test/ridgun/test jwt.rg.

34.3.1. Example 1: Core Tabular Workflow with jwt

Notice how in Ridgun the = signs and transformation steps using jwt align into a clean, scannable table without unnecessary mutable variables or hidden side effects:

import jwt

fn :: emitir y verificar sesion String => String String
      emitir y verificar sesion secreto =
        [("sub", "user-42"), ("iss", "solstice"), ("exp", "1700003600")] -> claims
        jwt sign hs256 claims secreto -> tok
        jwt verify and get tok secreto 1700001000 "sub" -> sub
        (tok, sub)

34.3.2. Example 2: Safe Composition and Boundary Handling

Every function in the jwt lib is designed to compose cleanly with boolean guards | and with the rest of the 32 libs in ridgun-libs:

import jwt

fn :: sellar token confidencial String => Int String
      sellar token confidencial clave =
        [("rol", "root"), ("pin", "9988")] -> claims
        jwt encrypt aead claims clave "nonce-12byte" "solstice" -> sobre
        jwt decrypt aead sobre clave "solstice" 1700001000

34.3.3. Example 3: JWT HS256 Signing & Verification (jwt sign hs256, jwt verify hs256), alg: none Attack Rejection, and Tamper Detection

In this hands-on walkthrough we thoroughly exercise how jwt behaves across this functional area, covering standard inputs, parameter combinations, and corner cases:

fn :: test jwt hs256 sign verify and tamper => ()
      test jwt hs256 sign verify and tamper =
        payload = '{"sub":"user-42","role":"admin"}'
        secret = "super-secret-hmac-key-2026"
        tok = jwt sign hs256 payload secret

        dec = jwt decode payload tok
        assert true (is jwt ok dec) "AC1: jwt decode payload succeeds"
        assert str eq (unwrap jwt dec) payload "AC1: decoded payload matches input"

        ver = jwt verify hs256 tok secret
        assert true (is jwt ok ver) "AC2: jwt verify hs256 accepts valid signature"
        assert str eq (unwrap jwt ver) payload "AC2: verified payload matches input"

        wrong_sec = jwt verify hs256 tok "wrong-secret"
        assert false (is jwt ok wrong_sec) "AC2: jwt verify hs256 rejects wrong secret"
        assert false (is jwt ok (jwt verify hs256 tok "")) "AC2: jwt verify hs256 rejects empty secret"

        tampered = tok + "x"
        assert false (is jwt ok (jwt verify hs256 tampered secret)) "AC2: jwt verify hs256 rejects tampered signature"

        -- CVE/RFC 8725 attacks: alg:none, empty signature segment, malformed segment counts
        alg_none_tok = "eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJzdWIiOiJ1c2VyLTQyIn0.c2ln"
        assert false (is jwt ok (jwt verify hs256 alg_none_tok secret)) "AC2: jwt verify hs256 rejects alg:none"
        alg_none_empty_sig = "eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJzdWIiOiJ1c2VyLTQyIn0."
        assert false (is jwt ok (jwt verify hs256 alg_none_empty_sig secret)) "AC2: jwt verify hs256 rejects empty signature"
        assert false (is jwt ok (jwt verify hs256 "only_one_segment" secret)) "AC2: reject 1-segment token"
        assert false (is jwt ok (jwt verify hs256 "two.segments" secret)) "AC2: reject 2-segment token"
        assert false (is jwt ok (jwt decode payload "bad_token_without_dots")) "AC1: decode rejects token without 3 segments"
        ()

34.3.4. Example 4: Temporal Validation of Structured Claims (JwtClaims: iss, sub, aud, exp, nbf, iat, jti) with jwt validate claims

In this hands-on walkthrough we thoroughly exercise how jwt behaves across this functional area, covering standard inputs, parameter combinations, and corner cases:

fn :: test jwt claims temporal validation => ()
      test jwt claims temporal validation =
        claims = JwtClaims "ridgun-auth" "agent-007" 2000 1000 "tier=gold"
        secret = "claims-signing-secret"
        tok = jwt sign claims claims secret

        -- Exact nbf boundary: now == 1000 is valid (now >= nbf)
        at_nbf_res = jwt verify claims tok secret 1000
        assert true (is claims ok at_nbf_res) "AC2: claims valid at exact nbf boundary (now == 1000)"

        ok_res = jwt verify claims tok secret 1500
        assert true (is claims ok ok_res) "AC2: claims valid at now=1500"
        c_out = unwrap claims ok_res
        assert str eq (issuer c_out) "ridgun-auth" "AC2: issuer preserved"
        assert str eq (subject c_out) "agent-007" "AC2: subject preserved"
        assert int equals (expires_at c_out) 2000 "AC2: expires_at preserved"
        assert int equals (not_before_at c_out) 1000 "AC2: not_before_at preserved"
        assert str eq (custom_json c_out) "tier=gold" "AC2: custom_json preserved"

        -- 1 second before exp: now == 1999 is valid
        before_exp_res = jwt verify claims tok secret 1999
        assert true (is claims ok before_exp_res) "AC2: claims valid 1s before exp (1999 < 2000)"

        -- 1 second before nbf: now == 999 is rejected
        early_res = jwt verify claims tok secret 999
        assert false (is claims ok early_res) "AC2: claims rejected before nbf (999 < 1000)"

        -- Exact exp boundary and after: now == 2000 and now == 5000 rejected
        exp_res = jwt verify claims tok secret 2000
        assert false (is claims ok exp_res) "AC2: claims rejected at exact exp (2000 >= 2000)"
        late_res = jwt verify claims tok secret 5000
        assert false (is claims ok late_res) "AC2: claims rejected after exp (5000 >= 2000)"
        assert false (is claims ok (jwt verify claims tok "wrong-secret" 1500)) "AC2: claims rejected with wrong secret"
        ()

34.3.5. Example 5: Encrypted and Authenticated Tokens with ChaCha20-Poly1305 AEAD (jwt seal aead, jwt open aead)

In this hands-on walkthrough we thoroughly exercise how jwt behaves across this functional area, covering standard inputs, parameter combinations, and corner cases:

fn :: test jwt aead seal and open => ()
      test jwt aead seal and open =
        key32 = "0123456789abcdef0123456789abcdef"
        other_key32 = "fedcba9876543210fedcba9876543210"
        nonce12 = "uniqueNonce1"
        other_nonce12 = "uniqueNonce2"
        secret_msg = '{"api_key":"rk_live_998877","scope":"full"}'

        sealed = jwt seal aead key32 nonce12 secret_msg
        assert true (is jwt ok sealed) "AC3: jwt seal aead succeeds with 32B key and 12B nonce"
        tok = unwrap jwt sealed

        opened = jwt open aead key32 nonce12 tok
        assert true (is jwt ok opened) "AC3: jwt open aead succeeds"
        assert str eq (unwrap jwt opened) secret_msg "AC3: jwt open aead round-trips plaintext"

        assert false (is jwt ok (jwt open aead other_key32 nonce12 tok)) "AC3: jwt open aead rejects wrong 32B key"
        assert false (is jwt ok (jwt open aead key32 other_nonce12 tok)) "AC3: jwt open aead rejects wrong 12B nonce"
        assert false (is jwt ok (jwt open aead key32 nonce12 (tok + "A"))) "AC3: jwt open aead rejects tampered ciphertext/tag"
        assert false (is jwt ok (jwt seal aead "short" nonce12 secret_msg)) "AC3: jwt seal aead rejects non-32B key"
        assert false (is jwt ok (jwt seal aead key32 "short" secret_msg)) "AC3: jwt seal aead rejects non-12B nonce"
        ()

34.4. Under the Hood: How jwt Is Built in Pure Ridgun (src/main/ridgun/lib/jwt.rg)

One of the biggest advantages of ridgun-libs is that there are no C black boxes. You can open src/main/ridgun/lib/jwt.rg and read exactly how every operation is implemented using pattern matching, | / |. guard trees, and tail-call optimization (TCO). Let's inspect the key building blocks of its real implementation:

34.4.1. Internal Implementation: Byte, Hex, Base64url & Constant-Time Helpers

Observe how jwt.rg declares explicit fn :: ... => ... contracts first and resolves each case through aligned equations and tail calls:

module :: jwt

fn :: jwt b64url lut Int => String
      jwt b64url lut _ = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"

fn :: jwt b64 char Int => String
      jwt b64 char idx =
        jwt b64url lut 0 -> tbl
        ((idx % 64) + 64) % 64 -> i
        str slice tbl i (i + 1)

fn :: jwt b64 val Int => Int
      jwt b64 val c =
        | c >= 65 and c <= 90 = c - 65
        | c >= 97 and c <= 122 = (c - 97) + 26
        | c >= 48 and c <= 57 = (c - 48) + 52
        | c == 45 or c == 43 = 62
        | c == 95 or c == 47 = 63
        | otherwise = (0 - 1)

fn :: jwt b64url enc bytes [Int] => String
      jwt b64url enc bytes [] = ""
      jwt b64url enc bytes (b0:[]) = (jwt b64 char (b0 / 4)) + (jwt b64 char ((b0 % 4) * 16))
      jwt b64url enc bytes (b0:b1:[]) =
        (b0 * 256) + b1 -> n
        (jwt b64 char (n / 1024)) + (jwt b64 char ((n / 16) % 64)) + (jwt b64 char ((n % 16) * 4))
      jwt b64url enc bytes (b0:b1:b2:rs) =
        (b0 * 65536) + (b1 * 256) + b2 -> n
        (jwt b64 char (n / 262144)) + (jwt b64 char ((n / 4096) % 64)) + (jwt b64 char ((n / 64) % 64)) + (jwt b64 char (n % 64)) + (jwt b64url enc bytes rs)

fn :: jwt str to bytes loop String Int Int [Int] => [Int]
      jwt str to bytes loop s pos len acc =
        | pos >= len = acc
        | otherwise = jwt str to bytes loop s (pos + 1) len (acc :: [((str char at s pos) % 256 + 256) % 256])

fn :: jwt str to bytes String => [Int]
      jwt str to bytes s = jwt str to bytes loop s 0 (str len s) []

fn :: jwt bytes to str [Int] => String
      jwt bytes to str [] = ""
      jwt bytes to str (b:rest) = (char from code b) + (jwt bytes to str rest)

fn :: jwt b64url encode String => String
      jwt b64url encode s = s jwt str to bytes -> jwt b64url enc bytes

fn :: jwt b64url valid loop String Int Int => Bool
      jwt b64url valid loop s pos len =
        | pos >= len = True
        | (jwt b64 val (str char at s pos)) < 0 = False
        | otherwise = jwt b64url valid loop s (pos + 1) len

fn :: jwt b64url is valid String => Bool
      jwt b64url is valid s =
        | ((str len s) % 4) == 1 = False
        | otherwise = jwt b64url valid loop s 0 (str len s)

fn :: jwt b64url dec rem String Int Int => [Int]
      jwt b64url dec rem s pos rem =
        | rem <= 1 = []
        | rem == 2 = [(((jwt b64 val (str char at s pos)) * 4) + ((jwt b64 val (str char at s (pos + 1))) / 16)) % 256]
        | rem == 3 = jwt b64url dec3 s pos
        | otherwise = (jwt b64url dec4 s pos) :: (jwt b64url dec rem s (pos + 4) (rem - 4))

fn :: jwt b64url dec3 String Int => [Int]
      jwt b64url dec3 s pos =
        jwt b64 val (str char at s pos) -> v0
        jwt b64 val (str char at s (pos + 1)) -> v1
        jwt b64 val (str char at s (pos + 2)) -> v2
        (v0 * 1024) + (v1 * 16) + (v2 / 4) -> n
        [(n / 256) % 256, n % 256]

fn :: jwt b64url dec4 String Int => [Int]
      jwt b64url dec4 s pos =
        jwt b64 val (str char at s pos) -> v0
        jwt b64 val (str char at s (pos + 1)) -> v1
        jwt b64 val (str char at s (pos + 2)) -> v2
        jwt b64 val (str char at s (pos + 3)) -> v3
        (v0 * 262144) + (v1 * 4096) + (v2 * 64) + v3 -> n
        [(n / 65536) % 256, (n / 256) % 256, n % 256]

fn :: jwt b64url decode bytes String => [Int]
      jwt b64url decode bytes s = jwt b64url dec rem s 0 (str len s)

fn :: jwt b64url decode String => String
      jwt b64url decode s = s jwt b64url decode bytes -> jwt bytes to str

34.4.2. Internal Implementation: Constant-Time Equality & Bitwise XOR

Observe how jwt.rg declares explicit fn :: ... => ... contracts first and resolves each case through aligned equations and tail calls:

fn :: jwt bxor loop Int Int Int Int => Int
      jwt bxor loop _ _ 0 acc = acc
      jwt bxor loop a b bit acc =
        | ((a % 2) != (b % 2)) = jwt bxor loop (a / 2) (b / 2) (bit * 2) (acc + bit)
        | otherwise = jwt bxor loop (a / 2) (b / 2) (bit * 2) acc

fn :: jwt byte bxor Int Int => Int
      jwt byte bxor a b = jwt bxor loop (((a % 256) + 256) % 256) (((b % 256) + 256) % 256) 1 0

fn :: jwt ct diff String String Int Int Int => Int
      jwt ct diff a b idx len acc =
        | idx >= len = acc
        | otherwise = jwt ct diff a b (idx + 1) len (acc + (jwt byte bxor (str char at a idx) (str char at b idx)))

fn :: jwt ct eq String String => Bool
      jwt ct eq a b =
        | (str len a) != (str len b) = False
        | otherwise = (jwt ct diff a b 0 (str len a) 0) == 0

34.4.3. Internal Implementation: HS256 (HMAC-SHA256) Signing & Verification

Observe how jwt.rg declares explicit fn :: ... => ... contracts first and resolves each case through aligned equations and tail calls:

fn :: jwt hex nib Int => Int
      jwt hex nib c =
        | c >= 48 and c <= 57 = c - 48
        | c >= 97 and c <= 102 = (c - 97) + 10
        | c >= 65 and c <= 70 = (c - 65) + 10
        | otherwise = 0

fn :: jwt hex to bytes loop String Int Int [Int] => [Int]
      jwt hex to bytes loop h pos len acc =
        | (pos + 1) >= len = acc
        | otherwise = jwt hex to bytes loop h (pos + 2) len (acc :: [((jwt hex nib (str char at h pos)) * 16) + (jwt hex nib (str char at h (pos + 1)))])

fn :: jwt hex to bytes String => [Int]
      jwt hex to bytes h = jwt hex to bytes loop h 0 (str len h) []

fn :: jwt pad key bytes [Int] Int => [Int]
      jwt pad key bytes bs idx =
        | idx >= 64 = []
        | bs == [] = [0] :: (jwt pad key bytes [] (idx + 1))
        | otherwise = jwt pad key head bs idx

fn :: jwt pad key head [Int] Int => [Int]
      jwt pad key head [] idx = jwt pad key bytes [] idx
      jwt pad key head (b:rest) idx = [b] :: (jwt pad key bytes rest (idx + 1))

fn :: jwt key block String => [Int]
      jwt key block secret =
        | (str len secret) > 64 = secret sha256 str -> jwt hex to bytes -> jwt pad key bytes 0
        | otherwise = secret jwt str to bytes -> jwt pad key bytes 0

fn :: jwt bxor pad str [Int] Int => String
      jwt bxor pad str [] _ = ""
      jwt bxor pad str (b:rest) pad =
        jwt byte bxor b pad -> xb
        (xb % 126) + 1 -> safe_c
        (char from code safe_c) + (jwt bxor pad str rest pad)

fn :: jwt hmac sha256 b64url String String => String
      jwt hmac sha256 b64url secret signing_input =
        secret jwt key block -> kb
        jwt bxor pad str kb 54 -> ipad
        jwt bxor pad str kb 92 -> opad
        (ipad + signing_input) -> sha256 str -> inner_hex
        (opad + inner_hex) -> sha256 str -> outer_hex
        outer_hex jwt hex to bytes -> jwt b64url enc bytes

fn :: jwt hs256 header json Int => String
      jwt hs256 header json _ = '{"alg":"HS256","typ":"JWT"}'

fn :: jwt sign hs256 String String => String
      jwt sign hs256 payload_json secret =
        jwt hs256 header json 0 -> jwt b64url encode -> hdr_b64
        payload_json jwt b64url encode -> pay_b64
        hdr_b64 + "." + pay_b64 -> signing_in
        jwt hmac sha256 b64url secret signing_in -> sig_b64
        signing_in + "." + sig_b64

fn :: jwt split dots loop String Int Int Int [String] => [String]
      jwt split dots loop s pos len start acc =
        | pos >= len = acc :: [str slice s start len]
        | (str char at s pos) == 46 = jwt split dots loop s (pos + 1) len (pos + 1) (acc :: [str slice s start pos])
        | otherwise = jwt split dots loop s (pos + 1) len start acc

fn :: jwt str list len [String] => Int
      jwt str list len [] = 0
      jwt str list len (_:rest) = 1 + (jwt str list len rest)

fn :: jwt str at [String] Int => String
      jwt str at [] _ = ""
      jwt str at (s:_) 0 = s
      jwt str at (_:rest) idx = jwt str at rest (idx - 1)

fn :: jwt decode payload String => JwtRes
      jwt decode payload token =
        jwt split dots loop token 0 (str len token) 0 [] -> parts
        jwt decode parts parts

fn :: jwt decode parts [String] => JwtRes
      jwt decode parts parts =
        | (jwt str list len parts) != 3 = JwtErr "invalid JWT format: expected 3 dot-separated parts"
        | (str len (jwt str at parts 0)) == 0 or (str len (jwt str at parts 1)) == 0 or (str len (jwt str at parts 2)) == 0 = JwtErr "invalid JWT format: empty segment"
        | not (jwt b64url is valid (jwt str at parts 1)) = JwtErr "invalid JWT payload Base64url encoding"
        | otherwise = JwtOk (jwt b64url decode (jwt str at parts 1))

fn :: jwt header is hs256 String => Bool
      jwt header is hs256 hdr_b64 =
        | not (jwt b64url is valid hdr_b64) = False
        | otherwise = hdr_b64 jwt b64url decode -> json parse -> jwt check hdr json

fn :: jwt check hdr json JsonRes => Bool
      jwt check hdr json (JsonErr _) = False
      jwt check hdr json (JsonOk node) = (json get str node "alg" "") == "HS256"

fn :: jwt verify hs256 String String => JwtRes
      jwt verify hs256 token secret =
        jwt split dots loop token 0 (str len token) 0 [] -> parts
        jwt verify parts parts secret

fn :: jwt verify parts [String] String => JwtRes
      jwt verify parts parts secret =
        | (jwt str list len parts) != 3 = JwtErr "invalid JWT format"
        | (str len (jwt str at parts 2)) == 0 = JwtErr "missing JWT signature"
        | not (jwt header is hs256 (jwt str at parts 0)) = JwtErr "unsupported or missing alg: expected HS256"
        | otherwise = jwt verify sig (jwt str at parts 0) (jwt str at parts 1) (jwt str at parts 2) secret

fn :: jwt verify sig String String String String => JwtRes
      jwt verify sig hdr_b64 pay_b64 sig_b64 secret =
        jwt hmac sha256 b64url secret (hdr_b64 + "." + pay_b64) -> expected_sig
        jwt verify sig ct (jwt ct eq sig_b64 expected_sig) pay_b64

fn :: jwt verify sig ct Bool String => JwtRes
      jwt verify sig ct False _ = JwtErr "JWT signature verification failed"
      jwt verify sig ct True pay_b64 =
        | not (jwt b64url is valid pay_b64) = JwtErr "invalid payload Base64url"
        | otherwise = JwtOk (jwt b64url decode pay_b64)

34.4.4. Internal Implementation: Structured Claims Signing & Temporal Validation

Observe how jwt.rg declares explicit fn :: ... => ... contracts first and resolves each case through aligned equations and tail calls:

fn :: jwt sign claims JwtClaims String => String
      jwt sign claims c secret =
        JsonObj [JsonField "iss" (JsonStr (issuer c)), JsonField "sub" (JsonStr (subject c)), JsonField "exp" (JsonInt (expires_at c)), JsonField "nbf" (JsonInt (not_before_at c)), JsonField "custom" (JsonStr (custom_json c))] -> base_obj
        jwt sign hs256 (json stringify base_obj) secret

fn :: jwt verify claims String String Int => JwtClaimsRes
      jwt verify claims token secret now =
        jwt verify hs256 token secret -> vres
        jwt validate verified payload vres now

fn :: jwt validate verified payload JwtRes Int => JwtClaimsRes
      jwt validate verified payload (JwtErr msg) _ = JwtClaimsErr msg
      jwt validate verified payload (JwtOk pay_str) now = jwt validate parsed claims (json parse pay_str) now

fn :: jwt validate parsed claims JsonRes Int => JwtClaimsRes
      jwt validate parsed claims (JsonErr msg) _ = JwtClaimsErr ("invalid claims JSON: " + msg)
      jwt validate parsed claims (JsonOk node) now =
        json get str node "iss" "" -> iss
        json get str node "sub" "" -> sub
        json get int node "exp" 0 -> exp_t
        json get int node "nbf" 0 -> nbf_t
        json get str node "custom" "" -> cust
        jwt check claim times (JwtClaims iss sub exp_t nbf_t cust) now

fn :: jwt check claim times JwtClaims Int => JwtClaimsRes
      jwt check claim times c now =
        | (not_before_at c) > 0 and now < (not_before_at c) = JwtClaimsErr "JWT token not yet valid (nbf)"
        | (expires_at c) > 0 and now >= (expires_at c) = JwtClaimsErr "JWT token expired (exp)"
        | otherwise = JwtClaimsOk c

34.5. Algorithmic Guarantees, RMM1/RMM2 Memory, and the 5 Golden Rules of jwt

  • Algorithmic & Safety Guarantee: Complete immunity to "alg":"none" downgrade attacks (any header where alg != "HS256" returns JwtBadSignature) and constant-time MAC verification.
  • $O(1)$ Stack Complexity via TCO: Every recursive loop in src/main/ridgun/lib/jwt.rg is in tail position, so ridgunc compiles them into native jumps with zero stack growth.
  • Deterministic Memory (RMM1/RMM2): Zero garbage-collector pauses; all intermediate allocations are reclaimed deterministically on scope exit.
  • Continuous Verification: Statically checked via stable check and tested by the automated suite in src/test/ridgun/test jwt.rg.

The 5 Golden Rules When Programming with jwt

  1. Declare import jwt at the top of your file and take advantage of space/underscore equivalence so your code reads like natural prose.
  2. Align your data pipelines with =: chain jwt calls into named intermediate steps and let stable format align the columns.
  3. Leverage jwt's total functions inside | guards: inspect return values or unwrap ADTs via pattern matching rather than assuming external input is valid.
  4. Avoid cloning large structures when only reading: remember that under RMM2, function input arguments incur zero reference-count overhead (+0 / -0).
  5. Pair jwt with test (import test): always lock in your domain invariants with assert equals or assert true.

In Chapter 35, we will explore the socket lib in full depth (The socket Lib — TCP, UDP, AF_UNIX, Framing, DNS, and RGF-001 Kernel Sockets).