| Crates.io | ntex-basicauth |
| lib.rs | ntex-basicauth |
| version | 0.3.1 |
| created_at | 2025-07-13 09:12:56.912437+00 |
| updated_at | 2025-11-25 13:09:02.991338+00 |
| description | A Basic Authentication middleware for ntex web framework. |
| homepage | |
| repository | https://github.com/lollipopkit/ntex-basicauth |
| max_upload_size | |
| id | 1750227 |
| size | 142,028 |
A Basic Authentication middleware for the ntex web framework.
default-features = false)json feature)regex feature)timing-safe, enabled by default). Automatic password memory cleanup using zeroize crate (secure-memory, enabled by default)Add the dependency in your Cargo.toml:
[dependencies]
ntex-basicauth = "0"
Enable optional features if needed:
[dependencies]
ntex-basicauth = { version = "0", features = ["bcrypt", "regex"] }
use ntex::web;
use ntex_basicauth::BasicAuthBuilder;
use std::collections::HashMap;
#[ntex::main]
async fn main() -> std::io::Result<()> {
web::HttpServer::new(move || {
let mut users = HashMap::new();
users.insert("admin".to_string(), "secret".to_string());
users.insert("user".to_string(), "password".to_string());
let auth = BasicAuthBuilder::new()
.users(users)
.realm("My Application")
.build()
.expect("Failed to configure authentication");
web::App::new()
.route(
web::scope("/protected")
.wrap(auth)
.route("/", web::get().to(protected_handler)),
)
.route("/public", web::get().to(public_handler))
})
.bind("127.0.0.1:8080")?
.run()
.await
}
async fn protected_handler() -> &'static str {
"This is protected content!"
}
async fn public_handler() -> &'static str {
"This is public content"
}
use ntex_basicauth::{BasicAuthBuilder, PathFilter};
use std::collections::HashMap;
let mut users = HashMap::new();
users.insert("admin".to_string(), "secret".to_string());
let filter = PathFilter::new()
.skip_prefix("/public/")
.skip_exact("/health")
.skip_suffix(".css");
let auth = BasicAuthBuilder::new()
.users(users)
.realm("My Application")
.path_filter(filter)
.log_failures(true)
.max_header_size(4096)
.build()
.unwrap();
Enable the regex feature in Cargo.toml:
[dependencies]
ntex-basicauth = { version = "0", features = ["regex"] }
use ntex_basicauth::{BasicAuthBuilder, PathFilter};
let filter = PathFilter::new()
.skip_regex(r"^/assets/.*\.(js|css|png|jpg)$").unwrap();
let auth = BasicAuthBuilder::new()
.user("admin", "secret")
.path_filter(filter)
.build()
.unwrap();
Enable the bcrypt feature in Cargo.toml:
[dependencies]
ntex-basicauth = { version = "0", features = ["bcrypt"] }
use ntex_basicauth::{BasicAuthBuilder, BcryptUserValidator};
use std::sync::Arc;
let mut validator = BcryptUserValidator::new();
validator.add_user_with_password("admin".to_string(), "secret").unwrap();
let auth = BasicAuthBuilder::new()
.validator(Arc::new(validator))
.realm("My Application")
.build()
.unwrap();
use ntex_basicauth::{UserValidator, Credentials, AuthResult, BasicAuthBuilder};
use std::sync::Arc;
use std::future::Future;
use std::pin::Pin;
struct DatabaseValidator;
impl UserValidator for DatabaseValidator {
fn validate<'a>(
&'a self,
credentials: &'a Credentials,
) -> Pin<Box<dyn Future<Output = AuthResult<bool>> + Send + 'a>> {
Box::pin(async move {
// Replace with your DB logic
Ok(credentials.username == "admin" && credentials.password == "secret")
})
}
}
let auth = BasicAuthBuilder::new()
.validator(Arc::new(DatabaseValidator))
.realm("Custom Realm")
.build()
.unwrap();
Get authenticated user information in the request handler:
use ntex::web;
use ntex_basicauth::{extract_credentials, get_username, is_user};
async fn handler(req: web::HttpRequest) -> web::Result<String> {
if let Some(credentials) = extract_credentials(&req) {
return Ok(format!("User: {}", credentials.username));
}
if let Some(username) = get_username(&req) {
return Ok(format!("Welcome, {}!", username));
}
if is_user(&req, "admin") {
return Ok("Admin access granted".to_string());
}
Ok("Unknown user".to_string())
}
You can use the PathFilter builder for convenient filter creation:
use ntex_basicauth::PathFilter;
let filter = PathFilter::new()
.skip_exact("/health")
.skip_exact("/metrics")
.skip_prefix("/public/")
.skip_suffix(".css")
.skip_suffix(".js");
Use built-in common skip paths for typical web applications (health checks, static assets, etc.):
use ntex_basicauth::{BasicAuthBuilder, PathFilter};
// Create a filter with common web paths
let common_filter = PathFilter::new()
.skip_exact("/health")
.skip_exact("/metrics")
.skip_exact("/favicon.ico")
.skip_prefix("/static/")
.skip_prefix("/assets/")
.skip_suffix(".css")
.skip_suffix(".js")
.skip_suffix(".png")
.skip_suffix(".jpg")
.skip_suffix(".ico");
let auth = BasicAuthBuilder::new()
.user("admin", "secret")
.path_filter(common_filter)
.build()
.unwrap();
When authentication fails, the middleware returns HTTP 401 status code and corresponding error information:
{
"code": 401,
"message": "Authentication required",
"error": "Invalid credentials"
}
Error types include:
MissingHeader - Missing Authorization headerInvalidFormat - Invalid Authorization header formatInvalidBase64 - Invalid Base64 encodingInvalidCredentials - Invalid user credentialsValidationFailed - User validation faileduse ntex_basicauth::{BasicAuthBuilder, CacheConfig, PathFilter};
use std::time::Duration;
// Production-ready configuration with security hardening
let cache_config = CacheConfig::new()
.max_size(1000)
.ttl_minutes(10)
.cleanup_interval_seconds(300);
// Common paths to skip authentication
let skip_paths = PathFilter::new()
.skip_exact("/health")
.skip_exact("/metrics")
.skip_prefix("/static/")
.skip_suffix(".css")
.skip_suffix(".js");
let auth = BasicAuthBuilder::new()
.users_from_file("users.txt") // Load users from file
.realm("Production API")
.with_cache(cache_config)
.max_concurrent_validations(100) // Prevent resource exhaustion
.validation_timeout(Duration::from_secs(30))
.rate_limit_per_ip(10, Duration::from_secs(60)) // 10 req/min per IP
.log_usernames_in_production(false) // Security: no username logging
.path_filter(skip_paths) // Skip health checks, assets
.build()
.unwrap();
secure-memory feature (enabled by default) automatically clears password data from memory after uselog_usernames_in_production(false) to prevent username leakage in production logsCache is enabled by default (unless disabled via builder/config):
use ntex_basicauth::{BasicAuthBuilder, CacheConfig};
// High-traffic configuration
let cache_config = CacheConfig::new()
.max_size(10000) // Large cache for busy servers
.ttl_minutes(5) // Short TTL for security
.cleanup_interval_seconds(60) // Frequent cleanup
.enable_stats(true); // Monitor cache performance
let auth = BasicAuthBuilder::new()
.user("admin", "secret")
.with_cache(cache_config)
.build()
.unwrap();
Licensed under the MIT License. See LICENSE for details.