Credentials and connections
The system must run unattended for months. Everything here was learned by getting it wrong first.
Connections must survive without a human
Authorise once; never again. The test is literal: switch off every laptop, come back a week later, and it still works.
OAuth refresh tokens rotate
Higgsfield issues a new refresh token on every refresh and kills the old one immediately. This is not unusual — assume any OAuth MCP does it.
Consequences, each of which broke something here:
- Persist every rotation to disk. Holding it in memory works until the process restarts, then fails with nothing obvious to point at — roughly a day after deploy.
- The file wins over the environment variable. The env var is the bootstrap handoff only; the file holds the live chain.
- One chain per consumer. Two processes sharing a refresh token will fight, and whichever refreshes second is dead. Dev and production hold separate authorisations for this reason.
- Collapse concurrent refreshes. Two simultaneous refreshes burn two rotations and the first result is already invalid.
src/lib/mcp/connection.ts implements all of this. Adding another MCP server is a config object — do not write a second copy of this logic.
Failed persistence must be loud
A write failure logs an explicit error and does not fail the request: the current run still has a working token, and the damage lands at the next restart. Silence is what makes that undiagnosable — a /data permission bug hid behind a working system for exactly this reason.
An API key is not a session
Higgsfield's API key authenticates the transport. Catalogue calls succeed with it; anything touching the account returns "session expired". A 200 on initialize is not evidence that authentication is solved.
Two wallets, one login
Higgsfield's subscription credits and its API-platform credits are billed separately. The MCP path spends the subscription; the REST path spends a wallet that has to be funded independently.
Where secrets live
.envon the box, mode 600, never committed- Rotated tokens in
/data, mode 600, on a volume owned by the app user - The portal's own MCP endpoint fails closed — an unset
MCP_TOKENdisables it rather than serving it open, and the comparison is constant-time
Anyone with root on the droplet can use all of it. That is inherent to unattended operation and is why the box is hardened: key-only SSH, three open ports, fail2ban, unattended security updates.
Google service account (Drive, read-only)
GOOGLE_SA_KEY_B64 in both droplet .env files — the service-account JSON, base64-wrapped because multi-line JSON cannot live in dotenv format. Full provenance, click-paths and the org-policy trap: ../sop/gcp-service-account.md. Scope is drive.readonly via domain-wide delegation; writes come only from Shared Drive membership. This key does not rotate itself — revocation and rotation are one click in the GCP Keys tab plus one set-secret.sh run.