HIGH insufficient loggingactixbearer tokens

Insufficient Logging in Actix with Bearer Tokens

Insufficient Logging in Actix with Bearer Tokens — how this specific combination creates or exposes the vulnerability

Insufficient logging in Actix applications that use Bearer tokens can prevent security teams from detecting and investigating authentication-related incidents. When authorization checks pass but critical events are not recorded, attackers can probe or abuse endpoints without leaving an actionable audit trail.

In an Actix-based API, each incoming request typically passes through middleware that validates the Authorization header and extracts the Bearer token. If the application does not log key details—such as token presence (without logging the token itself), user identity, request path, outcome of authorization checks, and timestamps—anomalies like repeated failed authorizations or access to sensitive endpoints may go unnoticed. For example, an endpoint that requires a scope or role claim might allow access when the claim is missing, but without logging the missing claim or the request context, the event appears as a normal 200 response in server logs.

Attackers can leverage this gap by iterating over IDs or functionality (Insecure Direct Object Reference or BOLA) and observing only generic success or error responses. Without logs capturing attempted token usage, rate-limit triggers, or authorization denials, defenders lack visibility into whether a token is being reused, rotated, or brute-forced. This lack of observability also complicates forensic investigations after a token is leaked or an account is compromised.

Compliance mappings illustrate the impact: frameworks such as OWASP API Top 10 (2023) list insufficient logging as A05:2023, and standards like SOC 2 and PCI-DSS require audit trails for access to authentication and authorization events. middleBrick scans can surface this risk by correlating runtime behavior (e.g., missing authorization checks on endpoints) with the absence of expected loggable events, surfaced in per-category breakdowns and prioritized findings with remediation guidance.

When using the OpenAPI/Swagger spec analysis feature, middleBrick resolves full $ref chains and cross-references spec definitions with runtime findings. If the spec defines securitySchemes of type http with bearerFormat, but runtime checks show endpoints that skip authorization or do not emit structured audit events, the scan highlights the discrepancy. This helps teams align implementation with declared security expectations.

Bearer Tokens-Specific Remediation in Actix — concrete code fixes

Remediation focuses on ensuring that every request handling path produces structured, actionable logs without exposing secrets. In Actix, this is typically implemented via middleware or dedicated authorization extractors that log essential context and then either proceed or reject the request.

Example: a logging middleware that records method, path, status, and anonymized auth context. The token value itself is never logged; only its presence and a derived principal are recorded.

use actix_web::{dev::ServiceRequest, dev::ServiceResponse, Error, HttpMessage};
use actix_web_httpauth::extractors::bearer::BearerAuth;
use std::rc::Rc;
use std::cell::RefCell;

struct AuditLogger {
    // non-sensitive audit fields
    method: String,
    path: String,
    status: Option,
    user_id: Option,
}

// Middleware to capture and log request context
pub async fn log_request(req: ServiceRequest, srv: &actix_web::dev::Service) -> Result {
    let path = req.path().to_string();
    let method = req.method().to_string();

    // Extract Bearer token without logging its value
    let auth = req.headers().get("authorization").and_then(|h| h.to_str().ok());
    let token_present = auth.is_some();
    let token_type = auth.and_then(|a| a.split_whitespace().next());

    // Perform authorization extraction later in the pipeline; here we only observe intent
    let user_id: Option = req.extensions().get::().cloned();

    let res = srv.call(req).await;

    match &res {
        Ok(response) => {
            let status = response.status().as_u16();
            // structured log line; avoid logging the raw token
            println!(
                r#"{{"event":"request","method":"{}","path":"{}","status":{},"token_present":{},"token_type":"{}","user_id":{}}"#, 
                method, path, status, token_present, token_type.unwrap_or(""), user_id.as_deref().map(|s| s as &dyn std::fmt::Debug).unwrap_or(&"".into())
            );
            res
        }
        Err(e) => {
            // log failures and ensure they are observable
            println!(
                r#"{{"event":"request","method":"{}","path":"{}","status":null,"error":"{}","token_present":{}}}"#,
                method, path, e, token_present
            );
            Err(e)
        }
    }
}

Example: an Actix extractor that validates Bearer tokens and logs authorization outcomes. This pattern makes authorization explicit and auditable.

use actix_web::{dev::Payload, Error, FromRequest, HttpMessage};
use actix_web_httpauth::extractors::bearer::BearerAuth;
use futures_util::future::{ok, Ready};
use std::task::{Context, Poll};

pub struct AuthContext {
    pub user_id: String,
    pub scopes: Vec,
}

pub struct BearerTokenExtractor {
    pub bearer: BearerAuth,
}

impl FromRequest for BearerTokenExtractor {
    type Error = actix_web::Error;
    type Future = Ready>;

    fn from_request(req: &actix_web::HttpRequest, _: &mut Payload) -> Self::Future {
        let extractor = BearerAuth::from_request(req, &mut Payload::None);
        match extractor.wait() {
            Ok(auth) => {
                // Validate token and derive principal — this is where business logic lives
                // For illustration, we accept a static token and assign a user_id and scopes
                if auth.token() == "valid_token_123" {
                    let ctx = AuthContext {
                        user_id: "user-123".to_string(),
                        scopes: vec!["read:data".to_string(), "write:data".to_string()],
                    };
                    req.extensions_mut().insert(ctx);
                    ok(BearerTokenExtractor { bearer: auth })
                } else {
                    // Log rejected attempts — include enough context to investigate
                    println!(
                        r#"{{"event":"auth_fail","token_present":true,"token_type":"Bearer","reason":"invalid_token"}}"#
                    );
                    Err(actix_web::error::ErrorUnauthorized("invalid token"))
                }
            }
            Err(e) => {
                // Missing or malformed Authorization header
                println!(
                    r#"{{"event":"auth_fail","token_present":false,"error":"{}"}}"#, 
                    e
                );
                Err(e)
            }
        }
    }
}

Ensure that logs include timestamp, request identifier, HTTP method, path, authorization status (e.g., authenticated/unauthenticated/forbidden), and outcome of business-level checks. Avoid logging the raw token, secrets, or PII. Combine these logs with monitoring rules that trigger alerts on repeated authorization failures or access to sensitive endpoints, which directly addresses the insufficient logging risk.

Frequently Asked Questions

What should I log when using Bearer tokens in Actix to avoid insufficient logging?
Log method, path, status, timestamp, a request identifier, whether a token was present, the token type, and the outcome of authorization (e.g., success, invalid token, missing scope). Never log the raw token value or PII.
How does middleBrick help detect insufficient logging risks for Bearer-token APIs?
middleBrick scans runtime behavior and spec definitions to identify missing authorization checks and gaps in observable events. Findings include severity, contextual details, and remediation guidance aligned with frameworks such as OWASP API Top 10 and SOC 2.