jwt
stableCreate and verify HMAC-signed JSON Web Tokens (HS256, HS384, HS512) and inspect their claims.
use plugin jwt Plugin snippets can be edited in the Playground, but native capabilities are executed locally with the Zolo CLI.
Functions (7)
- encode Sign a JSON payload and return a JWT string
- verify Check the HMAC signature, independently of expiration
- decode_parts Inspect the header, payload, and encoded signature
- decode_header Inspect the header's algorithm and token type
- decode_payload Read the payload JSON without verifying it
- get_claim Read a claim as text, or nil if it is absent
- is_expired Compare the expiration claim with a Unix timestamp
From import to result
- 01Import only what you use
- 02Copy the smallest example
- 03Run it with the Zolo CLI
Overview¶
jwt signs JSON payloads with a shared secret using HS256, HS384, or
HS512. Run these complete examples with the Zolo CLI and the jwt plugin
installed. The native plugin is not included in the browser playground.
JSON is text: use r#"..."# to keep its quotes and
braces literal. Single quotes are reserved for one character, such as 'a'.
The examples use a fixed clock and a demonstration secret so their output is
repeatable. In an application, supply the current Unix timestamp and load your
signing secret from configuration. verify checks the signature; expiration is
a separate check. Decoding a token does not authenticate its contents.
Common patterns¶
Accept a session before reading its permissions¶
Issue a short session, then check its signature and expiration before reading the user's identity and role. The fixed clock represents the receiving request.
use plugin jwt::{encode, verify, is_expired, get_claim}
let secret = "demo-session-secret"
let now: float = 1700000000
let payload = r#"{"sub":"user_42","role":"editor","exp":1700003600}"#
let token = encode(payload, secret, "HS256")
if !verify(token, secret, "HS256") {
print("session rejected: invalid signature")
} else if is_expired(token, now) {
print("session rejected: expired")
} else {
let user = get_claim(token, "sub")
let role = get_claim(token, "role")
print("signed in as {user}")
print("role: {role}")
}signed in as user_42
role: editorReject an expired session or an incorrect secret¶
Both failure paths are observable without a server or an external service.
use plugin jwt::{encode, verify, is_expired}
let secret = "demo-session-secret"
let token = encode(r#"{"sub":"alice","exp":1700000000}"#, secret)
print(verify(token, "incorrect-secret"))
print(is_expired(token, 1700000000))false
trueInspect token metadata¶
Inspect the header for debugging. It remains untrusted until verification.
use plugin jwt::{encode, decode_header, verify}
let secret = "demo-session-secret"
let token = encode(r#"{"sub":"bob"}"#, secret, "HS384")
let header = decode_header(token)
print(header["alg"])
print(header["typ"])
print(verify(token, secret, "HS384"))HS384
JWT
trueSign a JSON payload and return a JWT string
Signs valid JSON. The default algorithm is HS256.
use plugin jwt::{encode, verify}
let secret = "demo-session-secret"
let payload = r#"{"sub":"user_42","exp":1700003600}"#
let token = encode(payload, secret)
print(verify(token, secret, "HS256"))trueChoose HS512 explicitly when both sides use that algorithm:
use plugin jwt::{encode, verify}
let secret = "demo-session-secret"
let token = encode(r#"{"sub":"user_42"}"#, secret, "HS512")
print(verify(token, secret, "HS512"))trueCheck the HMAC signature, independently of expiration
Returns whether the HMAC signature matches. If no algorithm is supplied, the plugin reads it from the header. An explicit algorithm selects the HMAC used for verification. This function does not validate expiration or application claims such as audience and issuer.
use plugin jwt::{encode, verify}
let secret = "demo-session-secret"
let token = encode(r#"{"sub":"alice"}"#, secret, "HS512")
print(verify(token, secret, "HS512"))
print(verify(token, "incorrect-secret", "HS512"))
print(verify(token, secret, "HS256"))true
false
falseInspect the header, payload, and encoded signature
Returns the decoded header and payload JSON strings and the base64url
signature. This is inspection, without signature verification.
use plugin jwt::{encode, decode_parts}
let token = encode(r#"{"sub":"alice","role":"editor"}"#, "demo-session-secret")
let parts = decode_parts(token)
print(parts["header"])
print(parts["payload"]){"alg":"HS256","typ":"JWT"}
{"sub":"alice","role":"editor"}Inspect the header's algorithm and token type
Returns the header's alg and typ fields.
use plugin jwt::{encode, decode_header}
let token = encode(r#"{"sub":"bob"}"#, "demo-session-secret", "HS384")
let header = decode_header(token)
print(header["alg"])
print(header["typ"])HS384
JWTRead the payload JSON without verifying it
Reads the raw payload JSON. Verify the signature before using it for decisions.
use plugin jwt::{encode, verify, decode_payload}
let secret = "demo-session-secret"
let token = encode(r#"{"sub":"alice","role":"editor"}"#, secret)
if verify(token, secret, "HS256") {
print(decode_payload(token))
}{"sub":"alice","role":"editor"}Read a claim as text, or nil if it is absent
Returns strings unchanged; numbers and booleans become text. A missing claim returns nil. This function does not verify the signature.
use plugin jwt::{encode, verify, get_claim}
let secret = "demo-session-secret"
let token = encode(r#"{"sub":"user_7","active":true,"exp":1700003600}"#, secret)
if verify(token, secret, "HS256") {
print(get_claim(token, "sub"))
print(get_claim(token, "active"))
print(get_claim(token, "exp"))
if get_claim(token, "display_name") == nil {
print("display name not set")
}
}user_7
true
1700003600
display name not setCompare the expiration claim with a Unix timestamp
Returns true when a numeric exp is less than or equal to now_unix. An absent
or nonnumeric exp returns false; this function does not require expiration to
be present and does not verify the signature.
use plugin jwt::{encode, is_expired}
let secret = "demo-session-secret"
let token = encode(r#"{"sub":"alice","exp":1700003600}"#, secret)
print(is_expired(token, 1700003599))
print(is_expired(token, 1700003600))
let no_expiration = encode(r#"{"sub":"alice"}"#, secret)
print(is_expired(no_expiration, 1700003600))false
true
false