pub struct AuthSession(/* private fields */);Expand description
Axum request extractor providing typed, mutable session access.
Zero generic parameters: wraps the SessionHandle inserted by SessionLayer.
Obtain one in a handler by listing it as a parameter:
async fn my_handler(session: AuthSession) -> impl IntoResponse { ... }Changes are committed to the store automatically when the response is sent.
Implementations§
Source§impl AuthSession
impl AuthSession
Sourcepub async fn is_authenticated(&self) -> bool
pub async fn is_authenticated(&self) -> bool
Return true if the session is fully authenticated.
Sourcepub async fn auth_state(&self) -> AuthState
pub async fn auth_state(&self) -> AuthState
Clone the current authentication state enum (cheap; fields are Arc<str>).
Sourcepub async fn authenticating_state(
&self,
) -> Option<(UserId, TenantId, Vec<FactorKind>)>
pub async fn authenticating_state( &self, ) -> Option<(UserId, TenantId, Vec<FactorKind>)>
Destructure an AuthState::Authenticating session into its
(user_id, tenant_id, remaining_factors) triple. Returns None
for any other AuthState variant (Guest / Identifying /
Authenticated / PendingWorkflow).
Service-side callers in the multi-factor pipeline (begin_login,
prepare_factor, verify_factor) all need this triple to make
progress and treat any other state as the canonical
AuthnError::NoFlow,
typically session.authenticating_state().await.ok_or(AuthnError::NoFlow)?.
This destructuring was lifted out of AuthnService because it
has no service dependency; it belongs alongside the other
session-state accessors here.
Single-acquisition: the read lock is taken once and the entire
triple is built under it, matching snapshot’s
shape rather than the older “auth_state().await then match”
pattern that incurred two lock acquisitions and an extra
AuthState::clone.
Sourcepub async fn session_id(&self) -> SessionId
pub async fn session_id(&self) -> SessionId
Return the session ID.
Sourcepub async fn device_id(&self) -> Option<DeviceId>
pub async fn device_id(&self) -> Option<DeviceId>
Return the resolved crate::authn::ids::DeviceId for this session, if the device
subsystem populated it. None when the device feature is
disabled, when the resolver did not run for this request, or when
the request did not match a known device.
Single-acquisition read; cheap when the device subsystem is in
use because DeviceId is a 16-byte Copy UUID newtype.
Sourcepub async fn data(&self) -> SessionData
pub async fn data(&self) -> SessionData
Return a clone of the full session data.
Sourcepub async fn with_auth_state<F, T>(&self, f: F) -> T
pub async fn with_auth_state<F, T>(&self, f: F) -> T
Invoke f against a borrow of the current AuthState
without cloning. Use this when the caller only needs to read a
few fields. Avoids the full AuthState::clone() that
auth_state performs (which clones every
Arc<str> plus the workflow state). For AuthState::Authenticated
in particular this halves the per-request lock-held work in
authenticated handlers that just need the user id.
The closure runs while the session read lock is held, so do not
await inside it on something that needs the same lock.
Sourcepub async fn with_data<F, T>(&self, f: F) -> Twhere
F: FnOnce(&SessionData) -> T,
pub async fn with_data<F, T>(&self, f: F) -> Twhere
F: FnOnce(&SessionData) -> T,
Invoke f against a borrow of the full SessionData
without cloning. Useful when reading several fields together,
where data() would copy more than necessary. Same lock-held
caveat as with_auth_state.
Sourcepub async fn snapshot(&self) -> Option<AuthSnapshot>
pub async fn snapshot(&self) -> Option<AuthSnapshot>
Read all the common identity fields under a single
read-lock acquisition. The previous pattern of calling
is_authenticated() then user_id() then tenant_id() then
session_id() from a typical authenticated handler took four
RwLock reads per request: most contention-free, but each is a
cross-await synchronization point. snapshot() collapses them
into one acquisition.
Returns None when the session is not authenticated.
Sourcepub async fn set_authenticated(
&self,
user_id: UserId,
tenant_id: TenantId,
authn_time: DateTime<Utc>,
)
pub async fn set_authenticated( &self, user_id: UserId, tenant_id: TenantId, authn_time: DateTime<Utc>, )
Mark the session as fully authenticated.
Cycles the session id eagerly so handler code that subsequently calls
session.session_id().await (e.g. to register against a
SessionRegistry) reads the post-rotation id, the same id the
cookie will carry on the next request.
Sourcepub async fn set_identifying(&self, user_id: UserId, tenant_id: TenantId)
pub async fn set_identifying(&self, user_id: UserId, tenant_id: TenantId)
Enter the identifying state (user has typed their username).
Binds the session fingerprint early so that even pre-MFA sessions are protected against cross-device replay.
Sourcepub async fn set_pending_workflow(
&self,
user_id: UserId,
tenant_id: TenantId,
workflow: WorkflowState,
)
pub async fn set_pending_workflow( &self, user_id: UserId, tenant_id: TenantId, workflow: WorkflowState, )
Transition to a pending workflow state.
Sourcepub async fn clear(&self)
pub async fn clear(&self)
Clear the session (logout). Resets state to Guest and marks as modified.
The caller should regenerate the session ID separately to prevent session fixation.
Sourcepub async fn regenerate(&self)
pub async fn regenerate(&self)
Cycle the session ID immediately.
Mints a new id, swaps it in, and stashes the old id for the layer to
store.cycle on the way out. Idempotent within a single request;
calling twice still rotates only once.
Call at any privilege boundary; i.e. any change to the session’s authentication context, scope, or subject identity. Login is already auto-cycled; the rest is the app’s call. Canonical list (OWASP ASVS V3, OWASP Session Management Cheat Sheet, NIST SP 800-63B AAL transitions):
- MFA factor added (TOTP, WebAuthn, recovery codes, …)
- MFA factor removed or disabled (AAL drops)
- Password / primary-credential change
- Step-up to a higher assurance level
- Account-recovery flow completion
- Impersonation start / stop
- Role grant / revoke or scope change
- Tenant switch in a multi-tenant deployment
Do not call on routine writes (profile edit, factor config tuning, theme change); rotating churns the cookie and the store without any security benefit.
On credential changes (password change, recovery completion)
consider also revoking sibling sessions via
SessionRegistry::revoke_user_sessions; that is a strictly
stronger statement than rotation and cuts off other devices
still holding a stale credential-derived cookie.
See docs/sessions/lifecycle.md for the full rationale and
the “library can’t hook this for you” discussion.
Sourcepub async fn get_custom(&self, key: &str) -> Option<Value>
pub async fn get_custom(&self, key: &str) -> Option<Value>
Read a value from the custom JSON bag.
Sourcepub async fn clear_custom(&self)
pub async fn clear_custom(&self)
Wipe the entire custom JSON bag in one shot. Used at privilege
boundaries (e.g., admin impersonation) where the previous session’s
app-controlled custom data must not leak into the assumed identity:
pre-seeded OAuth ceremony state in custom could otherwise be used
to hijack a subsequent OAuth flow under the new principal.
Sourcepub async fn remove_custom(&self, key: &str) -> bool
pub async fn remove_custom(&self, key: &str) -> bool
Remove a key from the custom JSON bag. Returns true if a key was
removed. Use this rather than set_custom(k, Value::Null) so the
JSON object stays compact; repeated nulled-out keys would otherwise
monotonically grow until the size cap clears the whole bag.
Sourcepub async fn mutate_custom<F, T>(&self, f: F) -> T
pub async fn mutate_custom<F, T>(&self, f: F) -> T
Run f against a mutable borrow of the custom-bag JSON
object under a single write-lock acquisition. Returns the value
produced by f. Marks the session modified if f actually
mutated the bag (judged by JSON-byte-length comparison).
Use this in place of a series of remove_custom/set_custom
calls when several edits must appear atomic to a concurrent
reader. The original sequence in clear_oauth_state issued six
independent remove_custom calls; a parallel set_custom racing
in between could re-introduce a key after it had already been
removed.
f runs while the write lock is held; do not await inside it
on something that needs the same lock.
Sourcepub async fn take_custom(&self, key: &str) -> Option<Value>
pub async fn take_custom(&self, key: &str) -> Option<Value>
Atomically read and remove a key from the custom JSON bag.
Returns the removed value, or None if the key was absent. The
read and the remove run under a single write lock; use this in
preference to get_custom(k).await followed by remove_custom(k)
for any one-shot ceremony state (FIDO2 auth_state, OAuth PKCE
verifier, password-reset token, etc.) where two parallel
requests must not both observe the same value.
Trait Implementations§
Source§impl AuthSessionTestExt for AuthSession
Available on crate features testing only.
impl AuthSessionTestExt for AuthSession
testing only.Source§async fn set_authenticated(
&self,
user_id: UserId,
tenant_id: TenantId,
authn_time: DateTime<Utc>,
)
async fn set_authenticated( &self, user_id: UserId, tenant_id: TenantId, authn_time: DateTime<Utc>, )
AuthState::Authenticated.Source§async fn begin_authenticating(
&self,
user_id: UserId,
tenant_id: TenantId,
method_name: Arc<str>,
factors: Vec<FactorKind>,
)
async fn begin_authenticating( &self, user_id: UserId, tenant_id: TenantId, method_name: Arc<str>, factors: Vec<FactorKind>, )
AuthState::Authenticating
with the given factor sequence.Source§async fn advance_factor(&self, kind: &FactorKind, authn_time: DateTime<Utc>)
async fn advance_factor(&self, kind: &FactorKind, authn_time: DateTime<Utc>)
remaining queue and transitioning
to AuthState::Authenticated
when empty.Source§async fn record_attempt_at(&self, now: DateTime<Utc>)
async fn record_attempt_at(&self, now: DateTime<Utc>)
Source§impl Clone for AuthSession
impl Clone for AuthSession
Source§fn clone(&self) -> AuthSession
fn clone(&self) -> AuthSession
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl<S> FromRequestParts<S> for AuthSession
impl<S> FromRequestParts<S> for AuthSession
Auto Trait Implementations§
impl Freeze for AuthSession
impl !RefUnwindSafe for AuthSession
impl Send for AuthSession
impl Sync for AuthSession
impl Unpin for AuthSession
impl UnsafeUnpin for AuthSession
impl !UnwindSafe for AuthSession
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> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<S, T> FromRequest<S, ViaParts> for T
impl<S, T> FromRequest<S, ViaParts> for T
Source§type Rejection = <T as FromRequestParts<S>>::Rejection
type Rejection = <T as FromRequestParts<S>>::Rejection
Source§fn from_request(
req: Request<Body>,
state: &S,
) -> impl Future<Output = Result<T, <T as FromRequest<S, ViaParts>>::Rejection>>
fn from_request( req: Request<Body>, state: &S, ) -> impl Future<Output = Result<T, <T as FromRequest<S, ViaParts>>::Rejection>>
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.