# Design: NATS `external-apps` user ## Goal Add a third NATS user, `external-apps`, so third-party / external applications can connect to `wss://nats.tes.gd` with their own credential instead of borrowing the `admin` or `volcanic-agents` account. ## Scope decisions - **Permissions:** unrestricted. Same shape as the existing `admin` and `volcanic-agents` users — no `permissions` block, so full publish/subscribe on any subject, JetStream management included. Scoped permissions are explicitly out of scope for this change; if we later need to lock down external callers, that's a follow-up. - **Credential style:** password (not opaque bearer token). Env var is `NATS_EXTERNAL_APPS_PASSWORD`, following the `NATS_PASSWORD` convention used by `admin` rather than the `..._TOKEN` convention used by `volcanic-agents`. - **Wire protocol / transport:** unchanged. The user connects the same way as the others (WebSockets at `wss://nats.tes.gd`, standard user+password auth on the wire). ## Change surface 1. **`docker-compose.yml`** — inside `configs.nats-conf.content`, append one entry to `authorization.users`: ``` { user: "external-apps", password: "${NATS_EXTERNAL_APPS_PASSWORD}" } ``` Substitution happens at Docker Compose parse time, so NATS sees a static config on disk. 2. **Coolify env var** — add `NATS_EXTERNAL_APPS_PASSWORD` on the `nats` application (project `Volcanic MFEs`, app UUID from local `deploy.json`). Value: a fresh random secret (e.g. `openssl rand -hex 32`). 3. **`credentials.local.json`** — add a third entry under `users`: ```json "external-apps": { "user": "external-apps", "password": "…", "note": "…" } ``` Mirrors the Coolify env value. File is gitignored. 4. **`CLAUDE.md`** — update the two spots that enumerate users so the doc stays in sync: - The "Connection details (for agents managing this NATS)" intro list. - The "Auth" bullet under "What's inside the server". Mention that `external-apps` is the intended account for third-party callers, unrestricted for now. 5. **Deploy** — commit the compose + doc changes on `main`, then fire-and-forget `POST /api/v1/deploy?uuid=` on Coolify. Do not poll. ## Ordering constraint Set the Coolify env var **before** pushing the compose change. Otherwise the compose parser substitutes an empty string, the config lands as `password: ""`, and until the next deploy anyone who connects with empty credentials for user `external-apps` is authenticated. Order: 1. PATCH the env var into Coolify. 2. Commit + push the compose + doc changes. 3. Trigger the deploy. ## Verification After the deploy triggers, connect from a workstation with the `nats` CLI as the new user and confirm auth works: ``` nats --server=wss://nats.tes.gd \ --user=external-apps --password="$NATS_EXTERNAL_APPS_PASSWORD" \ server info ``` A `Server ID` response = success. An auth error = the env var didn't land or the substitution failed; check `docker logs` on the Coolify host per the existing "Gotchas" section of `CLAUDE.md`. ## Out of scope - Scoped/restricted permissions for external callers (deliberate — noted above). - Rotating the existing `admin` or `volcanic-agents` credentials. - Adding a UI or self-service flow for provisioning further users.