pub struct Claims {Show 15 fields
pub iss: String,
pub sub: String,
pub exp: i64,
pub iat: i64,
pub nbf: Option<i64>,
pub jti: String,
pub client_id: String,
pub entity_type: Option<EntityType>,
pub caps: Vec<String>,
pub scopes: Vec<String>,
pub admin: bool,
pub active_ppnum: Option<String>,
pub act: Option<Act>,
pub cid: Option<String>,
pub sid: Option<String>,
}Fields§
§iss: String§sub: String§exp: i64§iat: i64§nbf: Option<i64>§jti: String§client_id: String§entity_type: Option<EntityType>entity_type (M40) — the identity class of sub. None for
1st-party OTP/passkey tokens, which carry no such claim (legacy
admit). Typed, so the whitelist is enforced by parsing rather
than by every consumer re-stating it: a wire value outside
EntityType is rejected with AuthError::EntityTypeInvalid
before this struct is constructed.
Not session mode — a human identity driven by an agent is
Some(EntityType::Human) plus Self::act, never a
distinct value here. See EntityType for why that
distinction is enforced by the type.
caps: Vec<String>caps (M41) — capability list. Empty when absent or empty-array
on the wire (the engine collapses both to the same surface so
callers’ default-deny check is caps.contains(&"x")). Wire-shape
validation (must be a JSON array of strings) lives in
engine::check_domain; semantic interpretation of each
capability string is per-surface (PAS, PCS, RCW each own their
vocabulary).
scopes: Vec<String>scopes (M42) — OAuth scope list. Empty when absent or empty-
array (same collapse as caps). Engine bounds the array length
at ≤ 256; entries beyond that are a forgery / misconfiguration
signal that pessimizes per-request scope checks. Conceptually
distinct from caps (scopes are externally granted via OAuth;
caps are internally minted by PAS), so the surfacing is duplicated
rather than unified — collapsing them would force callers to
untangle two authorization vectors at every check site.
admin: booladmin (M44) — token claims admin authority. Admin authority
is DB-determined (STS_AUTH_PPOPPO §3.2: is_admin = TRUE AND lifecycle_state = 'active' AND active passkey ≥ 1). This
claim is the fast pre-flight signal — when admin == true,
the engine has already proven active_ppnum falls in the admin
band (defense in depth against stolen-signing-key forgeries).
Callers MUST still call the DB-side is_admin invariant — this
flag tells them whether to even bother.
active_ppnum: Option<String>active_ppnum (M44 + UI display) — the digit-form ppnum the
session is currently active under. UI surfaces render this;
sub (ULID) is the immutable authorization axis. Engine reads
it for the M44 admin-band check and surfaces it unchanged.
act: Option<Act>act (RFC 8693 §4.1) — the party currently acting for sub, and
the delegation chain behind it. Surfaced for audit logs (which
principal authorized this session) and because it is half of the
delegation predicate: delegated is
entity_type == Human && act.is_some(), derived at one site rather
than stored as a value in either axis. None for tokens outside a
chain.
The name is the registered claim’s. The retired delegator claim
carried a rationale that was backwards on both counts — RFC 8693
registers act (not actor), and its token-exchange chain
semantics apply here exactly: these tokens are minted by an RPC
named ExchangeToken. Depth lives in the nesting, which is why
dlg_depth is gone (see Act::depth).
cid: Option<String>cid — WebAuthn credential id that authenticated this session
(passkey path only). Surfaces for forensic provenance and
future selective-session-kill flows. None on every non-
passkey path so audit logs distinguish authentication methods
without a per-row lookup.
sid: Option<String>sid (M36) — the issuer’s identifier for the session this token
was minted into. The engine does not define what a session is;
it only carries the id and, when present, asks the issuer via
cfg.session_revocation.is_active(sub, sid), refusing if the
answer is “gone” (STS_JWT_DETAILS_MITIGATION §E “row deletion
= revocation”). None on machine tokens / AI-agent flows that
belong to no session; engine short-circuits the gate when None
so non-session-bound tokens admit.
In PAS this is the refresh-token family_id — that is the
system’s unit of session (accounts-core
session_management::list_sessions: “each family represents one
session”), so is_active reduces to “does an unrevoked family
sid still exist for sub”. Wire shape: ULID string.