Require a token on every call from the server to a Bot - #52
Open
zopeVaibhav wants to merge 1 commit into
Open
Conversation
zopeVaibhav
requested review from
MikeRyanDev,
davidmckayv,
guidovizoso and
tylerslaton
as code owners
August 20, 2026 17:45
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The problem
agent-botandagent-langgraphservePOST /ag-uiwithout any authentication. Any process that can reach the Bot's port issues an AG-UI run against the deployment's model credential;docker-compose.yml:162binds${BOT_PORT:-4200}:4200on0.0.0.0, so on the shipped configuration that is any process on the host's network and any container on the compose network.MANAGED_AGENT_TOKENis not read anywhere in either Bot, andserver/src/agents/runtime-agents.tsattaches no authentication header to its own calls, so the boundary is absent on both sides rather than misconfigured.agent-computerandsupervisorboth require a shared secret at boot and validate it on every request; the two Bots did not.This is the opposite direction to #34, which added per-agent callback tokens for the Bot→server path. That change does not cover requests from the server into a Bot's
/ag-ui, which is what this PR closes.Closes #50.
The approach
A single header,
x-openbot-agent-token, on every call from the server to a managed Bot. A newshared/agent-authorisation.tsholds a constant-timematchesTokenand ahasManagedAgentTokenrequest helper, kept inshared/so the two Bots and the server all read the same rule rather than three subtly different ones. Both Bots refuse to start whenMANAGED_AGENT_TOKENis unset, no silent-open dev fallback because the process holds a model credential and an unauthenticated port on it is worth failing loudly for, and reject/ag-uiwith 401 when the header is missing or wrong.GET /healthstays open so an orchestrator can check readiness without holding the token.The server side matches.
server/src/config.tsrequiresMANAGED_AGENT_TOKENat boot alongside the other secrets.server/src/agents/runtime-agents.tsattaches the header only on the agent whose endpoint equalsconfig.managedAgentAgUiUrl, so customer-owned AG-UI endpoints never see it and a token intended for the built-in Bot is not leaked to a third party's server on the first customer registration.docker-compose.ymlpassesMANAGED_AGENT_TOKENthrough to both Bots;.env.example,README.md, anddocs/configuration.mddocument the new required variable.What is not covered
agent-computerandsupervisorwere already token-guarded and are unchanged.Merge notes
MANAGED_AGENT_TOKEN. Existing deployments that upgrade without setting it get a loud refuse-to-start on both the server and each Bot rather than a silent regression.managedAgentToken: string;loadConfigtest fixtures are updated.createRuntimeAgentLoadergains an optional trailingmanagedAgentparameter; existing callers that passundefinedkeep their old behaviour but issue no header, so a self-hosted deployment that runs a custom Bot in place of the managed one needs to opt in.Verification
All gates from a clean tree at
c81d9b1.bun run format:check: no fixesbun run lint: 25 pre-existingnoTemplateCurlyInStringwarnings, none newbun run typecheck: app, server, worker all exit 0bun run test: 686 pass, 5 skip, 0 fail across 79 files, 1701 assertionsbun run build: exit 0Live against a rebuilt
openbot-agent-botcontainer (docker compose up -d --build --force-recreate agent-bot):POST /ag-ui, no headersUnauthorized.POST /ag-ui,x-openbot-agent-token: wrongPOST /ag-ui,x-openbot-agent-token: $MANAGED_AGENT_TOKENRUN_STARTEDGET /healthNew tests:
shared/agent-authorisation.test.ts(2). Existing tests updated:server/tests/config.test.ts(required-token assertion),server/tests/runtime-agents.integration.test.ts(managed endpoint receives header, customer endpoint does not).