pub enum AuthnError<E: Error + Send + Sync + 'static> {
Store(E),
NoFlow,
NotActive(EntityState),
Locked {
until: Option<DateTime<Utc>>,
},
InvalidAssertion,
ExternalService(String),
CrossTenant,
}Expand description
Errors that can occur during authentication flows.
Parameterised over the backend error type E so that storage errors are
propagated with their original type rather than being erased.
§Suggested HTTP status code mapping
| Variant | HTTP Status | Rationale |
|---|---|---|
Store | 500 Internal Server Error | Backend / database failure; not the client’s fault. |
NoFlow | 409 Conflict | No active authentication flow in the session; client must start one first. |
NotActive | 403 Forbidden | Account exists but is disabled, suspended, or otherwise ineligible. |
Locked | 423 Locked | Account locked due to too many failed attempts; retry after cooldown. |
InvalidAssertion | 401 Unauthorized | FIDO2 cryptographic validation failed; credential rejected. |
ExternalService | 502 Bad Gateway | Upstream provider (LDAP, OAuth IdP) returned an error or timed out. |
These are suggestions for handler authors. The library does not convert errors to HTTP responses automatically; that mapping belongs in your application’s error-handling layer.
Variants§
Store(E)
An error from the underlying identity or factor store.
NoFlow
No active authentication flow found in the session.
Returned by verify_factor when the session is not in Authenticating state.
NotActive(EntityState)
The account exists but is not in a state that permits login.
Locked
The account is locked (suspension or accumulated failed attempts).
Returned by:
prepare_factorwhenaccount_statusreportsSuspended.- FIDO2
finish_discoverable_loginwhen the lockout threshold is reached during a discoverable assertion’s failure path.
until is the suspension expiry when known (for Suspended
accounts whose StatusDetail.until is set), None for
indefinite locks or for the failed-attempt lockout (which has
no inherent expiry: an admin must reset). Use
lockout_expiry for one-call access
that also handles the legacy
NotActive(EntityState::Suspended(_)) case.
Callers should display a generic “account locked” message
(rendering until if present and non-trivial) rather than
distinguishing failed-attempt vs admin-suspension reasons;
that distinction is operator-visible via the audit log,
never a property of the error response.
InvalidAssertion
A FIDO2/WebAuthn assertion or registration failed validation.
Distinct from NoFlow (no ceremony in progress): this means a
ceremony was in progress but the cryptographic validation failed.
ExternalService(String)
An external service (LDAP, OAuth IdP, etc.) failed with a non-credential error (connection timeout, network issue, etc.).
Callers should treat this as a transient failure and may retry or show a “service unavailable” message, not “invalid credentials”.
CrossTenant
A tenant-scoped operation was invoked against a target whose
tenant_id does not match the caller-supplied expected tenant.
Returned by the _in_tenant family of methods on AuthnService
(e.g. suspend_user_in_tenant, activate_user_in_tenant,
begin_impersonation_in_tenant) when the structural rail
fires. Suggested HTTP status: 403 Forbidden (the caller is
authenticated but operating outside their authorised scope).
Treat audit logging of this variant as security-relevant; it almost always indicates either a buggy admin UI or an attempted cross-tenant pivot.
Implementations§
Source§impl<E: Error + Send + Sync + 'static> AuthnError<E>
impl<E: Error + Send + Sync + 'static> AuthnError<E>
Sourcepub fn lockout_expiry(&self) -> Option<DateTime<Utc>>
pub fn lockout_expiry(&self) -> Option<DateTime<Utc>>
Return the lockout expiry timestamp when this error represents
a locked account, regardless of whether the lock surfaces as
AuthnError::Locked or as AuthnError::NotActive(EntityState::Suspended(_)).
Returns None for indefinite locks, for failed-attempt
lockouts (which have no inherent expiry), and for any
non-lock error variant. Use this from UI code that wants to
render “try again at X” without distinguishing the two error
shapes: both a prepare_factor Suspended-account rejection
and a FIDO2 discoverable-login lockout collapse to a single
Option<DateTime<Utc>> lookup.
Saves callers from deep-pattern-matching
EntityState::Suspended(StatusDetail { until, .. }) and
handling the AuthnError::Locked { until } shape separately;
both legs collapse to one call.
Source§impl<E: Error + Send + Sync + 'static> AuthnError<E>
Default IntoResponse mapping for AuthnError.
impl<E: Error + Send + Sync + 'static> AuthnError<E>
Default IntoResponse mapping for AuthnError.
Gated behind the default-error-response feature because mapping a
library error to an HTTP response is policy that belongs to the
application: status code, body shape, locale, correlation IDs, and
problem+json formatting are all things callers may want to override.
The doc table on AuthnError documents the recommended mapping for
applications that ship their own impl.
Enable with axess-core = { features = ["default-error-response"] }
to get the conservative default below.
Sourcepub fn into_response_at(self, now: DateTime<Utc>) -> Response
Available on crate feature default-error-response only.
pub fn into_response_at(self, now: DateTime<Utc>) -> Response
default-error-response only.IntoResponse-shaped conversion taking the reference time
explicitly. Test code with MockClock
uses this to pin the Retry-After header against a controllable
clock; the trait impl below delegates here with Utc::now()
for production callers, which produces wall-clock behaviour
that’s correct but non-deterministic across runs.
Adopters who don’t enable the default-error-response feature
can still construct their own IntoResponse impl on top of
this helper without forking the body/status logic.
Trait Implementations§
Source§impl<E> Display for AuthnError<E>
impl<E> Display for AuthnError<E>
Source§impl<E> Error for AuthnError<E>
impl<E> Error for AuthnError<E>
Source§fn source(&self) -> Option<&(dyn Error + 'static)>
fn source(&self) -> Option<&(dyn Error + 'static)>
1.0.0 · Source§fn description(&self) -> &str
fn description(&self) -> &str
use the Display impl or to_string()
Source§impl<E: Error + Send + Sync + 'static> IntoResponse for AuthnError<E>
Available on crate feature default-error-response only.
impl<E: Error + Send + Sync + 'static> IntoResponse for AuthnError<E>
default-error-response only.Source§fn into_response(self) -> Response
fn into_response(self) -> Response
Delegates to AuthnError::into_response_at with chrono::Utc::now()
as the reference time. Production-correct but non-deterministic;
tests asserting on Retry-After should call into_response_at
directly with a MockClock-derived timestamp.
Auto Trait Implementations§
impl<E> Freeze for AuthnError<E>where
E: Freeze,
impl<E> RefUnwindSafe for AuthnError<E>where
E: RefUnwindSafe,
impl<E> Send for AuthnError<E>
impl<E> Sync for AuthnError<E>
impl<E> Unpin for AuthnError<E>where
E: Unpin,
impl<E> UnsafeUnpin for AuthnError<E>where
E: UnsafeUnpin,
impl<E> UnwindSafe for AuthnError<E>where
E: UnwindSafe,
Blanket Implementations§
Source§impl<T> ArchivePointee for T
impl<T> ArchivePointee for T
Source§type ArchivedMetadata = ()
type ArchivedMetadata = ()
Source§fn pointer_metadata(
_: &<T as ArchivePointee>::ArchivedMetadata,
) -> <T as Pointee>::Metadata
fn pointer_metadata( _: &<T as ArchivePointee>::ArchivedMetadata, ) -> <T as Pointee>::Metadata
Source§impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere
T: 'a,
impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere
T: 'a,
Source§impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere
T: 'a,
impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere
T: 'a,
Source§impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere
T: 'a,
impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere
T: 'a,
Source§impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere
T: 'a,
impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere
T: 'a,
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§impl<T> LayoutRaw for T
impl<T> LayoutRaw for T
Source§fn layout_raw(_: <T as Pointee>::Metadata) -> Result<Layout, LayoutError>
fn layout_raw(_: <T as Pointee>::Metadata) -> Result<Layout, LayoutError>
Source§impl<T, N1, N2> Niching<NichedOption<T, N1>> for N2
impl<T, N1, N2> Niching<NichedOption<T, N1>> for N2
Source§unsafe fn is_niched(niched: *const NichedOption<T, N1>) -> bool
unsafe fn is_niched(niched: *const NichedOption<T, N1>) -> bool
Source§fn resolve_niched(out: Place<NichedOption<T, N1>>)
fn resolve_niched(out: Place<NichedOption<T, N1>>)
out indicating that a T is niched.Source§impl<T> Pointable for T
impl<T> Pointable for T
Source§impl<T> PolicyExt for Twhere
T: ?Sized,
impl<T> PolicyExt for Twhere
T: ?Sized,
Source§impl<T> ToStringFallible for Twhere
T: Display,
impl<T> ToStringFallible for Twhere
T: Display,
Source§fn try_to_string(&self) -> Result<String, TryReserveError>
fn try_to_string(&self) -> Result<String, TryReserveError>
ToString::to_string, but without panic on OOM.