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

  1. Send exactly 'Authorization: Bearer <token>' on the logout request
  2. If you control the server, parse the scheme case-insensitively (see exampleFix)
  3. 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

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


AI-assisted analysis of ruvnet/RuView@4685618388 (2026-08-16). Data as JSON: /api/errors/e2ae54be9c800ef4. Report an issue: GitHub.