--- title: Admin (Production) description: "Run the enpilink Dashboard + Configuration in production behind a static bearer token — two-tier auth, browser token-login, SSE auth, and the reverse-proxy / OIDC path for SSO." --- The observability Dashboard and Configuration tab are always available in local dev. To expose them on a **production** server, enpilink has an opt-in **admin plane** guarded by a bearer token. It is **off by default** and **refuses to start without a token** — it is never default-open. ## Enabling the prod admin plane Two things are required: ```bash ENPILINK_ADMIN=1 \ ENPILINK_ADMIN_TOKEN= \ node dist/__entry.js ``` Or via the CLI flag, which sets `ENPILINK_ADMIN=1` for you: ```bash ENPILINK_ADMIN_TOKEN= enpilink start --admin ``` `ENPILINK_ADMIN` accepts `1`/`true`/`yes`/`on`. If admin is enabled but `ENPILINK_ADMIN_TOKEN` is empty or unset, the process **exits non-zero with a clear error** rather than starting an unauthenticated admin plane. The token is a **static shared secret**, read from the env in-process. It is never logged, never persisted to the database, and never returned by any HTTP route. Compared against presented tokens in **constant time** to avoid timing leaks. ## Two-tier auth The admin plane has two halves with different exposure: | Surface | Auth | Why | |---|---|---| | Console **SPA shell** (HTML/JS/CSS) | **public** | So a browser can always load the app and render its own login screen | | `/__enpilink/observability/*` + `/__enpilink/config*` (**data APIs**) | **bearer-gated** | The real analytics/config data | | `/mcp` (your MCP transport) | **always public** | The MCP endpoint must stay reachable for hosts | The bearer guard is mounted at the app root but enforces auth **only on the data API paths** — the shell, static assets, and `/mcp` pass straight through. So an unauthenticated browser gets the app shell and a login prompt, but **no data leaks** until the token is presented. In dev (`ENPILINK_ADMIN` unset) nothing is guarded — today's localhost behavior is unchanged and the login screen never appears. ## Browser login and SSE auth When the data APIs return 401, the Console shows a **token-login screen**. The token is verified against the observability summary endpoint and, on success, stored in **`sessionStorage`** (cleared on tab close — never `localStorage`, never a cookie). The app then attaches `Authorization: Bearer ` to every data fetch. Because browsers' `EventSource` can't set request headers, the live-log SSE stream (`/__enpilink/observability/stream`) **also** accepts the token via a `?token=` query param. enpilink copies that into the `Authorization` header so the *same* verifier enforces it, then **strips `token` from the request URL** so the secret never reaches the route handler, `req.query`, or any logged request line. `?token=` is honored on the stream route only. ## SSO / stronger auth The built-in mechanism is the **static bearer token** — simple, dependency-free, and good for a single operator or a small team. If you need single sign-on, per-user access, or short-lived credentials, put the admin plane behind an authenticating layer: ### Reverse proxy (recommended for SSO) Terminate auth in front of enpilink and forward only authenticated traffic to the admin paths. Any of these work well: - **Cloudflare Access** — Zero Trust policies in front of `/__enpilink/*`. - **oauth2-proxy** — an OIDC/OAuth2 reverse proxy that gates the data APIs. - **Tailscale** — keep the admin plane on your tailnet (and/or use Tailscale Serve) so only your devices can reach it. Keep `/mcp` reachable to your MCP hosts when you scope the proxy's protection, and you can still set `ENPILINK_ADMIN_TOKEN` as a second factor behind the proxy. ### Self-hosted OIDC enpilink builds on the MCP SDK's auth primitives — `requireBearerAuth` and `mcpAuthMetadataRouter` exist in the dependency tree — so a self-hosted OIDC / OAuth2 setup is possible for teams that want to wire their own verifier. This is **not** a built-in turnkey feature today; treat the static token as the shipped mechanism and reach for a proxy or a custom verifier for full SSO. Be honest with yourself about exposure: the static token is the built-in. If the admin plane is reachable from the public internet, front it with one of the options above and rotate the token. ## Storage in production When admin is enabled, enpilink ensures an active storage adapter exists even if analytics *recording* is off — the admin still needs somewhere to read/write config and observability data. In production the default engine is **SQLite**. See [Storage](/guides/storage). ## Related - [Observability](/guides/observability) — what the Dashboard shows - [Configuration](/guides/configuration) — the admin token is a bootstrap secret - [Storage](/guides/storage) — the prod-default SQLite store