1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
//! # modo::auth::role
//!
//! Role-based gating for axum applications.
//!
//! Roles-only — permission checks beyond "does this role match?" belong
//! in handler logic.
//!
//! Provides:
//!
//! - [`RoleExtractor`] — trait to resolve the current user's role from a request.
//! - [`middleware()`] — Tower layer that calls your extractor and stores [`Role`] in extensions.
//! - [`Role`] — newtype extractor over `String`; pull the resolved role into handlers.
//!
//! Route-level gating layers (`require_role`, `require_authenticated`) live in
//! [`crate::auth::guard`]. This module only resolves the role; `auth::guard`
//! compares it against an allow-list.
//!
//! # Wiring order
//!
//! The role middleware must be applied with `.layer()` on the outer router so it runs
//! before any guard. Guards must be applied with `.route_layer()` so they execute after
//! route matching and can find the `Role` already in extensions.
//!
//! ```rust,no_run
//! use axum::{Router, routing::get};
//! use modo::auth::{guard, role::{self, RoleExtractor}};
//! use modo::Result;
//!
//! struct MyExtractor;
//!
//! impl RoleExtractor for MyExtractor {
//! async fn extract(&self, _parts: &mut http::request::Parts) -> Result<String> {
//! Ok("admin".to_string())
//! }
//! }
//!
//! let app: Router = Router::new()
//! .route("/admin", get(|| async { "ok" }))
//! .route_layer(guard::require_role(["admin", "owner"]))
//! .layer(role::middleware(MyExtractor));
//! ```
pub use Role;
pub use middleware;
pub use RoleExtractor;