1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
//! Per-issuance id_token issuance config — mirror of `VerifyConfig`.
//!
//! Holds the deployment-stable fields (`issuer`, `audiences`, `typ`, `kid`,
//! `cat`) plus the **RP-knowable bindings** that pin a specific id_token
//! to a specific session (`nonce`) or a specific paired artifact
//! (`for_access_token` for at_hash, `for_authorization_code` for c_hash).
//!
//! ── Why bindings live on `IssueConfig` and not `IssueRequest<S>` ────────
//!
//! The conceptual split between `IssueConfig` and `IssueRequest<S>` is:
//!
//! * `IssueConfig` — fields the **RP** (verify side) holds an
//! independent copy of. The RP minted the nonce in its session, the
//! RP just received the access_token at the redirect_uri, the RP just
//! received the authorization_code. The id_token's job is to *prove*
//! the IdP's emission matches the RP's records. These fields land on
//! `IssueConfig` so that issuance configuration sits structurally
//! symmetric to `VerifyConfig` (same field, same surface, mirror
//! names).
//! * `IssueRequest<S>` — fields **only the IdP** asserts. `sub` is
//! IdP-assigned; `auth_time`/`acr`/`amr` describe the authentication
//! ceremony only the IdP witnessed; PII is sourced from the IdP's
//! account record. The RP cannot independently verify these against
//! its own state — it can only check well-formedness.
//!
//! This split is deeper than "per-deployment vs per-issuance": both
//! structs hold per-issuance state, but each owns one *side* of the
//! verifier-issuer agreement. Symmetric VerifyConfig and IssueConfig
//! both hold the RP's view; the IssueRequest is the IdP's testimony.
//!
//! ── No agility on `typ` and `cat` ───────────────────────────────────────
//!
//! `typ="JWT"` and `cat="id"` are pinned constructor-side. `&'static str`
//! literals prevent runtime mutation; the verify side enforces both
//! (`typ` via shared header check `M07-M16a`, `cat` via the M29-mirror
//! `engine::check_id_token_cat` landed in 10.10.A). Mirrors PASETO v4's
//! no-cryptographic-agility stance: zero negotiation surface.
use fmt;
use crateNonce;
/// Issuance configuration for an OIDC id_token.
///
/// Constructed via [`IssueConfig::id_token`] which pins `typ="JWT"`,
/// `cat="id"`, single-audience array, and the RP-supplied
/// [`Nonce`]. Multi-audience tokens replace the audience list via
/// [`with_audiences`](Self::with_audiences); hybrid + implicit flows add
/// the at_hash / c_hash binding inputs via
/// [`with_access_token_for_at_hash`](Self::with_access_token_for_at_hash)
/// and
/// [`with_authorization_code_for_c_hash`](Self::with_authorization_code_for_c_hash).
// Manual Debug — derive would expose `pub(crate)` field syntax in the
// output, which leaks naming. We render the same fields in a stable
// order, redacting the at_hash / c_hash binding inputs (an access_token
// is itself a bearer credential — never log raw). The Nonce is a public
// correlator with no secrecy contract (`id_token::nonce` doc-comment),
// so its derived Debug surfaces normally.