axess-core 0.2.0

Core implementation for the axess library. Session state machine, multi-factor authentication engine, Cedar Policy evaluation, and pluggable storage backends. Use the `axess` facade crate unless you need direct access to internals.
Documentation
#![forbid(unsafe_code)]
#![deny(missing_docs)]
#![deny(
    rustdoc::broken_intra_doc_links,
    rustdoc::private_intra_doc_links,
    rustdoc::redundant_explicit_links
)]
// Opt into the nightly `doc(cfg(...))` attribute so docs.rs renders an
// "available on feature `X`" badge on every feature-gated item. The
// `#[cfg_attr(docsrs, doc(cfg(...)))]` tags below are no-ops on stable
// builds; they only activate under docs.rs's `--cfg docsrs` flag (set in
// `[package.metadata.docs.rs]`).
#![cfg_attr(docsrs, feature(doc_cfg))]
//! Core implementation for the Axess authentication and authorization library.
//!
//! # Re-export strategy
//!
//! Public types have one **canonical location** (the module that defines or
//! that owns the canonical re-export from a sibling crate) and may also be
//! convenience-re-exported at the crate root. Adopters can use either path;
//! the canonical path is what `rustdoc` displays. When in doubt, prefer the
//! canonical path in import statements; it survives crate-root churn.
//!
//! | Concern | Canonical | Crate-root convenience |
//! |---------|-----------|-----------------------|
//! | Session state | [`session`]`::*` | (none; depth-2 access only) |
//! | Authn service / state machine | [`authn`]`::*` | (none) |
//! | Authn factor configs | [`authn::factor`]`::*` | (none) |
//! | Authn errors | [`authn::error`]`::*` | (none) |
//! | Authz policy / decision | [`authz`]`::*` | (none) |
//! | Identity (principal, IDs) | [`principal`]`::*` (re-exports `axess-identity`) | (none) |
//! | Clock / RNG (DST foundation) | `axess_clock::*` / `axess_rng::*` | [`Clock`], [`SecureRng`], [`SystemClock`], [`SystemRng`] |
//! | Health checks | [`health`]`::*` | [`HealthCheck`], [`HealthStatus`], [`CompositeHealthCheck`] |
//! | Authn metrics | [`metrics`]`::*` | [`AuthnMetrics`], [`NoopMetrics`] |
//! | Middleware (CSRF, rate-limit, request-id, trace-id) | [`middleware`]`::*` | [`RateLimitLayer`] + helpers; [`RequestIdLayer`] (feature-gated); [`TraceIdLayer`] + [`TraceContext`] (feature-gated) |
//! | Test fixtures | [`testing`]`::*` (gated `cfg(any(test, feature = "testing"))`) | [`MockClock`], [`MockRng`], [`MockIdentityStore`], ... |
//!
//! **Why some types have crate-root convenience and others don't:** the
//! ones promoted to the crate root are either DST primitives that every
//! adopter touches (`Clock`, `SecureRng`) or framework integration points
//! that read naturally as `axess_core::RateLimitLayer`. Authn / authz
//! types stay at depth-2 so the import line reveals *which layer* the
//! type belongs to. Useful when reading a route handler that mixes
//! authn and authz concerns.
//!
//! # Feature flags
//!
//! | Feature | What it enables |
//! |---------|----------------|
//! | `authz` | Cedar Policy authorization (RBAC + ABAC + ReBAC). **On by default.** |
//! | `device` | First-class [`device::Device`] identity with three-stage assurance ladder (`Unknown` → `Seen` → `Trusted`, plus terminal `Revoked`), per-tenant fingerprint pepper, refresh-family cascade, retention sweep, and `CachedDeviceStore` decorator. **On by default.** Pair with `sqlite` / `postgres` / `mysql` / `valkey` for persistent backends ([`SqliteDeviceStore`], [`PostgresDeviceStore`], [`MysqlDeviceStore`], [`ValkeyDeviceStore`]). See [`device`] and [`docs/identity/device.md`](https://github.com/GnomesOfZurich/axess/blob/main/docs/identity/device.md). |
//! | `memory` | In-memory session store and registry (`MemorySessionStore`, `MemorySessionRegistry`). Dev/test only, not in default features. Production builds without this flag cannot import these types. |
//! | `sqlite` | SQLite session store with AES-256-GCM encryption. |
//! | `postgres` | PostgreSQL session store with AES-256-GCM encryption. |
//! | `valkey` | Valkey/Redis session store and registry with optional encryption. |
//! | `fido2` | FIDO2/WebAuthn passkey authentication. |
//! | `oauth` | OAuth 2.0 / OIDC (AuthCode+PKCE, Client Credentials, Device Code). |
//! | `ldap` | LDAP bind authentication (Active Directory, OpenLDAP). |
//! | `request-id` | `X-Request-Id` middleware. |
//! | `trace-id` | W3C Trace Context (`traceparent`) middleware. |
//! | `default-error-response` | Built-in `IntoResponse` mapping for [`AuthnError`] (on by default). Disable to ship your own HTTP mapping; see [`authn::error`] for the recommended status-code table. |
//! | `full` | All of the above. |
//!
//! Internal features (used by the library, not intended for direct use):
//! `accept_client_id`.

// ── Session layer ──────────────────────────────────────────────────────────────

/// Custom tower session layer with HMAC-signed cookies and typed session data.
pub mod session;

pub use session::{
    AuthSession, AuthState, RefreshError, RefreshToken, RefreshTokenConfig, RefreshTokenStore,
    SameSite, SessionBinding, SessionConfig, SessionConfigBuilder, SessionData, SessionId,
    SessionLayer, SessionRegistry, SessionRegistryAdapter, SessionRegistryHandle, SessionRevoker,
    SessionStore, UserAgentBinding,
};
#[cfg(any(test, feature = "memory"))]
pub use session::{MemorySessionRegistry, MemorySessionStore};

// ── Authentication ─────────────────────────────────────────────────────────────

/// Authentication service: identity lookup, factor verification, session management.
pub mod authn;

// ── Device identity ───────────────────────────────────────────────────────────
//
// First-class subsystem (typed `Device` aggregate, three-stage assurance
// ladder, retention sweep, refresh-family cascade, PII tokenisation) rather
// than an authn-flow submodule. Legacy `axess_core::authn::Device*` paths
// continue to resolve via the re-export shim in `authn.rs`.
/// First-class typed `Device` aggregate + three-layer assurance ladder.
#[cfg(feature = "device")]
#[cfg_attr(docsrs, doc(cfg(feature = "device")))]
pub mod device;

pub use authn::{
    AuditContext, AuditQuery, AuthEvent, AuthEventBuilder, AuthEventStatus, AuthEventType,
    AuthMethod, AuthnBackend, AuthnError, AuthnScope, AuthnService, DeviceId, EmailOtpConfig,
    EntityState, EventQueryFilter, FactorConfig, FactorCredential, FactorKind, FactorOutcome,
    FactorStep, FactorStore, FactorTemplate, FederatedProvider, Fido2Config, HotpConfig,
    IdentityAdmin, IdentityAuthnLog, IdentityLookup, IdentityStore, IpPolicy, LdapBindFactorConfig,
    LockoutPolicy, LoginOutcome, NoSessionRegistryError, NoopAuthnLog, OtpAlgorithm,
    PasswordConfig, PasswordRules, PrepareOutcome, ProvisioningError, SessionValidator,
    SignupOutcome, StatusDetail, Tenant, TenantBootstrap, TenantId, TotpConfig, User, UserId,
    ZeroizedString, create_tenant, default_catalog, extract_audit_context,
    extract_audit_context_async, require_valid_session,
};

// ── Federation; external-IdP adapters ───────────────────────────────────────
//
// External-IdP surface collected here: OAuth/OIDC, JWT, mTLS, LDAP, FIDO2,
// PKCE, back-/front-channel logout, federation adapters (K8s SA / GitHub
// Actions / generic OAuth-RS). Each submodule gated on its own per-feature
// flag.
/// External-IdP federation adapters: per-protocol + per-issuer.
pub mod federation;

// ── Authorization ──────────────────────────────────────────────────

#[cfg(feature = "authz")]
#[cfg_attr(docsrs, doc(cfg(feature = "authz")))]
pub mod authz;

#[cfg(feature = "authz")]
#[cfg_attr(docsrs, doc(cfg(feature = "authz")))]
pub use authz::{
    AuthzDecision, AuthzDenied, AuthzEntityProvider, AuthzError, AuthzSession, AuthzStore,
    BuildRequestContext, NoContext, PolicyEvaluator, PolicyStore, StandardRequestContext,
    ip_from_headers, make_action_uid, make_entity_uid,
};

// ── Storage backends (re-exports from session::storage) ────────────────────────
//
// Pluggable storage backends for [`SessionStore`] and authentication state.
// The actual modules live under [`session::storage`]; kept there because
// every backend implements `SessionStore` and/or `SessionRegistry`, both
// session-domain traits. The flat re-exports below preserve the historical
// public API (`axess_core::SqliteSessionStore`, etc.) so downstream code
// importing those types is unaffected by the layout cleanup.

// `in_memory_backend` is gated behind `cfg(any(test, feature = "testing"))`
// in `session.rs`; the re-export must match or non-testing builds fail
// (E0432: unresolved import).
#[cfg(any(test, feature = "testing"))]
pub use session::storage::in_memory_backend::InMemoryBackend;

#[cfg(feature = "sqlite")]
#[cfg_attr(docsrs, doc(cfg(feature = "sqlite")))]
pub use session::storage::sqlite::SqliteSessionStore;

#[cfg(feature = "postgres")]
#[cfg_attr(docsrs, doc(cfg(feature = "postgres")))]
pub use session::storage::postgres::{PostgresSessionStore, PostgresStoreError};

#[cfg(feature = "mysql")]
#[cfg_attr(docsrs, doc(cfg(feature = "mysql")))]
pub use session::storage::mysql::{MysqlSessionStore, MysqlStoreError};

#[cfg(feature = "valkey")]
#[cfg_attr(docsrs, doc(cfg(feature = "valkey")))]
pub use session::storage::valkey::{ValkeySessionRegistry, ValkeySessionStore, ValkeyStoreError};

#[cfg(feature = "ldap")]
#[cfg_attr(docsrs, doc(cfg(feature = "ldap")))]
pub use axess_factors::ldap::{
    LdapBindResult, LdapError, LdapGroupSearch, LdapProvider, LdapProviderConfig, MockLdapProvider,
};

#[cfg(feature = "oauth")]
#[cfg_attr(docsrs, doc(cfg(feature = "oauth")))]
pub use axess_factors::oauth::{
    AuthUrlResult, MockOAuthProvider, OAuthClaims, OAuthError, OAuthLoginOptions, OAuthProvider,
    OAuthProviderConfig, ResponseMode, UserInfoClaims, spawn_jwks_refresh,
};

#[cfg(feature = "fapi")]
#[cfg_attr(docsrs, doc(cfg(feature = "fapi")))]
pub use axess_factors::oauth::{DpopProof, FapiConfig, ParResponse, SenderConstraint};

#[cfg(feature = "device")]
#[cfg_attr(docsrs, doc(cfg(feature = "device")))]
pub use device::{
    AttestationClass, CachedDeviceStore, DefaultFingerprintExtractor, Device, DeviceBinding,
    DeviceEventSink, DeviceFingerprintExtractor, DeviceLifecycleService, DevicePiiCategory,
    DevicePiiMapping, DevicePiiResolver, DevicePiiStore, DeviceResolver, DeviceStore,
    DeviceTrustLevel, FingerprintHash, LifecycleDeviceResolver, MemoryDevicePiiStore,
    MemoryDevicePiiStoreError, MemoryDeviceStore, MemoryDeviceStoreError, NoopDeviceEventSink,
    NoopDeviceResolver, PiiToken, REDACTED_PLACEHOLDER, RedactedResolver, SweepConfig,
    SweepConfigBuilder, SweepCounts, TenantPepperResolver, cascade_revoke_by_refresh_family,
    cascade_revoke_devices,
};

#[cfg(feature = "device")]
#[cfg_attr(docsrs, doc(cfg(feature = "device")))]
pub use authn::service::{StepUpPolicy, StepUpPolicyBuilder, decide_step_up};

#[cfg(all(
    feature = "device",
    any(feature = "sqlite", feature = "postgres", feature = "mysql")
))]
pub use device::storage::SqlDeviceStoreError;

#[cfg(all(feature = "device", feature = "sqlite"))]
pub use device::storage::SqliteDeviceStore;

#[cfg(all(feature = "device", feature = "postgres"))]
pub use device::storage::PostgresDeviceStore;

#[cfg(all(feature = "device", feature = "mysql"))]
pub use device::storage::MysqlDeviceStore;

#[cfg(all(feature = "device", feature = "valkey"))]
pub use device::storage::{ValkeyDeviceStore, ValkeyDeviceStoreError};

// ── Principal abstraction ────────────────────────────────────────────

/// Unified identity abstraction covering humans and workloads.
/// See [`docs/workload-identity/README.md`](https://github.com/GnomesOfZurich/axess/blob/main/docs/workload-identity/README.md).
pub mod principal;

/// Workload identity hub: re-exports inbound resolvers and houses
/// outbound primitives. See [`workload`] module docs.
pub mod workload;

/// On-behalf-of (OBO) access: axess acts *as a user* at a
/// downstream service. Two flow shapes share one conceptual
/// abstraction; see [`delegated::stored`] and [`delegated::exchange`]
/// for the per-flow contracts.
#[cfg(any(feature = "delegated-stored", feature = "delegated-exchange"))]
#[cfg_attr(
    docsrs,
    doc(cfg(any(feature = "delegated-stored", feature = "delegated-exchange")))
)]
pub mod delegated;

pub use principal::{
    AuthHumanPrincipal, AuthPrincipal, AuthWorkloadPrincipal, CliResolver, CliResolverBuilder,
    HumanPrincipal, IdentityError, Issuer, Principal, PrincipalRejection, PrincipalResolver,
    SessionResolver, TrustDomain, WorkloadId, WorkloadPrincipal,
};

#[cfg(feature = "authz")]
#[cfg_attr(docsrs, doc(cfg(feature = "authz")))]
pub use principal::ToCedarEntity;

// ── Shared store abstraction ───────────────────────────────────────────────────

/// Generic key/value-with-TTL store + codec, shared across backend
/// implementations.
pub mod store;

// ── Top-level utilities ────────────────────────────────────────────────────────

/// HTTP cookie parsing helpers (`extract_named_cookie` + caps).
/// Re-exported from [`session::cookies`]; lives next to the session
/// middleware that is its primary consumer.
pub use session::cookies;
/// Composite health-check primitives.
pub mod health;
/// HMAC helpers used by the session-layer signing + CSRF middleware.
/// Re-exported from [`session::hmac`]; lives next to the session
/// middleware that is its primary consumer.
pub use session::hmac;
/// Production-grade in-process IdP: mints workload-identity JWTs
/// against an adopter-supplied [`local_idp::LocalIdpKeyStore`] and
/// exposes JWKS for verifiers. Test counterpart lives at
/// [`testing::local_idp`]. Gated on the `local-idp` feature.
#[cfg(feature = "local-idp")]
#[cfg_attr(docsrs, doc(cfg(feature = "local-idp")))]
pub mod local_idp;
/// `AuthnMetrics` trait + `NoopMetrics` default implementation.
pub mod metrics;
/// Mock authentication/identity stores, deterministic clocks/RNGs,
/// fixture builders, and other test doubles. Gated behind
/// `cfg(any(test, feature = "testing"))` so production builds cannot
/// import them; in-crate tests get them via `cfg(test)`.
#[cfg(any(test, feature = "testing"))]
pub mod testing;
/// Identifier / e-mail / URL validation helpers.
pub mod validation;

pub use axess_clock::{Clock, SystemClock};
pub use axess_rng::{SecureRng, SystemRng};
pub use health::{CompositeHealthCheck, CompositeStatus, HealthCheck, HealthStatus};
pub use metrics::{AuthnMetrics, NoopMetrics};

#[cfg(any(test, feature = "testing"))]
pub use testing::mock_tracing::TracingCapture;

#[cfg(any(test, feature = "testing"))]
pub use testing::{
    MemoryRefreshStoreError, MemoryRefreshTokenStore, MockClock, MockFactorStore,
    MockIdentityStore, MockResolver, MockRng,
};

#[cfg(all(feature = "authz", any(test, feature = "testing")))]
pub use testing::mock_policy::{MockEntityProvider, MockPolicyEvaluator};

// ── Middleware ─────────────────────────────────────────────────────────────────

/// Optional axum/tower middleware: request ID, W3C trace context, rate
/// limiting, CSRF. Renamed from `extras` in (the prior name was
/// meant to signal "outside the core auth flow"; `middleware` is what
/// these actually are).
pub mod middleware;

#[cfg(feature = "request-id")]
#[cfg_attr(docsrs, doc(cfg(feature = "request-id")))]
pub use middleware::request_id::RequestIdLayer;

#[cfg(feature = "trace-id")]
#[cfg_attr(docsrs, doc(cfg(feature = "trace-id")))]
pub use middleware::trace_id::{TraceContext, TraceContextLayer, TraceIdLayer};

pub use middleware::ratelimit::{
    KeyExtractor, RateLimitConfig, RateLimitConfigBuilder, RateLimitLayer,
    RateLimitLoginIdentifier, RateLimitService, RateLimitTenantId, RateLimitUserId,
};

// ── Re-export axum and tracing for macro hygiene ────────────────────────────────

#[doc(hidden)]
pub use axum;
#[doc(hidden)]
pub use tracing;