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
//! Shared CLI auth helpers (#28).
//!
//! Centralizes the `acquire_service_auth` orchestration — get a
//! Cairn-bound service-auth token from the operator's PDS, with
//! one-shot refresh-and-retry on a 401 from `getServiceAuth`. The
//! refresh path also persists the rotated tokens back to the
//! session file on disk so the next CLI invocation starts with
//! current credentials (§5.3).
//!
//! Callers (cli/audit.rs, cli/report.rs, cli/retention.rs,
//! cli/trust_chain.rs) used to carry byte-identical local copies of
//! this function. Factoring threshold per session N3 was 6+
//! identical copies; the trust-chain CLI (#37) brought the count
//! to 8 callsites across 4 modules and tripped the rule.
use Path;
use CliError;
use ;
use SessionFile;
/// Acquire a service-auth token bound to the given lexicon method,
/// refreshing the moderator session file in-place on a 401.
///
/// Behavior contract preserved from the pre-factor copies:
///
/// 1. Call `getServiceAuth(access_jwt, cairn_service_did, lxm)`.
/// 2. On `Unauthorized { context: "getServiceAuth" }`, refresh
/// the session via `refreshSession(refresh_jwt)`, write the
/// rotated tokens back to `session_path` (mode 0600 owner
/// invariants per §5.3), then retry `getServiceAuth` once.
/// 3. Any other PDS error propagates as `CliError::Pds`.
///
/// One-shot retry — a second 401 is propagated, not chained into
/// another refresh.
pub async