Skip to main content

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::*;