JSON Web Tokens (JWT)

RPA flows constantly need to mint or verify bearer tokens for the APIs they drive, but the framework only had HMAC file signing (action_signing) and an ACME-bound RS256 JWS (acme_v2) — neither produces or validates a compact bearer JWT. This adds a focused, pure-stdlib JWT codec for the HMAC family with full claim validation, designed to feed straight into http_request’s bearer auth.

Pure standard library (hmac + hashlib + base64 + json); the clock is injectable so exp / nbf checks are deterministic. Imports no PySide6.

Security

The decoder is safe by default:

  • it rejects ``alg: “none”`` and any algorithm the caller did not explicitly allow-list, defeating the classic algorithm-confusion / downgrade attack;

  • it compares signatures with hmac.compare_digest (constant time);

  • RSA/EC algorithms (RS256/ES256) are intentionally out of scope — they require a third-party crypto library.

Headless API

from je_auto_control import encode_jwt, decode_jwt, ClaimsPolicy

token = encode_jwt({"sub": "user1", "aud": "api", "exp": 1893456000}, secret)
# -> "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...."

# default policy: HS256 only, verify exp/nbf, no audience/issuer check
claims = decode_jwt(token, secret)

# tighten the policy for audience / issuer / leeway / algorithms
policy = ClaimsPolicy(algorithms=("HS256",), audience="api",
                      issuer="my-service", leeway=30)
claims = decode_jwt(token, secret, policy)

encode_jwt signs a compact header.payload.signature token with HS256 / HS384 / HS512. decode_jwt verifies the signature, then validates the standard claims against a ClaimsPolicy (exp / nbf with leeway, aud membership, iss match) using an injectable now; it raises ExpiredTokenError / InvalidSignatureError / JwtError on failure. The minted token drops straight into the HTTP client:

from je_auto_control import http_request
http_request("https://api.example.com/me",
             auth={"type": "bearer", "token": token})

Executor commands

AC_jwt_encode takes claims (a dict or JSON string), key and an optional alg; it returns {token}. AC_jwt_decode takes token, key and optional algorithms / audience / leeway; it returns {ok, claims} (or {ok: false, error} so a flow can branch without raising). Both are exposed as the MCP tools ac_jwt_encode / ac_jwt_decode and as Script Builder commands under Security.