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
//! M70 — id_token `auth_time` freshness gate (OIDC Core 1.0 §3.1.3.7).
//!
//! When the RP's auth request specified a `max_age` parameter, the
//! returned id_token MUST carry an `auth_time` claim and the
//! verification MUST refuse the token if too much time has elapsed
//! since end-user authentication.
//!
//! ── Opt-in semantics ────────────────────────────────────────────────────
//!
//! Engine inspects `auth_time` only when `cfg.max_age` is `Some(n)`.
//! RPs that did not request a max_age window leave it unset and the
//! engine returns `Ok(())` without touching the claim. Symmetric to
//! M67/M68 (`with_access_token_binding` / `with_authorization_code_binding`):
//! freshness is conditional on the verifier asking for it.
//!
//! ── Strictness when opted in ────────────────────────────────────────────
//!
//! Once `max_age` is set, missing `auth_time` is a hard refusal
//! (`AuthTimeMissing`). The OIDC Core §3.1.3.7 wording is
//! "auth_time Claim is REQUIRED when max_age request was made"; the
//! engine rejects rather than defaulting to `now`. Stale tokens
//! (`now - auth_time > max_age`) yield `AuthTimeStale` — distinct
//! variant from missing because the operator response differs:
//! Stale = re-authenticate the user; Missing = IdP misconfiguration.
//!
//! ── Clock source ────────────────────────────────────────────────────────
//!
//! `now: i64` is injected from the verify pipeline (clock-port RFC Slice 7).
//! The caller (`id_token::verify`) receives `now` from its own caller,
//! propagating the single clock read all the way from the infrastructure layer.
use crate;
pub