HTTP Basic Authentication
HTTP Basic Authentication sends credentials in the Authorization header.
How It Works
Authorization: Basic base64(username:password)
Example:
Authorization: Basic YWRtaW46YWRtaW4= // admin:admin
Enabling HTTP Basic
Configure your authorizer to use HTTP Basic:
use actix_security::http::security::AuthorizationManager;
let authorizer = AuthorizationManager::request_matcher()
.http_basic() // Enable HTTP Basic
.login_url("/login");
Full Example
use actix_web::{get, App, HttpServer, HttpResponse, Responder};
use actix_security::secured;
use actix_security::http::security::{
AuthenticatedUser, AuthenticationManager, AuthorizationManager,
Argon2PasswordEncoder, PasswordEncoder, User,
};
use actix_security::http::security::middleware::SecurityTransform;
#[secured("USER")]
#[get("/api/data")]
async fn get_data(user: AuthenticatedUser) -> impl Responder {
HttpResponse::Ok().body(format!("Data for {}", user.get_username()))
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
let encoder = Argon2PasswordEncoder::new();
HttpServer::new(move || {
let enc = encoder.clone();
App::new()
.wrap(
SecurityTransform::new()
.config_authenticator(move || {
AuthenticationManager::in_memory_authentication()
.password_encoder(enc.clone())
.with_user(
User::with_encoded_password("api_user", enc.encode("api_secret"))
.roles(&["USER".into()])
)
})
.config_authorizer(|| {
AuthorizationManager::request_matcher()
.http_basic() // Enable HTTP Basic
})
)
.service(get_data)
})
.bind("127.0.0.1:8080")?
.run()
.await
}
Testing with cURL
# Using -u flag (automatic base64 encoding)
curl -u api_user:api_secret http://127.0.0.1:8080/api/data
# Manual header
curl -H "Authorization: Basic YXBpX3VzZXI6YXBpX3NlY3JldA==" http://127.0.0.1:8080/api/data
Testing in Rust
use actix_web::test;
use base64::prelude::*;
fn basic_auth(username: &str, password: &str) -> String {
let credentials = format!("{}:{}", username, password);
format!("Basic {}", BASE64_STANDARD.encode(credentials))
}
#[actix_web::test]
async fn test_http_basic() {
let app = create_test_app().await;
let req = test::TestRequest::get()
.uri("/api/data")
.insert_header(("Authorization", basic_auth("api_user", "api_secret")))
.to_request();
let resp = test::call_service(&app, req).await;
assert_eq!(resp.status(), StatusCode::OK);
}
401 Response
When authentication fails, the server returns:
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Basic realm="Restricted"
Security Considerations
Use HTTPS
HTTP Basic sends credentials in base64 encoding (not encryption). Always use HTTPS in production.
// In production, bind to HTTPS
HttpServer::new(|| App::new())
.bind_openssl("0.0.0.0:443", ssl_builder)?
.run()
.await
Consider Token-Based Auth
For APIs, consider using:
- JWT tokens
- API keys
- OAuth2
HTTP Basic is simple but has limitations:
- Credentials sent with every request
- No built-in expiration
- Harder to revoke access
Spring Security Comparison
Spring Security:
@Configuration
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.httpBasic(Customizer.withDefaults())
.authorizeHttpRequests(auth -> auth
.anyRequest().authenticated()
);
return http.build();
}
}
Actix Security:
SecurityTransform::new()
.config_authenticator(|| /* ... */)
.config_authorizer(|| {
AuthorizationManager::request_matcher()
.http_basic()
})
Feature Flag
HTTP Basic authentication requires the http-basic feature flag:
[dependencies]
actix-security = { version = "0.2", features = ["http-basic"] }
This feature is enabled by default.