pub struct IssueRequest {Show 14 fields
pub sub: String,
pub client_id: String,
pub ttl: Duration,
pub jti: Option<Ulid>,
pub account_type: Option<String>,
pub admin: bool,
pub caps: Vec<String>,
pub delegator: Option<String>,
pub dlg_depth: u8,
pub cid: Option<String>,
pub sv: Option<u64>,
pub active_ppnum: Option<String>,
pub scopes: Vec<String>,
pub sid: Option<String>,
}Fields§
§sub: StringSubject — the principal the token is about (RFC 7519 §4.1.2).
PAS-issued human tokens carry ppnum_id (ULID); AI-agent tokens
carry the agent’s ULID. Never empty.
client_id: Stringclient_id — the OAuth client whose credentials authorized this
token (RFC 9068 §2.2). 1st-party flows use "ppoppo-internal";
External Developer flows use the registered OAuth client_id.
ttl: DurationTime-to-live from now. The engine computes exp = iat + ttl and
emits both. Per-profile cap (24h access / 200d refresh) is
enforced via M19 on the verify side.
jti: Option<Ulid>Optional caller-supplied jti. When None, engine::encode::issue
generates a fresh ULID at issuance time. Tests pin a known ULID
so assertions can match by exact value.
account_type: Option<String>account_type — principal class (M40). Whitelist {human, ai_agent}
enforced verifier-side; absent for legacy tokens. PAS sets "human"
on user-facing flows and "ai_agent" on client_credentials.
admin: booladmin — issue-time admin gate flag (M44). When true, the
verifier additionally requires active_ppnum (or sub band
fallback) to fall in an admin-allocated band — defense in depth
against forged tokens with a stolen signing key.
caps: Vec<String>caps — capability list (M41). Default [] is the default-deny
surface contract: a token with no capabilities cannot perform any
privileged operation. Engine validates only that the wire shape
is an array of strings; semantic enforcement is per-surface.
delegator: Option<String>delegator — delegating principal’s ppnum_id (M40-adjacent).
Set on tokens minted via Token Exchange flows to record who
authorized the delegated session. Audit logs key off this field.
(Wire name: delegator; the earlier actor name was retired —
RFC 8693 reserves actor for token-exchange chain semantics that
don’t apply here.)
dlg_depth: u8dlg_depth — delegation chain depth (M43). 0 = original principal,
each Token Exchange step increments by 1. Engine rejects > 4 to
bound the audit-trail explosion of arbitrarily deep delegation.
u8 is intentional: there is no scenario where depth ≥ 256.
cid: Option<String>cid — WebAuthn credential id that authenticated this session
(passkey path only). Enables session-to-credential provenance for
forensic analysis and selective-session-kill flows. Absent on
every non-passkey path so audit logs distinguish authentication
methods without a per-row lookup.
sv: Option<u64>sv — per-account session_version snapshot (Human path only).
Validators compare token.sv >= cached(sv:{sub}) and reject
stale tokens; the counter bumps inside the break-glass TX,
invalidating all prior tokens within the consumer cache TTL.
Absent on AI-agent and delegated tokens (no break-glass mechanism).
active_ppnum: Option<String>active_ppnum — display ppnum (e.g. 123-1234-5678). UI surfaces
render this; sub is the immutable ULID and is the authorization
axis. Absent on tokens that don’t represent a human-facing
session (raw machine tokens).
scopes: Vec<String>scopes — OAuth scope list (M42). Engine bounds the array to ≤ 256
entries (RFC 8725-adjacent — bound the per-token audit surface).
Default [] is “no externally-granted scope”; 1st-party flows
emit a non-empty list (profile, email, etc).
sid: Option<String>sid — session row id (M36, Phase 5). When set, the verifier’s
cfg.session_revocation::is_active(sub, sid) query gates token
admission against user_sessions(sub, sid) row liveness — row
deletion = revocation per STANDARDS_JWT_DETAILS_MITIGATION §E.
PAS issuance sets this on every Human-path token bound to a
session row; AI-agent / machine flows leave it unset and the
verifier short-circuits the gate. Wire shape: ULID string when
present (matches user_sessions.session_id PK).
Implementations§
Source§impl IssueRequest
impl IssueRequest
Sourcepub fn new(
sub: impl Into<String>,
client_id: impl Into<String>,
ttl: Duration,
) -> Self
pub fn new( sub: impl Into<String>, client_id: impl Into<String>, ttl: Duration, ) -> Self
Construct a new request with the required fields. Domain claim
fields default to “absent / empty / 0 / false” — every emission
is opt-in via a with_* builder, so a caller who forgets to set
admin cannot accidentally mint an admin token.
Sourcepub fn with_jti(self, jti: Ulid) -> Self
pub fn with_jti(self, jti: Ulid) -> Self
Pin a specific jti instead of letting the engine generate one.
Test-only escape hatch — production paths should never override.
Sourcepub fn with_account_type(self, account_type: impl Into<String>) -> Self
pub fn with_account_type(self, account_type: impl Into<String>) -> Self
Set account_type (M40). PAS issuance paths pass "human" or
"ai_agent"; the verifier’s whitelist (Phase 4 commit 4.2)
rejects anything else.
Sourcepub fn with_admin(self, admin: bool) -> Self
pub fn with_admin(self, admin: bool) -> Self
Set the admin gate flag (M44). Combined with active_ppnum band
check on the verify side, this is the issue-time half of the
admin-token defense in depth.
Sourcepub fn with_caps(self, caps: Vec<String>) -> Self
pub fn with_caps(self, caps: Vec<String>) -> Self
Set the capability list (M41). An empty list (the default) means no privileged capabilities; surface code MUST positive-check.
Sourcepub fn with_delegator(self, delegator: impl Into<String>) -> Self
pub fn with_delegator(self, delegator: impl Into<String>) -> Self
Set the delegating principal’s ppnum_id (M40-adjacent). Token
Exchange flows record the human authorizer here.
Sourcepub fn with_dlg_depth(self, dlg_depth: u8) -> Self
pub fn with_dlg_depth(self, dlg_depth: u8) -> Self
Set the delegation chain depth (M43). 0 = direct, increments by 1 per Token Exchange step; engine bounds at 4.
Sourcepub fn with_credential_id(self, credential_id: impl Into<String>) -> Self
pub fn with_credential_id(self, credential_id: impl Into<String>) -> Self
Set the WebAuthn credential id (cid). Call this only on the
passkey issuance path; other paths MUST leave it unset so audit
logs distinguish authentication methods without a per-row lookup.
Sourcepub fn with_session_version(self, sv: u64) -> Self
pub fn with_session_version(self, sv: u64) -> Self
Set the per-account session_version (Human entity path only).
AI-agent and delegated paths MUST leave it unset — they have no
break-glass mechanism, and emitting sv = 0 would lock those
tokens out the moment the human originator break-glasses.
Sourcepub fn with_active_ppnum(self, active_ppnum: impl Into<String>) -> Self
pub fn with_active_ppnum(self, active_ppnum: impl Into<String>) -> Self
Set the display ppnum (active_ppnum). UI surfaces render this;
sub remains the immutable ULID for authorization decisions.
Sourcepub fn with_scopes(self, scopes: Vec<String>) -> Self
pub fn with_scopes(self, scopes: Vec<String>) -> Self
Set the OAuth scope list (M42). Engine bounds the array to ≤ 256 entries on the verify side.
Sourcepub fn with_sid(self, sid: impl Into<String>) -> Self
pub fn with_sid(self, sid: impl Into<String>) -> Self
Set the session row id (sid claim, M36 — Phase 5). Call this
only on issuance paths bound to a user_sessions row (Human
magic-link / passkey / refresh-cycle); AI-agent and machine
paths MUST leave it unset so the verifier short-circuits the
session-revocation gate. The verifier compares (sub, sid)
against the substrate; row deletion = revocation per
STANDARDS_JWT_DETAILS_MITIGATION §E.
Trait Implementations§
Source§impl Clone for IssueRequest
impl Clone for IssueRequest
Source§fn clone(&self) -> IssueRequest
fn clone(&self) -> IssueRequest
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read more