fix(server): put /api/status behind password auth

Only /api/health remains public for liveness probes. /api/status
exposes hostname, version, and server ID which shouldn't be
accessible without authentication.
This commit is contained in:
Mohamed Boudra
2026-05-01 21:16:36 +07:00
parent a4a6713550
commit 829f3f7460
4 changed files with 4 additions and 5 deletions

View File

@@ -122,6 +122,5 @@ export function shouldBypassBearerAuth(method: string, path: string): boolean {
if (method === "OPTIONS") {
return true;
}
// Public liveness/version endpoints used by local supervisors and health probes.
return path === "/api/health" || path === "/api/status";
return path === "/api/health";
}

View File

@@ -97,7 +97,7 @@ describe("daemon bearer auth", () => {
expect(health.status).toBe(200);
const status = await fetch(`http://127.0.0.1:${daemonHandle.port}/api/status`);
expect(status.status).toBe(200);
expect(status.status).toBe(401);
} finally {
await daemonHandle.close();
}

View File

@@ -91,7 +91,7 @@ Legacy fields `log.level` and `log.format` are still supported and map to the ne
## Password authentication
You can require a password to connect to the daemon. When set, all HTTP and WebSocket clients must authenticate — except the health and status endpoints (`/api/health`, `/api/status`).
You can require a password to connect to the daemon. When set, all HTTP and WebSocket clients must authenticate. Only the `/api/health` liveness endpoint is exempt, so that process supervisors and load balancers can probe without credentials.
The easiest way to set a password is with the CLI:

View File

@@ -89,7 +89,7 @@ Configure via `daemon.hostnames` in `config.json`:
By default, anyone who can reach the daemon's listening address can connect. On localhost this is fine — only local processes have access. But if you bind to a network interface (e.g. your LAN IP or `0.0.0.0`), or if you don't fully trust your local network, you can require a password.
When a password is configured, all HTTP requests must include an `Authorization: Bearer <password>` header and all WebSocket connections must authenticate via subprotocol. Unauthenticated requests receive a `401 Unauthorized` response. The `/api/health` and `/api/status` endpoints are exempt so that health probes and process supervisors continue to work without credentials.
When a password is configured, all HTTP requests must include an `Authorization: Bearer <password>` header and all WebSocket connections must authenticate via subprotocol. Unauthenticated requests receive a `401 Unauthorized` response. Only the `/api/health` liveness endpoint is exempt, so that process supervisors and load balancers can probe without credentials.
The password is stored as a bcrypt hash in `config.json` — the daemon never stores it in plaintext. See [Configuration](/docs/configuration#password-authentication) for setup instructions.