ruvnet/RuView · error · HTTPException
Missing or invalid Authorization header
Error message
Missing or invalid Authorization header
What it means
Raised as HTTP 401 by POST /auth/logout (archive/v1/src/api/routers/auth.py:23) when the Authorization header is missing or does not start with the exact string 'Bearer '. The token after the prefix is what gets added to the in-memory token_blacklist, so logout is impossible without a well-formed Bearer header. Note the check is case-sensitive even though RFC 7235 makes auth schemes case-insensitive.
Source
Thrown at archive/v1/src/api/routers/auth.py:23
import logging
from typing import Optional
from fastapi import APIRouter, Request, HTTPException, status
from src.api.middleware.auth import token_blacklist
logger = logging.getLogger(__name__)
router = APIRouter(prefix="/auth", tags=["auth"])
@router.post("/logout")
async def logout(request: Request):
"""Logout by blacklisting the current Bearer token."""
auth_header = request.headers.get("authorization")
if not auth_header or not auth_header.startswith("Bearer "):
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Missing or invalid Authorization header",
)
token = auth_header.split(" ", 1)[1]
token_blacklist.add_token(token)
logger.info("Token blacklisted via /auth/logout")
return {"success": True, "message": "Token revoked"}
View on GitHub (pinned to 4685618388)
Solutions
- Send exactly 'Authorization: Bearer <token>' on the logout request
- If you control the server, parse the scheme case-insensitively (see exampleFix)
- If the header is set client-side but still missing server-side, check proxy/middleware configuration
Example fix
# before
if not auth_header or not auth_header.startswith('Bearer '):
raise HTTPException(401, 'Missing or invalid Authorization header')
token = auth_header.split(' ', 1)[1]
# after
scheme, _, token = (auth_header or '').partition(' ')
if scheme.lower() != 'bearer' or not token.strip():
raise HTTPException(401, 'Missing or invalid Authorization header')
token = token.strip() Defensive patterns
Strategy: validation
Validate before calling
def auth_headers(token):
if not token:
raise ValueError('not logged in')
return {'Authorization': f'Bearer {token}'}
await client.post('/auth/logout', headers=auth_headers(token)) Type guard
def is_bearer_header(h) -> bool:
if not isinstance(h, str):
return False
scheme, _, rest = h.partition(' ')
return scheme.lower() == 'bearer' and rest.strip() != '' Try / catch
resp = await client.post('/auth/logout', headers=headers)
if resp.status_code == 401:
session.clear() # header unusable or token unknown — force clean re-login Prevention
- Attach the Authorization header via shared client middleware, not per call
- Use the exact 'Bearer ' prefix with that casing to match the server check
- On 401 from logout, drop local session state anyway — the token is not usable
When it happens
Trigger: POST /auth/logout with no Authorization header, with 'Authorization: Token abc' or a bare JWT, or with a lowercase 'bearer ...' value that fails the startswith('Bearer ') check.
Common situations: The client stores the token under a different header name; a fetch wrapper attaches the header only to JSON calls and the logout request bypasses it; a proxy strips Authorization; some HTTP clients send the scheme in lowercase.
Related errors
- Authentication required
- Invalid authentication credentials
- Token has expired
- Invalid token
- JWT authentication is not configured. In development mode, e
AI-assisted analysis of ruvnet/RuView@4685618388 (2026-08-16).
Data as JSON: /api/errors/e2ae54be9c800ef4.
Report an issue: GitHub.