aster_forge_auth/lib.rs
1//! Product-neutral local session authentication mechanics.
2//!
3//! `aster_forge_auth` owns JWT token contracts, validation policy, token-pair issuance, and the
4//! refresh-rotation coordinator. Product repositories own account state, database transactions,
5//! session tables, cookies, permissions, audit events, and error presentation. Persistence is
6//! accessed through [`RefreshSessionStore`], so this crate does not depend on `SeaORM` or a product
7//! schema.
8//!
9//! Select exactly one Cargo backend feature: `aws-lc-rs` (default) or `rust-crypto`.
10//! The product entrypoint must call [`initialize_jwt_crypto_provider`] before any JWT use,
11//! including direct `jsonwebtoken` calls. This installs a process-wide provider, not an
12//! instance-specific backend. Signing algorithms remain a runtime [`JwtPolicy`] choice.
13//!
14//! ```
15//! use aster_forge_auth::{AuthTokenType, JwtKey, JwtPolicy, JwtSigner, JwtVerifier,
16//! Restriction, SessionId, SessionVersion, Subject};
17//!
18//! # fn main() -> aster_forge_auth::Result<()> {
19//! aster_forge_auth::initialize_jwt_crypto_provider()?;
20//! let key = JwtKey::hmac([42; 32])?; // Product loads a dedicated random signing key.
21//! let policy = JwtPolicy::new("product", "local-web", 900, 604_800)?;
22//! let signer = JwtSigner::with_system_clock(key.clone(), policy.clone());
23//! let verifier = JwtVerifier::with_system_clock(key, policy);
24//! let pair = signer.issue(Subject::new("42")?, SessionId::new("session-1")?,
25//! SessionVersion::new(1), Restriction::None)?;
26//! let verified = verifier.verify(&pair.access_token, AuthTokenType::Access)?;
27//! assert_eq!(verified.claims().sub.as_str(), "42");
28//! // Product persists the session before publishing pair, and checks current authorization.
29//! # Ok(())
30//! # }
31//! ```
32#![deny(missing_docs)]
33#![cfg_attr(
34 not(test),
35 deny(
36 clippy::unwrap_used,
37 clippy::unreachable,
38 clippy::expect_used,
39 clippy::panic,
40 clippy::unimplemented,
41 clippy::todo
42 )
43)]
44
45#[cfg(all(feature = "aws-lc-rs", feature = "rust-crypto"))]
46compile_error!(
47 "aster_forge_auth: features `aws-lc-rs` and `rust-crypto` are mutually exclusive; disable default features to select `rust-crypto`"
48);
49#[cfg(not(any(feature = "aws-lc-rs", feature = "rust-crypto")))]
50compile_error!(
51 "aster_forge_auth: select exactly one JWT backend feature: `aws-lc-rs` or `rust-crypto`"
52);
53
54mod coordinator;
55mod error;
56mod ids;
57mod jwt;
58mod provider;
59mod refresh;
60mod time;
61
62pub use coordinator::RefreshCoordinator;
63pub use error::{AuthError, Result};
64pub use ids::{IdSource, RandomIdSource, RefreshJti, SessionId, Subject};
65pub use jwt::{
66 AuthTokenPair, AuthTokenType, JwtAlgorithm, JwtKey, JwtPolicy, JwtSigner, JwtVerifier,
67 Restriction, SessionVersion, TokenClaims, VerifiedToken,
68};
69pub use provider::initialize_jwt_crypto_provider;
70pub use refresh::{
71 ClientContext, RefreshDecision, RefreshError, RefreshOutcome, RefreshPolicy, RefreshRejection,
72 RefreshRotationRequest, RefreshSession, RefreshSessionStore, RefreshStoreOutcome,
73 RefreshTokenService, classify_refresh,
74};
75pub use time::{Clock, FixedClock, SystemClock};
76
77#[cfg(feature = "password")]
78mod password;
79#[cfg(feature = "password")]
80pub use password::*;