zeroclaw-labs/zeroclaw · error
empty bearer token
Error message
empty bearer token
What it means
NevisAuthProvider::validate_token rejects the call before any network or signature work when the token string is empty (nevis.rs:137-139). It is a fail-fast input guard: it always fires immediately and never contacts the Nevis instance. Hitting it means your code extracted no bearer token from the request but still called the validator.
Source
Thrown at crates/zeroclaw-runtime/src/security/nevis.rs:138
Ok(Self {
instance_url,
realm,
client_id,
client_secret,
validation_mode,
jwks_url,
require_mfa,
session_timeout: Duration::from_secs(session_timeout_secs),
http_client,
})
}
/// Validate a bearer token and resolve the caller's identity.
/// Returns `NevisIdentity` on success, or an error if the token is invalid,
/// expired, or MFA requirements are not met.
pub async fn validate_token(&self, token: &str) -> Result<NevisIdentity> {
if token.is_empty() {
bail!("empty bearer token");
}
let identity = match self.validation_mode {
TokenValidationMode::Local => self.validate_token_local(token).await?,
TokenValidationMode::Remote => self.validate_token_remote(token).await?,
};
if self.require_mfa && !identity.mfa_verified {
bail!(
"MFA is required but user '{}' has not completed MFA verification",
crate::security::redact(&identity.user_id)
);
}
let now = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap_or_default()
.as_secs();View on GitHub (pinned to 88bb9c8533)
Solutions
- Reject requests whose Authorization header is missing or has no token before calling validate_token (return 401 early)
- Check token.trim().is_empty() in your middleware and log which header name was inspected
- Verify your header parsing strips the 'Bearer ' scheme and uses the same header name your clients send
Example fix
// before
let token = auth_header.unwrap_or_default();
let identity = provider.validate_token(&token).await?;
// after
let token = auth_header
.and_then(|h| h.strip_prefix("Bearer "))
.map(str::trim)
.filter(|t| !t.is_empty())
.ok_or_else(|| anyhow::anyhow!("missing bearer token"))?;
let identity = provider.validate_token(token).await?; Defensive patterns
Strategy: validation
Validate before calling
fn extract_bearer(header: Option<&str>) -> Option<&str> {
header?
.strip_prefix("Bearer ")
.map(str::trim)
.filter(|t| !t.is_empty())
} Try / catch
If validate_token still errors, match on err.to_string().contains("empty bearer token") and return 401 immediately — never retry and never treat it as an IdP outage. Prevention
- Centralize Authorization header extraction in one middleware that returns 401 on empty
- Log which header name was inspected, never the token value
- Add a unit test that a missing Authorization header never reaches validate_token
When it happens
Trigger: Calling validate_token with an empty string — typically because the Authorization header was missing, used a different scheme or header name, or the 'Bearer ' prefix stripping left an empty value; tests pass an unset env var or String::new().
Common situations: Gateway middleware forwards an empty string when the Authorization header is absent; client sends the token in x-api-key instead; config template ships an empty token value; integration tests forget to inject the token.
Related errors
- Invalid JWT structure: expected 3 dot-separated parts
- empty session token
- MFA is required but user '{}' has not completed MFA verifica
- Nevis session expired
- Nevis introspection returned HTTP {}
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/a5134f4779dc26a3.
Report an issue: GitHub.