Zie619/n8n-workflows · error · HTTPException

Invalid authentication token

Error message

Invalid authentication token

What it means

Raised by the admin reindex endpoint in api_server.py when the supplied admin_token does not equal the ADMIN_TOKEN environment variable. It is a deliberate 401 authentication rejection protecting a destructive/background indexing operation. The server also logs 'Security: Unauthorized reindex attempt from {client_ip}' whenever it fires.

Source

Thrown at api_server.py:603

            status_code=429, detail="Rate limit exceeded. Please try again later."
        )

    # Security: Basic authentication check
    # In production, use proper authentication (JWT, OAuth, etc.)
    # For now, check for environment variable or disable endpoint

    expected_token = os.environ.get("ADMIN_TOKEN", None)

    if not expected_token:
        # If no token is configured, disable the endpoint for security
        raise HTTPException(
            status_code=503,
            detail="Reindexing endpoint is disabled. Set ADMIN_TOKEN environment variable to enable.",
        )

    if admin_token != expected_token:
        print(f"Security: Unauthorized reindex attempt from {client_ip}")
        raise HTTPException(status_code=401, detail="Invalid authentication token")

    def run_indexing():
        try:
            db.index_all_workflows(force_reindex=force)
            print(f"Reindexing completed successfully (requested by {client_ip})")
        except Exception as e:
            print(f"Error during reindexing: {e}")

    background_tasks.add_task(run_indexing)
    return {"message": "Reindexing started in background", "requested_by": client_ip}


@app.get("/api/integrations")
async def get_integrations():
    """Get list of all unique integrations."""
    try:
        stats = db.get_stats()
        # For now, return basic info. Could be enhanced to return detailed integration stats

View on GitHub (pinned to 94007c1445)

Solutions

  1. Confirm the exact value of ADMIN_TOKEN in the server process environment (print len() or a hash, never the value) and re-send a token that matches it exactly.
  2. Check how the endpoint declares the admin_token parameter (query vs header vs body) and send it in that position.
  3. Strip whitespace when setting the env var: export ADMIN_TOKEN=$(cat token.txt | tr -d '[:space:]') or fix the .env line.
  4. If ADMIN_TOKEN is unset you will instead get a 503 'endpoint is disabled' — set the variable to enable the endpoint, then authenticate.

Example fix

# before
resp = requests.post("http://host/api/reindex", params={"force": True})  # 401: no token

# after
import os
resp = requests.post(
    "http://host/api/reindex",
    params={"force": True, "admin_token": os.environ["ADMIN_TOKEN"]},
)
Defensive patterns

Strategy: validation

Validate before calling

import os

def can_reindex() -> tuple[bool, str]:
    token = os.environ.get("ADMIN_TOKEN")
    if not token:
        return False, "ADMIN_TOKEN not set on client; endpoint will return 503/401"
    return True, token

# before the call:
ok, token = can_reindex()
if ok:
    requests.post(f"{BASE}/api/reindex", params={"admin_token": token, "force": False})

Try / catch

try:
    resp = requests.post(url, params={"admin_token": token}, timeout=30)
    resp.raise_for_status()
except requests.HTTPError as e:
    status = e.response.status_code
    if status == 401:
        # credential mismatch: re-read ADMIN_TOKEN from source of truth, never retry in a loop
        raise RuntimeError("Admin token rejected; refresh credential") from e
    if status == 503:
        raise RuntimeError("Endpoint disabled; ADMIN_TOKEN unset on server") from e
    raise

Prevention

When it happens

Trigger: POST to the reindex endpoint (e.g. /api/reindex?force=true) with a missing, misspelled, or stale admin_token argument while ADMIN_TOKEN is set in the server environment. Also triggered when the client sends a token computed against a different ADMIN_TOKEN value than the one the server process was started with.

Common situations: ADMIN_TOKEN was rotated or differs between environments (dev vs prod); the server was restarted with a new env var but the client still uses the old token; the token is passed as a header while the endpoint expects it as a query/body parameter (or vice versa); trailing whitespace/newline in the env var from a .env file.

Understand the failure class

Related errors


AI-assisted analysis of Zie619/n8n-workflows@94007c1445 (2026-08-15). Data as JSON: /api/errors/980ca83bbbc420a5. Report an issue: GitHub.