pas_external/lib.rs
1#![doc = include_str!("../README.md")]
2
3pub mod audit;
4// Clock port re-export — External Developer consumers can use
5// `pas_external::clock::ArcClock` / `pas_external::clock::FrozenClock`
6// without a separate `ppoppo-clock` dep in their Cargo.toml.
7pub mod clock {
8 pub use ::ppoppo_clock::*;
9}
10// Perimeter Bearer-auth Layer kit — Phase A Slice 4 lifted the kit to
11// `ppoppo_sdk_core::bearer::*`. pas-external 0.11.0 re-exports the
12// kit at `pas_external::bearer::*` (audit decision D — 1-level
13// role-named module, no `oidc::axum::*` nesting) for 3rd-party
14// consumers (RCW/CTW). 1st-party services (chat-auth) import direct
15// from sdk-core (audit decision B). The framework-dep visibility
16// (axum / tower) is signalled by the `axum` feature gate, not by a
17// nested `pas_external::oidc::axum::*` namespace.
18#[cfg(feature = "axum")]
19pub mod bearer {
20 pub use ::ppoppo_sdk_core::bearer::*;
21}
22// `epoch` re-exports the engine `EpochRevocation` port + ships the
23// canonical adapter set (Phase 11.Z, RFC_2026-05-09 §3.5). Gated on
24// `well-known-fetch` because the engine port itself needs `token` and
25// the original `UserinfoFetcher` (deleted in 0.10.0) required the HTTP
26// client (`oauth`) — both implied by the `well-known-fetch` flag.
27// `SharedCacheCache` (0.10.0, RFC_2026-05-08 §4.1) requires the
28// additional `shared-cache` feature for the `ppoppo-infra` adapter dep.
29#[cfg(feature = "well-known-fetch")]
30pub mod epoch;
31pub mod error;
32// `oauth` is two-tiered: the `TokenResponse` wire DTO compiles at the
33// `oauth` tier (consumed by `pas_port` / `session_liveness`), while the
34// `OAuthConfig` + `AuthClient` HTTP adapter is gated inside the module on
35// `well-known-fetch` — the tier of its sole constructor,
36// `oidc::RelyingParty::new`. As of 0.8.0 the module is `pub(crate)`:
37// consumers reach the OIDC RP composition root (`oidc::RelyingParty<S>`)
38// and never the raw OAuth surface. See `oidc::RefreshOutcome` for the
39// boundary type at `RelyingParty::refresh`.
40#[cfg(feature = "oauth")]
41pub(crate) mod oauth;
42#[cfg(feature = "token")]
43pub mod oidc;
44// Native-app OAuth composition root (RFC 8252) — the non-OIDC sibling of
45// `oidc::RelyingParty<S>`. Separate rather than a relaxation: the RP is
46// welded to OIDC in three places (an `openid` scope marker, an
47// unconditional `nonce`, a verified id_token) and a native resource client
48// breaks all three. See the module docs.
49#[cfg(feature = "native")]
50pub mod native;
51#[cfg(feature = "oauth")]
52pub mod pas_port;
53// Renewing `TokenSource` (G3 / RTR) — `RefreshTokenSource` + `TokenStore`.
54// For native / CLI clients (CNC) that hold a durable refresh token and feed a
55// `ppoppo_sdk_core::TokenCache`; depends on the `PasAuthPort` port (`oauth`)
56// and sdk-core's `token-cache` (the `TokenSource` trait it implements).
57#[cfg(feature = "refresh-source")]
58pub mod refresh_source;
59// `pkce` primitives (`generate_state`, `generate_code_verifier`,
60// `generate_code_challenge`) are SDK plumbing — `oidc::RelyingParty::start`
61// is the sole consumer, so the module is gated on `well-known-fetch`
62// (the RP's tier) rather than the lower `oauth` tier, which would orphan
63// it under the default feature set. `pub(crate)` since 0.8.0.
64#[cfg(feature = "well-known-fetch")]
65pub(crate) mod pkce;
66// Granted-vs-requested scope validation (RFC 6749 §5.1). Ungated and
67// dependency-free — it reads only a `&str` echo and a `ConsentScopes`
68// marker, and every leg that receives a token response uses the same
69// function, so the RFC's absence-and-containment semantics are decided in
70// exactly one place.
71pub mod scope_grant;
72// `session_liveness` is intentionally ungated at module level — the
73// 0.10.0 `SessionLiveness` port has no AES / OAuth deps and ships
74// regardless of feature configuration so the verifier slot
75// (`PasJwtVerifier::with_session_liveness`) can reference it under
76// just `feature = "well-known-fetch"`. Internal sub-modules
77// (`cipher`, `liveness`) remain gated on `feature = "session-liveness"`
78// for the AES wrapper + PAS refresh-token check.
79pub mod session_liveness;
80pub mod types;
81
82// Test-support helpers. `FakePasServer` is the SDK-owned wiremock-wrapped
83// fake PAS Authorization Server, replacing the 0.7.x
84// `RelyingParty::for_test_with_parts` escape hatch. Consumer integration
85// tests construct a real `RelyingParty::new(...)` against
86// `FakePasServer.issuer_url()` so production and test go through the same
87// public interface.
88#[cfg(feature = "test-support")]
89pub mod test_support;
90
91// Re-exports for convenient access
92pub use audit::{
93 AuditEvent, AuditSink, IdTokenFailureKind, MemoryRateLimiter, NoopAuditSink, RateLimitKey,
94 RateLimitedAuditSink, RateLimiter, VerifyErrorKind, compose_id_token_source_id,
95 compose_source_id,
96};
97#[cfg(any(test, feature = "test-support"))]
98pub use audit::MemoryAuditSink;
99pub use error::{Error, TokenError};
100// 0.10.0 — ungated L2 verifier-slot port (RFC_2026-05-08 §4.2 lock).
101pub use session_liveness::{SessionLiveness, SessionLivenessError};
102#[cfg(feature = "session-liveness")]
103pub use session_liveness::{
104 CipherError, EncryptedRefreshToken, LivenessFailure, LivenessOutcome, RevokeCause,
105 TokenCipher, TransientCause, attempt_liveness_refresh,
106};
107// γ port-and-adapter — Phase 6.1 (D-04 = γ, locked 2026-05-05).
108// Phase A (RFC `RFC_2026-05-08_app-credential-collapse.md`, audit
109// decisions E + G) lifted the cohesive verifier group to
110// `ppoppo_sdk_core::verifier::*`. pas-external re-exports at top level
111// (no `token::` namespace — audit decision E) so consumer code
112// reaches `pas_external::{BearerVerifier, JwtVerifier, ...}`. Renames:
113// `PasJwtVerifier` → `JwtVerifier`; `Expectations` → `VerifyConfig`;
114// `AuthSession` → `VerifiedClaims`. The `crypto-side` `VerifyError`
115// re-exports as `TokenVerifyError` (BREAKING) to make space for the
116// Layer-side `VerifyError` from `pas_external::bearer::*` (Slice 4
117// migration). Phase A 0.11.0 ships clean — no transitional alias.
118#[cfg(feature = "token")]
119pub use ::ppoppo_sdk_core::verifier::{
120 BearerVerifier, VerifiedClaims, VerifyConfig, VerifyError as TokenVerifyError,
121};
122#[cfg(feature = "well-known-fetch")]
123pub use ::ppoppo_sdk_core::verifier::{EpochEnforcement, JwksCache, JwtVerifier};
124#[cfg(all(feature = "token", any(test, feature = "test-support")))]
125pub use ::ppoppo_sdk_core::verifier::MemoryBearerVerifier;
126// OIDC RP surface — composition root + post-verify shapes + ports.
127// `RelyingParty<S>` is the consumer-facing entry point; `RefreshOutcome`
128// is the typed boundary return for `RelyingParty::refresh` (replaces
129// the 0.7.x `oauth::TokenResponse` re-export).
130#[cfg(feature = "token")]
131pub use oidc::{Address, IdAssertion, IdTokenVerifier, IdVerifyError, Nonce, ScopePiiReader};
132#[cfg(all(feature = "token", any(test, feature = "test-support")))]
133pub use oidc::MemoryIdTokenVerifier;
134pub use types::{KeyId, Ppnum, PpnumId, SessionId, UserId};
135// The SDK-family scope contract. Re-exported (facade rule: every type in a
136// public signature is reachable from this crate's root) because
137// `NativeAuthFlow<S: ConsentScopes>` and the sources it yields put both
138// names on the public surface. A 3rd party must never have to name the
139// engine crate — `pcs-session` re-exports the same two, so an integration
140// spells `pcs_session::scopes::Notify` and nothing else.
141pub use ::ppoppo_sdk_core::scopes::ConsentScopes;
142#[cfg(feature = "refresh-source")]
143pub use ::ppoppo_sdk_core::scopes::ScopedTokenSource;
144pub use scope_grant::{ScopeNotCovered, ensure_covers};
145// Native-app OAuth surface (RFC 8252).
146#[cfg(feature = "native")]
147pub use native::{CallbackError, NativeAuthFlow, NativeAuthInitError, NativeConfig};
148// `AuthClient` — nameable, deliberately NOT constructible.
149//
150// It appears as a generic argument in what `NativeAuthFlow::{complete,
151// token_source}` return (`RefreshTokenSource<AuthClient, T, S>`), and a native
152// app holds that source in its application state — which means writing the
153// type down. Without this re-export the signature names a `pub(crate)`
154// internal and the surface is unusable from outside, while the crate still
155// compiles cleanly: `private_interfaces` does not fire on a private type in
156// generic-argument position. `tests/native_auth_flow_boundary.rs` names the
157// type from outside precisely because no lint will.
158//
159// Constructing one still requires `OAuthConfig`, which stays unexported — so
160// 0.8.0's decision (consumers reach OAuth through a composition root, never
161// the raw client) is intact. Nameable is not the same as constructible, and
162// only the first is needed here.
163#[cfg(feature = "well-known-fetch")]
164pub use oauth::AuthClient;
165
166// Renewing TokenSource (G3 / RTR).
167#[cfg(feature = "refresh-source")]
168pub use refresh_source::{MemoryTokenStore, RefreshTokenSource, TokenStore, TokenStoreError};
169// `Url` is consumer-facing via `Config::new(client_id, redirect_uri: Url, ...)`
170// and `Discovery::for_test`. Re-exported so consumers reach the same `url`
171// crate version the SDK uses without separately tracking it in their
172// Cargo.toml.
173#[cfg(feature = "oauth")]
174pub use url::Url;