infiniflow/ragflow · error · AuthException

Login failed: missing Authorization header

Error message

Login failed: missing Authorization header

What it means

Thrown by the RAGFlow admin client (admin/client/user.py:75) after a successful login POST to /admin/login or /auth/login: the JSON body reported code==0, but the HTTP response carried no 'Authorization' response header, which is where the server (via sync_construct_response(auth=user.get_id())) returns the session token. The client treats a missing token as a fatal login failure even though the login itself succeeded. It is an AuthException raised client-side, not an HTTP error status.

Source

Thrown at admin/client/user.py:75

    raise AuthException(f"Register failed: {msg}")


def login_user(client: HttpClient, server_type: str, email: str, password: str) -> str:
    password_enc = encrypt_password(password)
    payload = {"email": email, "password": password_enc}
    if server_type == "admin":
        response = client.request("POST", "/admin/login", use_api_base=True, auth_kind=None, json_body=payload)
    else:
        response = client.request("POST", "/auth/login", use_api_base=True, auth_kind=None, json_body=payload)
    try:
        res = response.json()
    except Exception as exc:
        raise AuthException(f"Login failed: invalid JSON response ({exc})") from exc
    if res.get("code") != 0:
        raise AuthException(f"Login failed: {res.get('message')}")
    token = response.headers.get("Authorization")
    if not token:
        raise AuthException("Login failed: missing Authorization header")
    return token

View on GitHub (pinned to 554fb1133a)

Solutions

  1. Verify server_type matches the target deployment (admin server vs standard API) so login POSTs to /admin/login which is guaranteed to echo the token header.
  2. Curl the login endpoint directly and confirm the response includes the Authorization header; if absent, upgrade the RAGFlow server so sync_construct_response sets it.
  3. If a reverse proxy sits in front, ensure it forwards response headers (no proxy_hide_header/proxy_pass_header misconfig for Authorization).
  4. As a last resort, extract the token from the JSON body (resp access_token) instead of the header, mirroring what the server sets in user.access_token.

Example fix

# before
response = client.request("POST", "/admin/login", use_api_base=True, auth_kind=None, json_body=payload)
token = response.headers.get("Authorization")
if not token:
    raise AuthException("Login failed: missing Authorization header")

# after - fall back to body token set by login_admin()
res = response.json()
token = response.headers.get("Authorization") or f"Bearer {res['data']['access_token']}"
if not token:
    raise AuthException("Login failed: missing Authorization header")
Defensive patterns

Strategy: try-catch

Validate before calling

import requests
r = requests.post(f"{base_url}/admin/login", json=payload)
body = r.json()
has_header = "Authorization" in r.headers
has_body_token = isinstance(body.get("data"), dict) and body["data"].get("access_token")
if body.get("code") == 0 and not (has_header or has_body_token):
    raise RuntimeError("Server does not return a login token; upgrade server or fix proxy header forwarding")

Type guard

def login_response_has_token(response) -> bool:
    if response.headers.get("Authorization"):
        return True
    try:
        data = response.json().get("data")
    except ValueError:
        return False
    return isinstance(data, dict) and bool(data.get("access_token"))

Try / catch

from admin.client.user import AuthException
try:
    token = login(client, payload)
except AuthException as e:
    if "missing Authorization header" in str(e):
        # token echo broken: fix proxy/server, or read data.access_token from body
        raise
    raise

Prevention

When it happens

Trigger: Calling RagFlowAdminClient login (client.request('POST', '/admin/login'|'/auth/login', auth_kind=None, json_body=payload)) where the response body has code==0 but the Authorization response header is absent. Happens when: (1) server_type is wrong so the request hits /auth/login on a deployment that does not echo the token header; (2) a reverse proxy (nginx with 'proxy_hide_header Authorization' or underscore/header filtering) strips the response header; (3) the server build predates the header-echo behavior in sync_construct_response.

Common situations: Running an older ragflow server against a newer admin client, pointing the client at the wrong base URL or server_type ('admin' vs regular auth), or deploying behind a proxy/gateway that filters Authorization headers in both directions. Also seen when a custom WSGI middleware drops headers on login responses.

Related errors


AI-assisted analysis of infiniflow/ragflow@554fb1133a (2026-08-15). Data as JSON: /api/errors/f4019148c56193e2. Report an issue: GitHub.