pub struct IssueRequest<S: ScopeSet> {
pub sub: String,
pub ttl: Duration,
pub auth_time: Option<i64>,
pub acr: Option<String>,
pub amr: Option<Vec<String>>,
pub azp: Option<String>,
/* private fields */
}Expand description
OIDC id_token issuance payload, phantom-typed by S: ScopeSet.
The S parameter witnesses the OAuth scope the issuer is honoring.
PII builders (with_email, with_name, …) are gated by the matching
marker traits (HasEmail, HasProfile, HasPhone, HasAddress),
making “wrong scope, wrong field” a compile error.
── compile_fail evidence (D2 emission half) ────────────────────────────
The standing acceptance fixture is the doc-test below; cargo test --doc -p ppoppo-token runs it and asserts the snippet fails to
compile (E0599 — method not found).
use std::time::Duration;
use ppoppo_token::id_token::{IssueRequest, scopes::Openid};
fn _compile_fail() {
let _ = IssueRequest::<Openid>::new(
"01HSAB00000000000000000000",
Duration::from_secs(600),
)
.with_email("u@example.com"); // ERROR: with_email requires S: HasEmail
}Granting the email scope at issuance time satisfies the bound:
use std::time::Duration;
use ppoppo_token::id_token::{IssueRequest, scopes::Email};
fn _compiles() {
let _ = IssueRequest::<Email>::new(
"01HSAB00000000000000000000",
Duration::from_secs(600),
)
.with_email("u@example.com");
}Fields§
§sub: Stringsub — the principal the id_token is about (RFC 7519 §4.1.2,
OIDC Core §2). PAS-issued tokens carry ppnum_id (ULID); never
empty.
ttl: DurationTime-to-live from now. The engine computes exp = iat + ttl and
emits both. Per-profile cap is per-deployment; the engine may
enforce upper bounds in a future row (analogous to access-token
M19).
auth_time: Option<i64>auth_time — when the End-User authentication occurred (Unix
seconds). The verify-side M70 gate (Phase 10.6) compares this
against now - max_age; the issuer-side just emits what the IdP
witnessed. Required when the RP requested max_age in the auth
request — but that contract is between RP and IdP at the
app-protocol level, not the engine; emitting whenever the IdP
has a value is the safe default.
acr: Option<String>acr — Authentication Context Class Reference (OIDC §2). The
verify-side M71 gate (Phase 10.7) refuses tokens whose acr is
not in cfg.acr_values. Emit a value when the IdP can attest to
a specific authentication context; absence collapses to “RP has
no acr policy or IdP cannot assert one”.
amr: Option<Vec<String>>amr — Authentication Methods References (e.g. ["pwd", "mfa"],
OIDC §2). Surfaced as data on the verify side; no gate. Emit
whenever the IdP knows the methods; absence is admitted.
azp: Option<String>azp — Authorized Party (OIDC §2). The verify-side M69 gate
(Phase 10.5) requires azp == client_id whenever it’s present
AND requires presence on multi-aud tokens. Issue side: set on
every multi-aud token; optional on single-aud (the §2 guidance
is silent on single-aud).
Implementations§
Source§impl<S: ScopeSet> IssueRequest<S>
impl<S: ScopeSet> IssueRequest<S>
Sourcepub fn new(sub: impl Into<String>, ttl: Duration) -> Self
pub fn new(sub: impl Into<String>, ttl: Duration) -> Self
Construct a new request with the required core fields. All
optional fields default to absent; every emission is opt-in via a
with_* builder, so a caller who forgets to set a value cannot
accidentally emit a populated claim.
The scope parameter is fixed at construction via turbofish:
IssueRequest::<Email>::new("01H...", Duration::from_secs(600)).
Sourcepub fn with_auth_time(self, auth_time: i64) -> Self
pub fn with_auth_time(self, auth_time: i64) -> Self
Set auth_time (Unix seconds) — when the End-User authentication
occurred. Always available regardless of S (auth_time is in
BASE_CLAIMS).
Source§impl<S: HasEmail> IssueRequest<S>
email scope — OIDC §5.4.
impl<S: HasEmail> IssueRequest<S>
email scope — OIDC §5.4.
pub fn with_email(self, email: impl Into<String>) -> Self
pub fn with_email_verified(self, verified: bool) -> Self
Source§impl<S: HasProfile> IssueRequest<S>
profile scope — OIDC §5.4 (name family + locale + updated_at).
impl<S: HasProfile> IssueRequest<S>
profile scope — OIDC §5.4 (name family + locale + updated_at).
pub fn with_name(self, name: impl Into<String>) -> Self
pub fn with_given_name(self, given_name: impl Into<String>) -> Self
pub fn with_family_name(self, family_name: impl Into<String>) -> Self
pub fn with_middle_name(self, middle_name: impl Into<String>) -> Self
pub fn with_nickname(self, nickname: impl Into<String>) -> Self
pub fn with_preferred_username( self, preferred_username: impl Into<String>, ) -> Self
pub fn with_profile(self, profile: impl Into<String>) -> Self
pub fn with_picture(self, picture: impl Into<String>) -> Self
pub fn with_website(self, website: impl Into<String>) -> Self
pub fn with_gender(self, gender: impl Into<String>) -> Self
pub fn with_birthdate(self, birthdate: impl Into<String>) -> Self
pub fn with_zoneinfo(self, zoneinfo: impl Into<String>) -> Self
pub fn with_locale(self, locale: impl Into<String>) -> Self
Sourcepub fn with_updated_at(self, updated_at: i64) -> Self
pub fn with_updated_at(self, updated_at: i64) -> Self
updated_at is Unix seconds (OIDC §5.1).
Source§impl<S: HasPhone> IssueRequest<S>
phone scope — OIDC §5.4.
impl<S: HasPhone> IssueRequest<S>
phone scope — OIDC §5.4.
pub fn with_phone_number(self, phone_number: impl Into<String>) -> Self
pub fn with_phone_number_verified(self, verified: bool) -> Self
Source§impl<S: HasAddress> IssueRequest<S>
address scope — OIDC §5.4 (single structured claim).
impl<S: HasAddress> IssueRequest<S>
address scope — OIDC §5.4 (single structured claim).