@deny_all

Blocks all access to an endpoint. Always returns 403 Forbidden.

Syntax

#[deny_all]

Usage

use actix_web::{get, HttpResponse, Responder};
use actix_security::deny_all;
use actix_security::http::security::AuthenticatedUser;

#[deny_all]
#[get("/disabled")]
async fn disabled_endpoint(_user: AuthenticatedUser) -> impl Responder {
    // This code is never executed
    HttpResponse::Ok().body("Never reached")
}

Common Use Cases

Temporarily Disable Endpoints

// Disable an endpoint for maintenance
#[deny_all]
#[post("/payments/process")]
async fn process_payment(_user: AuthenticatedUser) -> impl Responder {
    HttpResponse::Ok().body("Processing")
}

Deprecate Endpoints

// Mark old API version as deprecated
#[deny_all]
#[get("/api/v1/users")]
async fn v1_users(_user: AuthenticatedUser) -> impl Responder {
    HttpResponse::Ok().body("Old API")
}

Placeholder for Future Features

// Reserve endpoint for future implementation
#[deny_all]
#[get("/premium/advanced-analytics")]
async fn advanced_analytics(_user: AuthenticatedUser) -> impl Responder {
    HttpResponse::Ok().body("Coming soon")
}

Security Lockdown

// Emergency lockdown of sensitive endpoints
#[deny_all]
#[delete("/admin/database")]
async fn delete_database(_user: AuthenticatedUser) -> impl Responder {
    HttpResponse::Ok().body("Deleted")
}

AuthenticatedUser Parameter

The handler should have an AuthenticatedUser parameter (typically prefixed with _ since it's unused):

#[deny_all]
#[get("/disabled")]
async fn disabled(_user: AuthenticatedUser) -> impl Responder {
    HttpResponse::Ok().body("Never reached")
}

The _user parameter is needed for type inference, even though the handler code is never executed.

Response

Always returns:

HTTP/1.1 403 Forbidden
Content-Length: 0

Regardless of:

  • User authentication status
  • User roles or authorities
  • Request method or body

How It Works

The macro replaces your handler with one that immediately returns Forbidden:

// Input
#[deny_all]
#[get("/disabled")]
async fn disabled(_user: AuthenticatedUser) -> impl Responder {
    HttpResponse::Ok().body("Never reached")
}

// Expansion (simplified)
#[get("/disabled")]
async fn disabled(_user: AuthenticatedUser) -> Result<impl Responder, AuthError> {
    return Err(AuthError::Forbidden);

    // Unreachable - kept for type inference
    #[allow(unreachable_code)]
    Ok(HttpResponse::Ok().body("Never reached"))
}

Spring Security / Java EE Comparison

Spring Security / Java EE:

@DenyAll
@GetMapping("/disabled")
public String disabled() {
    return "never reached";
}

Actix Security:

#[deny_all]
#[get("/disabled")]
async fn disabled(_user: AuthenticatedUser) -> impl Responder {
    HttpResponse::Ok().body("never reached")
}

When to Use

Use #[deny_all] when:

  • Temporarily disabling an endpoint
  • Deprecating old API versions
  • Reserving endpoints for future use
  • Emergency security lockdown

Consider removing the endpoint entirely if it's permanently disabled.

Alternatives

Return Custom Error

If you want to return a custom message:

#[get("/deprecated")]
async fn deprecated() -> impl Responder {
    HttpResponse::Gone().body("This endpoint has been deprecated. Use /api/v2 instead.")
}

Conditional Disable

If you want to conditionally disable:

#[get("/feature")]
async fn feature(user: AuthenticatedUser) -> impl Responder {
    if !feature_flag_enabled("new_feature") {
        return HttpResponse::ServiceUnavailable()
            .body("Feature temporarily disabled");
    }
    HttpResponse::Ok().body("Feature content")
}