axum-login
🪪 User identification, authentication, and authorization for Axum.
🎨 Overview
This crate provides user identification, authentication, and authorization
as a tower middleware for axum.
It offers:
- User Identification, Authentication, and Authorization: Leverage
AuthSessionto easily manage authentication and authorization. This is also an extractor, so it can be used directly in youraxumhandlers. - Support for Arbitrary Users and Backends: Applications implement a
couple of traits,
AuthUserandAuthnBackend, allowing for any user type and any user management backend. Your database? Yep. LDAP? Sure. An auth provider? You bet. - User and Group Permissions: Authorization is supported via the
AuthzBackendtrait, which allows applications to define custom permissions. Both user and group permissions are supported. - Convenient Route Protection: Middleware for protecting access to
routes is available via the
login_requiredandpermission_requiredmacros, and via therequirebuilder (require-builderfeature). The builder is the long-term primary surface; macros are convenience wrappers over the same behavior. - Rock-solid Session Management: Uses
tower-sessionsfor high-performing and ergonomic session management. Look ma, no deadlocks!
📦 Install
To use the crate in your project, add the following to your Cargo.toml file:
[dependencies] axum-login = "0.18.0"
🤸 Usage
We recommend reviewing our sqlite example. There is also a template for cargo-generate using postgres.
Builder quick start
use axum_login::require::{RedirectHandler, Require}; use axum_login::{AuthUser, AuthnBackend, UserId}; #[derive(Clone, Debug)] struct User; impl AuthUser for User { type Id = i64; fn id(&self) -> Self::Id { 0 } fn session_auth_hash(&self) -> &[u8] { &[] } } #[derive(Clone)] struct Backend; impl AuthnBackend for Backend { type User = User; type Credentials = (); type Error = std::convert::Infallible; async fn authenticate( &self, _: Self::Credentials, ) -> Result<Option<Self::User>, Self::Error> { Ok(Some(User)) } async fn get_user( &self, _: &UserId<Self>, ) -> Result<Option<Self::User>, Self::Error> { Ok(Some(User)) } } let require = Require::<Backend>::builder() .unauthenticated(RedirectHandler::new().login_url("/login")) .build();
You can customize access logic with .decision(...), which receives an
AuthSession plus Arc<state> when you build with shared state.
✅ Behavior Contract
The middleware surfaces follow the same contract:
- If the request is unauthenticated, the unauthenticated handler is used.
- If the request is authenticated but not authorized, the unauthorized handler is used.
- Redirect fallbacks preserve explicit redirect query parameters if already present and otherwise append the configured redirect field.
- Redirect construction errors return
500 Internal Server Error.
🧩 Feature Flags
require-builder: Enables the builder-basedrequiremodule, which is the primary middleware surface.macros-middleware: Enables thelogin_required!andpermission_required!macros. These are convenience wrappers over the builder and are enabled by default.
Example (builder only, no macros):
[dependencies] axum-login = { version = "0.18.0", default-features = false, features = ["require-builder"] }
🦺 Safety
This crate uses #![forbid(unsafe_code)] to ensure everything is implemented in 100% safe Rust.
🛟 Getting Help
We've put together a number of examples to help get you started. You're also welcome to open a discussion and ask additional questions you might have.
👯 Contributing
We appreciate all kinds of contributions, thank you!