chmonitor
Authentication

Clerk

Authenticate chmonitor users with Clerk — browser sign-in via __session cookie, with optional public read-only mode and MCP OAuth support.

Use Clerk when you want browser-based sign-in with user accounts. The browser authenticates via a Clerk __session cookie, verified networklessly on each /api/v1/* call. The MCP server additionally accepts Clerk OAuth bearer tokens.

  • Browser clients sign in through Clerk's hosted UI.
  • The __session cookie is sent automatically same-origin and verified on the server using the Clerk secret key — no network call per request.
  • The publishable key must be present at build time so the client-side gate enables Clerk UI (sign-in button, user menu). The secret key is read at runtime.

Prerequisites

A Clerk application with its publishable and secret keys. The client VITE_AUTH_PROVIDER / VITE_CLERK_PUBLISHABLE_KEY values are derived from the canonical CHM_* names at build time, so set them before bun run build. CLERK_SECRET_KEY (the sk_... key) is the runtime secret and stays server-side.

Migrating from Next.js?

If migrating from the legacy Next.js app, see Migrate to v0.3 for the NEXT_PUBLIC_*VITE_* rename.

Setup

Prop

Type

Create a Clerk application

Create a Clerk application at clerk.com.

Copy your keys

Copy the Publishable key (pk_live_...) and Secret key (sk_live_...) from the Clerk dashboard.

Set build-time env vars

Set these before building the client (the client VITE_* values are derived from them):

CHM_AUTH_PROVIDER=clerk
CHM_CLERK_PUBLISHABLE_KEY=pk_live_...

Set runtime env vars

Set these on the server (or as Worker secrets):

CHM_AUTH_PROVIDER=clerk
wrangler secret put CLERK_SECRET_KEY   # paste sk_live_...

Rebuild and redeploy

The sign-in button appears in the header after redeploy.

Verify

After redeploy, the sign-in button appears in the header. Sign in through Clerk's hosted UI, then confirm data loads on the dashboard — an authenticated __session cookie satisfies the guard on every /api/v1/* call.

Clerk OAuth for MCP

The MCP server at /api/mcp also accepts Clerk OAuth bearer tokens. Clerk acts as the authorization server (login, consent, dynamic client registration); chmonitor is the resource server and verifies tokens via Clerk's REST introspection. This lets MCP clients use an OAuth flow instead of a chm_ API key. It uses the same CLERK_SECRET_KEY — no extra configuration needed.

See MCP Server for connection details.

Gate features to authenticated users

Most features are public even with Clerk enabled. The AI agent (agent) and control actions (actions — KILL QUERY, OPTIMIZE TABLE) default to authenticated, so they require sign-in. To change a feature's access:

CHM_FEATURE_AGENT_ACCESS=public          # loosen the agent to public
CHM_FEATURE_TABLES_ACCESS=authenticated  # require sign-in for tables

See Feature Permissions for all feature ids and options.

Public read-only mode

By default, Clerk gates every /api/v1/* request — an anonymous visitor sees the dashboard shell but no data (every data call returns 401). Set CHM_CLERK_PUBLIC_READ to let anonymous visitors view read-only monitoring content while keeping sign-in required for writes:

CHM_AUTH_PROVIDER=clerk
CHM_CLERK_PUBLIC_READ=true   # runtime / Worker var

Access is then split along a read / write boundary:

  • Reads — predefined monitoring data (overview, queries, tables, metrics, charts, schema browsing) — serve to anonymous visitors.
  • Writes — the AI agent, control actions (KILL QUERY, OPTIMIZE TABLE), and arbitrary SQL execution (SQL Console / explorer query) — still return 401 for anonymous callers. Running attacker-chosen SQL is treated as a write even though it runs read-only, because it is a far more powerful capability than a fixed registry query.
  • API keys (chm_ bearer tokens) and signed-in Clerk users get full read + write.

Anonymous capability matrix

Auth modeAnonymous readAnonymous write
none✅ (everyone is authenticated)
clerk + CHM_CLERK_PUBLIC_READ=true
clerk (default)
proxy❌ (proxy authenticates upstream)

The flag only applies to the clerk provider — none is already fully public and proxy fronts its own auth. It is off by default, so existing locked-down Clerk deployments are unchanged. The client reads these flags from GET /api/v1/config (capabilities.read / capabilities.write) to decide what to surface.

On this page