{"record":{"id":"77e8da38befa28ab","repo":"bytedance/deer-flow","slug":"detail","errorCode":null,"errorMessage":"{detail}","messagePattern":"\\{detail\\}","errorType":"http","errorClass":"HTTPException","httpStatus":403,"severity":"error","filePath":"backend/app/gateway/deps.py","lineNumber":804,"sourceCode":"    \"\"\"Require the authenticated caller to be an admin user.\n\n    ``AuthMiddleware`` normally stamps ``request.state.user`` before the request\n    reaches a router. Falling back to the strict dependency keeps the route safe\n    in tests or alternative ASGI compositions that mount a router without the\n    global middleware. ``detail`` is the route-specific 403 message.\n\n    Centralising this here means a future change to the admin definition (e.g.\n    allowing an internal system role, adding audit logging, or switching to a\n    permission-based check) lands in one place instead of drifting across the\n    per-router copies that previously existed in ``mcp``, ``channel_connections``\n    and ``channels``.\n    \"\"\"\n    user = getattr(request.state, \"user\", None)\n    if user is None:\n        user = await get_current_user_from_request(request)\n\n    if getattr(user, \"system_role\", None) != \"admin\":\n        raise HTTPException(status_code=403, detail=detail)\n\n\nasync def get_optional_user_from_request(request: Request):\n    \"\"\"Get optional authenticated user from request.\n\n    Returns None if not authenticated.\n    \"\"\"\n    try:\n        return await get_current_user_from_request(request)\n    except HTTPException:\n        return None\n\n\nasync def get_current_user(request: Request) -> str | None:\n    \"\"\"Extract user_id from request cookie, or None if not authenticated.\n\n    Thin adapter that returns the string id for callers that only need\n    identification (e.g., ``feedback.py``). Full-user callers should use","sourceCodeStart":786,"sourceCodeEnd":822,"githubUrl":"https://github.com/bytedance/deer-flow/blob/1dd6ba1acb03700589994b0366c5d1c7d05e2eff/backend/app/gateway/deps.py#L786-L822","documentation":"HTTP 403 raised by require_admin_user() when the authenticated caller's system_role is not 'admin'. The dependency first prefers request.state.user stamped by AuthMiddleware, falling back to get_current_user_from_request(); the detail string is supplied per-route by the caller, so the message varies by endpoint.","triggerScenarios":"Calling an admin-only route (extension management in mcp/channels/channel_connections routers, admin config endpoints) as a regular user or with a token whose user record lacks system_role='admin'.","commonSituations":"Default first-registered user is not admin and tries admin endpoints; user record edited/seeded without the admin role; internal/system service account (not an admin user) hitting an admin route; tests using a standard user fixture for admin flows.","solutions":["Verify the caller's system_role in the users store; promote the intended account (UPDATE users SET system_role='admin' or the admin management endpoint)","Log in as an actual admin user for admin operations","If the request should have been stamped by AuthMiddleware with an internal admin identity, confirm the middleware ordering and that the internal auth source is enabled for that path","In tests, use the admin user fixture"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// before calling admin APIs\nconst me = await api.get('/api/auth/me');\nif (me.system_role !== 'admin') throw new Error('admin only');","typeGuard":"type IsAdmin = (u: { system_role?: string } | null) => boolean;\nconst isAdmin: IsAdmin = (u) => u?.system_role === 'admin';","tryCatchPattern":"try {\n    await api.post('/api/admin/extensions/enable', body)\nexcept HTTPError as e:\n    if e.status == 403:\n        raise PermissionError('Admin role required for this operation')\n    raise","preventionTips":["Hide admin UI affordances unless system_role === 'admin'","Seed the first admin account explicitly during provisioning","Return the caller's role from /me so clients can gate without guessing"],"tags":["auth","http-403","authorization","admin","roles"],"backgroundTag":null,"analyzedSha":"1dd6ba1acb03700589994b0366c5d1c7d05e2eff","analyzedAt":"2026-08-14T21:20:34.804Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}