@permit_all
Marks an endpoint as publicly accessible. No authentication required.
Syntax
#[permit_all]
Usage
use actix_web::{get, HttpResponse, Responder};
use actix_security::permit_all;
#[permit_all]
#[get("/health")]
async fn health_check() -> impl Responder {
HttpResponse::Ok().body("OK")
}
#[permit_all]
#[get("/")]
async fn index() -> impl Responder {
HttpResponse::Ok().body("Welcome!")
}
No AuthenticatedUser Required
Unlike other security macros, #[permit_all] handlers don't need an AuthenticatedUser parameter since no authentication is required:
// ✓ Correct - no AuthenticatedUser needed
#[permit_all]
#[get("/public")]
async fn public_endpoint() -> impl Responder {
HttpResponse::Ok().body("Public content")
}
// ✓ Also valid - AuthenticatedUser is optional
#[permit_all]
#[get("/info")]
async fn info(user: Option<AuthenticatedUser>) -> impl Responder {
match user {
Some(u) => HttpResponse::Ok().body(format!("Hello, {}!", u.get_username())),
None => HttpResponse::Ok().body("Hello, guest!"),
}
}
Common Use Cases
Health Checks
#[permit_all]
#[get("/health")]
async fn health() -> impl Responder {
HttpResponse::Ok().body("OK")
}
#[permit_all]
#[get("/ready")]
async fn readiness() -> impl Responder {
// Check database, etc.
HttpResponse::Ok().body("Ready")
}
Public API Endpoints
#[permit_all]
#[get("/api/public/version")]
async fn api_version() -> impl Responder {
HttpResponse::Ok().json(serde_json::json!({
"version": "1.0.0"
}))
}
Landing Pages
#[permit_all]
#[get("/")]
async fn home() -> impl Responder {
HttpResponse::Ok().body("Welcome to our app!")
}
#[permit_all]
#[get("/about")]
async fn about() -> impl Responder {
HttpResponse::Ok().body("About us")
}
Login/Registration
#[permit_all]
#[get("/login")]
async fn login_page() -> impl Responder {
HttpResponse::Ok().body("Login form")
}
#[permit_all]
#[post("/login")]
async fn do_login(form: web::Form<LoginForm>) -> impl Responder {
// Process login
HttpResponse::Ok().body("Logged in")
}
#[permit_all]
#[post("/register")]
async fn register(form: web::Form<RegisterForm>) -> impl Responder {
// Process registration
HttpResponse::Created().body("Registered")
}
Important Note
#[permit_all] marks the handler as public, but URL-based authorization still applies. If your URL matcher requires authentication for the path, users will still need to authenticate.
To make an endpoint truly public, ensure your URL matcher doesn't require authentication for that path:
// URL authorization
let authorizer = AuthorizationManager::request_matcher()
.add_matcher("/api/private/.*", Access::new().authenticated())
// /api/public/.* has no matcher, so it's public by default
;
// Handler authorization
#[permit_all] // Explicitly marks handler as public
#[get("/api/public/info")]
async fn public_info() -> impl Responder {
HttpResponse::Ok().body("Public info")
}
How It Works
The macro simply passes through your function unchanged:
// Input
#[permit_all]
#[get("/health")]
async fn health() -> impl Responder {
HttpResponse::Ok().body("OK")
}
// Output (unchanged)
#[get("/health")]
async fn health() -> impl Responder {
HttpResponse::Ok().body("OK")
}
The macro serves as documentation and ensures consistency with other security annotations.
Spring Security / Java EE Comparison
Spring Security / Java EE:
@PermitAll
@GetMapping("/public")
public String publicEndpoint() {
return "public";
}
Actix Security:
#[permit_all]
#[get("/public")]
async fn public_endpoint() -> impl Responder {
HttpResponse::Ok().body("public")
}
When to Use
Use #[permit_all] for:
- Health check endpoints
- Public API endpoints
- Login/registration pages
- Landing pages
- Any endpoint that should be accessible without authentication
Consider using URL-based authorization instead when you have many public endpoints under a common path prefix.