axum-login makes your Axum session the thing handlers read
🪪 User identification, authentication, and authorization for Axum.
At a glance
- What is it?
- axum-login is a Rust crate that provides identification, authentication and authorization for Axum as a tower middleware, with two traits you implement and a builder that decides what happens to an unauthenticated or unauthorized request. Version 0.18 makes the builder the primary surface and demotes the login_required and permission_required macros to wrappers over it.
- Who is it for?
- Adopt axum-login if you are writing an Axum service that needs sessions and route protection and you want to supply your own user type and backend, since the crate asks for two trait implementations and takes care of the middleware, the extractor and the session handling around them. Do not adopt it if you need a specific protocol out of the box, because there is no OAuth flow in the core; the oauth2 example is an example, not a feature.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 127 days ago.
- What is it written in?
- Mainly Rust, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Two traits and you have a login system
The crate provides user identification, authentication and authorization as a tower middleware for axum, and the design is that the application supplies the parts it knows about. You implement `AuthUser` for your user type, which gives the crate an id and a session auth hash, and `AuthnBackend` for the thing that looks users up, which gives it an `authenticate` method and a `get_user` method. The backend is generic over the user type, the credentials type and the error type, so a database, LDAP or an external auth provider all fit the same shape. The README puts it plainly: your database, LDAP, sure, an auth provider, you bet. Once those are in place, `AuthSession` handles the session, and it is also an extractor, so a handler can take it directly and ask who the user is.
The builder is now the primary surface
This is the recent structural change and it is worth knowing before you read any example. The `require` builder is described as the long-term primary surface, and the `login_required!` and `permission_required!` macros are convenience wrappers over the same behaviour. The quick start shows what that looks like:
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] {
&[]
}
}The access logic itself is a method on the builder. You set what happens to an unauthenticated request, in this case a redirect to the login page, and you can customise the decision logic with `.decision(...)`, which receives an `AuthSession` plus `Arc<state>` when you build with shared state. The examples in the repository are the practical reference, with separate directories for sqlite, permissions, oauth2 and multi-auth, and there is a cargo-generate template for a Postgres setup.
Authorization is a trait, not a config file
Authorization is supported through the `AuthzBackend` trait, which lets an application define its own permissions, and both user and group permissions are supported. The distinction between the two traits is the useful part of the design. `AuthnBackend` answers whether this is a valid user and can this credential become one, which is a yes or no question about identity. `AuthzBackend` answers whether this identified user may do this thing, which is a question about policy, and the policy is the part that differs between applications. Keeping them separate means a single authentication mechanism can serve several authorization schemes, and the group support means permissions can attach to a group rather than to each user individually. In a corporate application that is the difference between a permission list per user and a role system.
The behaviour contract is written down
The middleware surfaces follow a contract that the documentation states in four rules, and it is worth reading before you configure the redirect handlers, because the query parameter behaviour is the fiddly part. If the request is unauthenticated, the unauthenticated handler is used. If the request is authenticated but not authorized, the unauthorized handler is used, which is a different code path from the first and the one people forget to configure. Redirect fallbacks preserve explicit redirect query parameters if they are already present, and otherwise append the configured redirect field, so a value already present is kept. Redirect construction errors return 500 Internal Server Error, which is the honest answer when the configured login URL cannot be turned into a valid redirect.
Feature flags decide how much surface you get
There are two feature flags and they are worth reading carefully, because one of them changes the default. `require-builder` enables the builder-based `require` module, which is the primary middleware surface. `macros-middleware` enables the `login_required!` and `permission_required!` macros, which are convenience wrappers over the builder and are enabled by default. If you want the builder only and no macros, you turn the defaults off:
[dependencies]
axum-login = { version = "0.18.0", default-features = false, features = ["require-builder"] }The plain install is a single line with the version pinned, `axum-login = "0.18.0"`. The reason to disable the macros is that they are a convenience over a builder, and a codebase that has committed to the builder can drop the extra dependency surface and the extra syntax. Since the macros are wrappers rather than a parallel implementation, the behaviour is the same either way.
Sessions come from tower-sessions, and the crate is forbid-unsafe
Session management is delegated to tower-sessions, which is a separate crate by the same author, and the README describes it as high-performing and ergonomic with the note that there are no deadlocks. That is a meaningful design choice for an authentication library, since the classic failure mode of a session layer in an async runtime is a lock held across an await point. The crate also declares `#![forbid(unsafe_code)]`, so everything in it is implemented in safe Rust, and that is enforced at compile time rather than by convention. The repository is a Cargo workspace with the crate itself as the default member and the examples as workspace members, and the top level also holds a rustfmt.toml, a CHANGELOG.md and an AGENTS.md. The licence is MIT.
Editorial conclusion
Adopt axum-login if you are writing an Axum service that needs sessions and route protection and you want to supply your own user type and backend, since the crate asks for two trait implementations and takes care of the middleware, the extractor and the session handling around them. Do not adopt it if you need a specific protocol out of the box, because there is no OAuth flow in the core; the oauth2 example is an example, not a feature. Verify first which features you want, since the builder and the macros are separate feature flags, and read the behaviour contract before wiring the redirect handlers, because the query parameter handling has specific rules.
Frequently asked questions
What does axum-login provide?
User identification, authentication and authorization for axum as a tower middleware, with `AuthSession` managing the session and also working as an extractor that handlers can take directly. Route protection is available through the `require` builder and through the `login_required!` and `permission_required!` macros.
Which traits do I implement to use axum-login?
`AuthUser` for your user type, giving the crate an id and a session auth hash, and `AuthnBackend` for looking users up, giving it `authenticate` and `get_user`. Authorization is a separate concern handled by the `AuthzBackend` trait, and both user and group permissions are supported.
How do I install axum-login?
Add `axum-login = "0.18.0"` to the dependencies in your Cargo.toml. To use the builder without the macros, set `default-features = false` and enable only `require-builder`.
What happens when a request is not authenticated or not authorized?
An unauthenticated request goes to the unauthenticated handler, and an authenticated but unauthorized request goes to the unauthorized handler. Redirect fallbacks keep any explicit redirect query parameter that is already present and otherwise append the configured redirect field, and a redirect that cannot be constructed returns 500 Internal Server Error.
Which session backend does axum-login use?
It uses tower-sessions, a separate crate by the same author, for session management. The crate itself is written with `#![forbid(unsafe_code)]`, so everything in it is safe Rust.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/maxcountryman-axum-login)Was this useful?