ywt/claim
Types
Values
pub fn audience(primary: String, others: List(String)) -> Claim
The aud claim identifies who the token is meant for.
Tokens with an aud field are rejected by default unless you add this claim
and the value matches one of the accepted audiences. ywt validates both
string and array-valued aud fields.
let claims = [
claim.expires_at(max_age: duration.minutes(15), leeway: duration.minutes(1)),
claim.issuer("https://auth.example.com", []),
claim.audience("https://api.example.com", []),
]
pub fn custom(
name name: String,
value value: a,
encode encode: fn(a) -> json.Json,
decoder decoder: decode.Decoder(a),
) -> Claim
A custom claim stores an application-specific value.
The decoded token value must exactly match value. Use this for simple
fixed requirements such as role, tenant, or token class checks.
let claims = [
claim.custom("role", "admin", json.string, decode.string),
claim.expires_at(max_age: duration.minutes(15), leeway: duration.minutes(1)),
claim.issuer("https://auth.example.com", []),
claim.audience("https://api.example.com", []),
]
pub fn encode(
claims: List(Claim),
data: List(#(String, json.Json)),
) -> json.Json
Encodes claims and application data into a JSON object.
This is a low-level function used internally by ywt.
Claims take precedence when a field appears in both lists. Put security
fields such as exp, iss, aud, and sub in claims instead of payload
data.
let claims = [
claim.subject("user_123", []),
claim.expires_at(max_age: duration.minutes(15), leeway: duration.minutes(1)),
]
claim.encode(claims, [
#("sub", json.string("ignored")),
#("role", json.string("admin")),
])
pub fn encode_numeric_date(
timestamp: timestamp.Timestamp,
) -> json.Json
Encodes a timestamp as a JWT numeric date.
Fractional seconds are truncated to keep encoded JWTs compact.
#("checked_at", claim.encode_numeric_date(timestamp.system_time()))
pub fn expires_at(
max_age max_age: duration.Duration,
leeway leeway: duration.Duration,
) -> Claim
The exp claim says when the token expires.
Prefer short lifetimes. Tokens with exp are checked by default with zero
leeway, but ywt will not add an expiration unless you include this claim.
max_age is used when writing the token; verification checks the token’s
exp value plus leeway.
let claims = [
claim.expires_at(max_age: duration.minutes(15), leeway: duration.minutes(1)),
claim.issuer("https://auth.example.com", []),
claim.audience("https://api.example.com", []),
]
pub fn id(id: String, others: List(String)) -> Claim
The jti claim gives the token a unique id.
ywt does not store token ids. Use this with your own denylist or session store if you need revocation.
let claims = [
claim.id("session-123", []),
claim.expires_at(max_age: duration.minutes(15), leeway: duration.minutes(1)),
claim.issuer("https://auth.example.com", []),
claim.audience("https://api.example.com", []),
]
pub fn issued_at() -> Claim
The iat claim records when the token was issued.
This writes the current time when creating a token, but it does not reject
future-dated tokens when verifying. Use not_before for that.
let claims = [
claim.issued_at(),
claim.expires_at(max_age: duration.minutes(15), leeway: duration.minutes(1)),
claim.issuer("https://auth.example.com", []),
claim.audience("https://api.example.com", []),
]
pub fn issuer(issuer: String, others: List(String)) -> Claim
The iss claim identifies who issued the token.
Use this to reject tokens from the wrong issuer. Issuer strings often point at the service that also publishes verification keys, but ywt does not fetch or trust those keys automatically.
let claims = [
claim.expires_at(max_age: duration.minutes(15), leeway: duration.minutes(1)),
claim.issuer("https://auth.example.com", []),
claim.audience("https://api.example.com", []),
]
pub fn not_before(
time time: timestamp.Timestamp,
leeway leeway: duration.Duration,
) -> Claim
The nbf claim says the token must not be accepted before a time.
Tokens with nbf are checked by default with zero leeway. Add this claim
when you want to set the value while signing or allow clock skew while
verifying. Keep leeway small.
let claims = [
claim.not_before(timestamp.system_time(), leeway: duration.minutes(1)),
claim.expires_at(max_age: duration.minutes(15), leeway: duration.minutes(1)),
claim.issuer("https://auth.example.com", []),
claim.audience("https://api.example.com", []),
]
pub fn numeric_date_decoder() -> decode.Decoder(
timestamp.Timestamp,
)
Decodes a JWT numeric date into a timestamp.
JWT numeric dates are seconds since the Unix epoch.
decode.field("exp", claim.numeric_date_decoder())
pub fn optional(claim: Claim) -> Claim
Allows a claim to be absent during verification.
When the field is present it is still validated. If the claim is already optional, it is returned unchanged.
let claims = [
claim.id("session-123", []) |> claim.optional,
claim.expires_at(max_age: duration.minutes(15), leeway: duration.minutes(1)),
claim.issuer("https://auth.example.com", []),
claim.audience("https://api.example.com", []),
]
pub fn subject(subject: String, others: List(String)) -> Claim
The sub claim identifies the user or entity the token is about.
Prefer stable internal ids. Avoid putting personal data in the subject, because JWT payloads are readable by whoever has the token.
let claims = [
claim.subject("user_123", []),
claim.expires_at(max_age: duration.minutes(15), leeway: duration.minutes(1)),
claim.issuer("https://auth.example.com", []),
claim.audience("https://api.example.com", []),
]
pub fn typ(expected: String) -> Claim
The typ header describes what kind of token this is.
The field is optional in the JWT specification, but some systems require
"JWT" or another explicit type. It is not a security boundary; still
validate issuer, audience, expiration, and signature.
let claims = [
claim.typ("JWT"),
claim.expires_at(max_age: duration.minutes(15), leeway: duration.minutes(1)),
claim.issuer("https://auth.example.com", []),
claim.audience("https://api.example.com", []),
]
pub fn verify(
payload: dynamic.Dynamic,
claims: List(Claim),
) -> Result(Nil, @internal Error)
Validates claims against a JWT payload.
This is a low-level function used internally by ywt.
This does not verify the token signature. Use the platform ywt.decode
function for normal JWT verification.
Tokens with exp and nbf are checked by default with zero leeway. Tokens
with aud are rejected by default unless you pass an audience claim.
Audience validation accepts string or array values.