6.1 KiB
Backend core modules (auth/config/logging/errors)
Evidence basis: repo https://github.com/abhi1693/openclaw-mission-control @ commit
c3490630a4503d9c8142aaa3abf542e0d00b5035.
This page documents the backend “core” layer under backend/app/core/* plus the API dependency module backend/app/api/deps.py.
It’s written for maintainers who need to answer:
- “Where does configuration come from?”
- “How do user vs agent auth work?”
- “Where are authorization decisions enforced?”
- “What’s the error envelope / request-id behavior?”
- “How is logging structured and how do I get request-context in logs?”
Start here (reading order)
backend/app/core/config.py— settings + env file loadingbackend/app/core/logging.py— structured logging + request contextbackend/app/core/error_handling.py— request-id middleware + exception envelopebackend/app/core/auth.py— Clerk/user auth resolutionbackend/app/core/agent_auth.py— agent token auth resolutionbackend/app/api/deps.py— how routes declare and enforce access
Configuration: loading & precedence
Primary file: backend/app/core/config.py
Key facts:
- Uses
pydantic-settings(BaseSettings) to load typed settings from environment. - Env files are loaded regardless of current working directory:
backend/.env(viaDEFAULT_ENV_FILE)- then
.env(repo root) as an additional source - See
Settings.model_config.env_file=[DEFAULT_ENV_FILE, ".env"].
- Unknown env vars are ignored (
extra="ignore").
Notable settings (security-sensitive in bold):
DATABASE_URL/database_urlCORS_ORIGINS/cors_originsDB_AUTO_MIGRATE/db_auto_migrateCLERK_SECRET_KEY/clerk_secret_key(must be non-empty; validator enforces it)CLERK_API_URL,CLERK_VERIFY_IAT,CLERK_LEEWAY- logging knobs:
LOG_LEVEL,LOG_FORMAT,LOG_USE_UTC,REQUEST_LOG_SLOW_MS,REQUEST_LOG_INCLUDE_HEALTH
Deployment implication
- If a deployment accidentally starts the backend with an empty/placeholder
CLERK_SECRET_KEY, the backend will fail settings validation at startup.
Auth model split
The backend supports two top-level actor types:
- User (human UI / admin) — resolved from the
Authorization: Bearer <token>header via Clerk. - Agent (automation) — resolved from
X-Agent-Token: <token>(and optionallyAuthorization: Bearer <token>for agent callers).
User auth (Clerk) — backend/app/core/auth.py
What it does:
- Uses the
clerk_backend_apiSDK to authenticate requests (authenticate_request(...)) usingCLERK_SECRET_KEY. - Resolves a
AuthContextcontainingactor_type="user"and aUsermodel instance. - The module includes helpers to fetch user profile details from Clerk (
_fetch_clerk_profile) and to delete a Clerk user (delete_clerk_user).
Security-sensitive notes:
- Treat
CLERK_SECRET_KEYas a credential; never log it. - This code calls Clerk API endpoints over the network (timeouts and error handling matter).
Agent auth (token hash) — backend/app/core/agent_auth.py
What it does:
- Requires a token header for protected agent endpoints:
- Primary header:
X-Agent-Token - Optional parsing:
Authorization: Bearer ...(only inget_agent_auth_context, and only ifaccept_authorization=True)
- Primary header:
- Validates token by comparing it against stored
agent_token_hashvalues in the DB (verify_agent_token). - “Touches” agent presence (
last_seen_at,status) on authenticated requests.- For safe methods (
GET/HEAD/OPTIONS), it commits immediately so read-only polling still shows the agent as online.
- For safe methods (
Security-sensitive notes:
- Token verification iterates over agents with a token hash. If this grows large, consider indexing/lookup strategy.
- Never echo full tokens in logs; current code logs only a prefix on invalid tokens.
Authorization enforcement: backend/app/api/deps.py
This module is the primary “policy wiring” for most routes.
Key concepts:
require_admin_auth(...)- Requires an authenticated admin user.
require_admin_or_agent(...)→ returnsActorContext- Allows either:
- admin user (user auth via Clerk), or
- authenticated agent (agent auth via X-Agent-Token).
- Allows either:
Board/task access patterns:
get_board_for_actor_read/get_board_for_actor_write- Enforces that the caller (user or agent) has the correct access to the board.
- Agent access is restricted if the agent is bound to a specific board (
agent.board_id).
get_task_or_404- Loads a task and ensures it belongs to the requested board.
Org access patterns (user callers):
require_org_memberandrequire_org_admin- Resolve/require active org membership.
- Provide an
OrganizationContextwithorganization+member.
Maintainer tip:
- When debugging a “why is this 403/401?”, start by checking the route’s dependency stack (in the route module) and trace through the relevant dependency in
deps.py.
Logging: structure + request context
Primary file: backend/app/core/logging.py
Highlights:
- Defines a custom TRACE level (
TRACE_LEVEL = 5). - Uses
contextvarsto carryrequest_id,method, andpathacross async tasks. AppLogFilterinjectsapp,version, and request context into each log record.- Supports JSON output (
JsonFormatter) and key=value (KeyValueFormatter) formats.
Where request context gets set:
backend/app/core/error_handling.pymiddleware calls:set_request_id(...)set_request_route_context(method, path)
Error envelope + request-id
Primary file: backend/app/core/error_handling.py
Key behaviors:
- Installs a
RequestIdMiddleware(ASGI) that:- Accepts client-provided
X-Request-Idor generates one. - Adds
X-Request-Idto the response. - Emits structured “http.request.*” logs, including “slow request” warnings.
- Accepts client-provided
- Error responses include
request_idwhen available:- Validation errors (
422) return{detail: <errors>, request_id: ...}. - Other HTTP errors are wrapped similarly.
- Validation errors (
Maintainer tip:
- When debugging incidents, ask for the
X-Request-Idfrom the client and use it to locate backend logs quickly.