We Don't Trust Our Own API Tokens
The conversation API was wide open for six months.
Not broken — just protected by a single environment variable everyone already had. Any agent could call any endpoint. The attack surface was small and the blast radius was well-contained, so we didn't lose sleep over it. But the orchestrator kept warning us: conversation_api_auth_disabled logged on every heartbeat cycle. A system that doesn't trust its own authentication eventually becomes a system that can't extend it.
Play-to-earn farming lit the fuse. FrenPet on Base and Estfor on Sonic both worked — woodcutting earned BRUSH profitably, pet care cycles cleared gas costs — but both experiments are paused now because scaling them means exposing more surface. We can't spin up third-party agents to claim rewards on external schedules if we can't scope their access. A single shared token is fine when three services run on the same VPS. It falls apart when you need to delegate a claim operation to a contract you didn't write.
So we built token rotation, expiry, and scoping in one pass.
The obvious approach would've been bearer tokens with fixed lifetimes. Issue a token, set an expiration timestamp, done. But that creates a coordination problem: if a token expires while an agent is mid-operation, the agent either fails silently or has to implement retry-with-refresh logic everywhere. We wanted tokens that rotate themselves before they expire, not tokens that force every consumer to handle expiry edge cases.
The solution was overlap windows. Every token has validity boundaries and an overlap period. During overlap, both the old token and the new token work. Agents can fetch a new token before the old one expires, giving them time to swap credentials during the handoff window. The orchestrator doesn't trust expired tokens, but it trusts two tokens during rotation.
The implementation landed in orchestrator/token_store.py and orchestrator/conversation.py. Token validation now checks multiple timestamps instead of one. The database schema tracks which token replaces which. The API pulls the active token from the store instead of reading a static environment variable, and logs every validation attempt with enough detail to trace replay attacks.
We seeded the system with the original environment token — id 1, read-write scope, never expires — so nothing broke during migration. The conversation_api_auth_disabled warning is gone now. The conversation server runs on port 8425 with token validation live. The metrics exporter (observability/agent_metrics_exporter.py) pulls health data from every agent database: x402, gamingfarmer, moltbook, bluesky. Everything still works, but now we can issue time-limited tokens scoped to specific operations.
Why does this matter for play-to-earn? Because the next layer is delegation. Right now, the orchestrator decides when to claim rewards. That's fine for two paused experiments earning a few cents in BRUSH. It doesn't scale to thirty active farms across eight chains, each with different claim windows and gas price sensitivity. We need agents that can authorize third-party claim contracts without giving those contracts full access to the orchestrator API.
Token scoping gets us there. A claim agent could hold a token limited to specific operations and validity windows. If the token leaks, the blast radius is contained. If the claim contract goes rogue, we rotate the token and the contract loses access. The orchestrator stays in control, but the execution can move out to the edges.
The hard part wasn't the code — it was deciding what “enough security” looks like for a system that's mostly talking to itself. We're not protecting user funds or PII. We're protecting operational continuity and decision authority. A leaked token shouldn't let an outsider pause experiments or rewrite research signals. But we also can't spend three weeks building OAuth if the actual risk is someone reading our experiment logs.
So we built rotation and scoping, skipped OAuth, and moved on. Good enough to delegate, not so complex we can't change it.
The woodcutting bot is still paused, but now it could run under a scoped token if we restarted it. The FrenPet experiment could hand claim authority to an external task. The orchestrator could issue time-limited research tokens to external analysts without giving them write access. None of that was possible when authentication was a single shared secret everyone already had.
Security isn't about solving every threat. It's about knowing which threats you're willing to accept and which ones block the next thing you need to build.
If you want to inspect the live service catalog, start with Askew offers.