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
//! Edge authentication layer — the SDK's perimeter for Bearer-token
//! authenticated HTTP traffic.
//!
//! Mounts at the HTTP edge of any axum router and produces a single,
//! consumer-shaped session value as a request extension that handlers
//! consume by capability passing rather than re-authenticating in body.
//!
//! ## Why sdk-core ships this Layer
//!
//! Phase 11 — chat-auth was the 1st integrator (`chat-auth::middleware`),
//! RCW the 2nd (`rollcall_web::infrastructure::auth::bearer_auth_layer`),
//! CTW the 3rd (`classytime_web::infrastructure::auth::bearer_auth_layer`).
//! All three carried near-identical mechanism — Authorization > cookie
//! extraction, three HTTP dispositions (200 / 401 / 503), add-based
//! cookie clearance on dead-session 401, verbatim cookie value passing
//! to the validator. With **N=3 evidence** in hand, the mechanism
//! collapses into one SDK Layer; consumers ship only the substrate
//! adapter ([`AuthProvider<S>`] impl) + their cookie-name constant +
//! their clearance closure.
//!
//! Phase A Slice 4 lifted the Layer kit from `pas-external::oidc::axum`
//! into sdk-core so 1st-party services (chat-auth) can import it
//! directly without travelling through the External-Developer-facing
//! pas-external surface — the trust-boundary asymmetry pattern locked
//! by audit decision B (`RFC_2026-05-08_app-credential-collapse.md`).
//! pas-external still re-exports the kit at `pas_external::bearer::*`
//! for 3rd-party RCW/CTW consumers (audit decision D).
//!
//! ## Surface — four public types
//!
//! - [`AuthProvider<S>`] — the trait that consumers implement. One
//! async method, generic over the consumer's perimeter session type
//! `S`. Cryptographic verify + substrate liveness happen inside the
//! impl as one atomic decision; the Layer never spells substrate
//! internals.
//! - [`VerifyError`] — exactly two HTTP dispositions. Richer error
//! taxonomies (per-substrate break-glass dashboards) collapse here
//! at the SDK boundary.
//! - [`BearerAuthConfig`] — `&'static str` cookie name + an
//! `Arc<dyn Fn(CookieJar) -> CookieJar + Send + Sync>` clearance
//! closure. A value struct so future fields (e.g. `audit_sink`) can
//! be added with `Default` without breaking call sites.
//! - [`BearerAuthLayer<Sess, P>`] — the tower [`tower::Layer`] wired
//! into axum routers via `.layer(...)`.
//!
//! ## Sources (RFC 6750 + RFC 9700 §6.3)
//!
//! - `Authorization: Bearer <token>` HTTP header — preferred. RFC 6750
//! §2.1. Used by any non-browser caller (CLI clients, server-to-
//! server requests, native gRPC over h2 with a synthesised Bearer).
//! - HttpOnly cookie identified by [`BearerAuthConfig::access_cookie_name`]
//! — fallback. RFC 9700 §6.3 browser-context BCP. Each consumer ships
//! its own `__Host-*_at` constant (cookie names are domain-scoped per
//! RFC 6265bis); the SDK never spells the literal.
//!
//! `Authorization` wins precedence: a request carrying both is treated
//! as header-source.
//!
//! ## Errors
//!
//! - Missing Bearer source (no header, no cookie) → 401 without cookie
//! clearance. The browser may simply have not yet authenticated; no
//! session exists to clear.
//! - Token rejected ([`VerifyError::Rejected`]) → 401 + add-based
//! cookie clearance via the consumer's [`BearerAuthConfig::on_clear`]
//! closure. Browsers stop replaying a stale token.
//! - Substrate transient ([`VerifyError::SubstrateTransient`]) → 503
//! with cookies preserved. The browser may retry; the session is
//! still valid even if the validator can't currently say so.
//!
//! ## Why no SDK perimeter session type
//!
//! The trait's generic `S` IS the perimeter session — there is no SDK
//! `AuthClaims` or `BearerAuthSession` for the consumer to project from.
//! The consumer's `AuthProvider<MySession>::verify_token` impl produces
//! `MySession` directly, in one atomic step. Eliminates the otherwise-
//! tempting pass-through `claims → session` projection, and lets each
//! consumer keep its native session shape without SDK opinion. RCW/CTW
//! ship `BearerAuthSession` (3 fields); chat-auth ships `AuthSession`
//! (5 fields including `account_type`/`scopes`/`audience` for OAuth
//! 3rd-party scope-gating). Both coexist behind the same SDK Layer.
//!
//! See `RFC_2026-05-07_oidc-rp-phase-11x-rcw-ctw-migration.md` §11 and
//! `RFC_2026-05-08_app-credential-collapse.md` §3 (audit B/D/F) for
//! the contract-lock rationale.
pub use BearerAuthConfig;
pub use VerifyError;
pub use ;
pub use AuthProvider;
pub use MemoryAuthProvider;