{"record":{"id":"2c6877f009f545be","repo":"BerriAI/litellm","slug":"admin-only-endpoint-your-user-role-user-api-key","errorCode":null,"errorMessage":"Admin-only endpoint. Your user role={user_api_key_dict.user_role}","messagePattern":"Admin-only endpoint\\. Your user role=(.+?)","errorType":"http","errorClass":"HTTPException","httpStatus":401,"severity":"error","filePath":"litellm/proxy/management_endpoints/customer_endpoints.py","lineNumber":844,"sourceCode":") -> list[CustomerResponse]:\n    \"\"\"\n    [Admin-only] List all available customers\n\n    Example curl:\n    ```\n    curl --location --request GET 'http://0.0.0.0:4000/customer/list' \\\n        --header 'Authorization: Bearer sk-1234'\n    ```\n\n    \"\"\"\n    try:\n        from litellm.proxy.proxy_server import prisma_client\n\n        if (\n            user_api_key_dict.user_role != LitellmUserRoles.PROXY_ADMIN\n            and user_api_key_dict.user_role != LitellmUserRoles.PROXY_ADMIN_VIEW_ONLY\n        ):\n            raise HTTPException(\n                status_code=401,\n                detail={\"error\": f\"Admin-only endpoint. Your user role={user_api_key_dict.user_role}\"},\n            )\n\n        if prisma_client is None:\n            raise HTTPException(\n                status_code=400,\n                detail={\"error\": CommonProxyErrors.db_not_connected_error.value},\n            )\n\n        response: Final = await _typed_table(EndUserRepository(prisma_client)).find_many(\n            include={\"litellm_budget_table\": True, \"object_permission\": True}\n        )\n\n        return [_to_customer_response(item) for item in response]\n\n    except Exception as e:\n        verbose_proxy_logger.exception(","sourceCodeStart":826,"sourceCodeEnd":862,"githubUrl":"https://github.com/BerriAI/litellm/blob/77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8/litellm/proxy/management_endpoints/customer_endpoints.py#L826-L862","documentation":"GET /customer/list is restricted to PROXY_ADMIN and PROXY_ADMIN_VIEW_ONLY roles taken from the authenticated key's user (user_api_key_dict.user_role). Any other role (internal_user, team member, etc.) gets HTTP 401 with the caller's actual role echoed in the message. Note the DB check on this route comes after the role check.","triggerScenarios":"Calling GET /customer/list with a virtual key whose owning user is not a proxy admin - team-scoped keys, personal keys, or org-member keys created via /user/new.","commonSituations":"Operators holding team keys try to enumerate all customers; scripts pull the wrong secret from a vault; new staff have the default internal_user role and attempt admin operations on day one.","solutions":["Call with the master key (LITELLM_MASTER_KEY) or a key whose user has the proxy_admin role","An admin can elevate the user via /user/update (role: proxy_admin), or issue a proxy_admin_view_only key for read-only access","Non-admin callers should use scoped endpoints (e.g. GET /customer/info) instead of the full listing"],"exampleFix":"# before\nheaders = {\"Authorization\": \"Bearer sk-team-key\"}   # internal_user role -> 401\n\n# after\nheaders = {\"Authorization\": \"Bearer sk-master-key\"}    # proxy_admin -> 200","handlingStrategy":"validation","validationCode":"import httpx\n\n\ndef is_admin_key(base: str, headers: dict) -> bool:\n    key = headers[\"Authorization\"].split(\" \", 1)[1]\n    info = httpx.get(f\"{base}/key/info\", params={\"key\": key}, headers=headers).json()\n    role = (info.get(\"key_info\") or {}).get(\"user_role\")\n    return role in (\"proxy_admin\", \"proxy_admin_view_only\")","typeGuard":null,"tryCatchPattern":"try:\n    r = httpx.get(f\"{base}/customer/list\", headers=headers)\nexcept httpx.HTTPStatusError as e:\n    if e.response.status_code == 401 and \"Admin-only endpoint\" in e.response.text:\n        raise PermissionError(\"/customer/list needs a proxy_admin key\") from e\n    raise","preventionTips":["Store admin and non-admin keys separately in secret managers and label them clearly","Check the key's user_role via /key/info before scripting admin endpoints","Grant proxy_admin_view_only for reporting tooling that only needs to read"],"tags":["litellm","authorization","roles","customer-management","http-401"],"backgroundTag":"insufficient-permissions","analyzedSha":"77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8","analyzedAt":"2026-08-18T11:44:31.656Z","schemaVersion":2},"datasetVersion":"2026-08-27T19:17:21.184Z"}