Skip to main content

Authentication

Mesachat authenticates with Clerk. Every request under /api needs a valid principal unless its path is on a short, explicit allowlist.

Derived from backend/src/auth/.

The gate is fail-closed

There is one mandatory checkpoint — apiAuthGate, mounted once before the route table (backend/src/api/server.ts). Being authenticated is the default; being public is the exception, and the exceptions are enumerated in code rather than opted into per router.

Two consequences worth knowing before you debug a 401:

  • Guards do not pass through when Clerk is unconfigured. A deployment with no Clerk credentials does not become open; it refuses everything under /api.
  • The gate matches case-insensitively. Express routes case-insensitively by default, so /API/bots reaches the router mounted at /api/bots. The gate lowercases the path first, so the casing trick does not slip past it.

Sending credentials

Pass a Clerk session token as a bearer token:

curl -H "Authorization: Bearer $CLERK_SESSION_TOKEN" \
http://localhost:3001/api/bots

In the web app and admin console this is handled for you — the browser holds a Clerk session and the app attaches the token.

For scripted access, mint a session token with Clerk's Backend API for a user that already has the membership you need. Mesachat does not issue its own long-lived API tokens; there is no "create an API key for the REST API" endpoint. (/api/keys manages provider keys — your OpenAI or Anthropic credentials — not credentials for this API. See REST API.)

Tenant scope comes from the token

Tenant scope is derived from the authenticated principal, never from client input. Sending tenantId in a body or query string does not select a tenant, and cannot be used to reach one you are not a member of. Where a tenantId appears in a path it is validated against the caller before the handler runs.

This is a load-bearing security property, not a convention. Do not design a client around passing a tenant identifier as data.

Endpoints reachable without authentication

Exactly four prefixes are allowlisted (PUBLIC_API_PREFIXES, backend/src/auth/clerk-middleware.ts):

PrefixWhy it is public
/api/healthLiveness probe
/api/otelTelemetry ingest proxy
/api/telegram-authTelegram login flow — you cannot require a session to establish one
/api/email-authEmail sender verification flow, same reason

Anything matching a prefix, or a path beneath it, passes through. Everything else under /api requires a principal.

Two paths that look public and are not:

  • /api/auth is the authorization administration router — rules, moderation, channel grants. It is not a login endpoint, and it requires authentication.
  • /api/tenant selects the active tenant for an existing session, so it needs one.

/webhooks/* is a separate surface outside /api. It is not covered by this gate at all; each handler verifies its own signature. See Webhooks.

Telegram login

The flow lives under /api/telegram-auth, not /api/auth/telegram:

MethodEndpointPurpose
GET/api/telegram-auth/configWidget configuration for the client
GET/api/telegram-auth/callbackWhere the Telegram Login Widget returns
POST/api/telegram-auth/completeCompletes the login and establishes the session
GET/api/telegram-auth/statusCurrent state of an in-flight login

Email sender authorization

/api/email-auth verifies that an email address may talk to a bot, and manages the resulting grants: /validate-token, /check-tenant-access, /authorization-groups, /authorize-thread, /authorized-threads, and /senders.

Local development

AUTH_DEV_MODE=true injects a synthetic admin principal so you can work without Clerk credentials.

It is refused outside local environments. The bypass is honoured only when NODE_ENV is development or test; with AUTH_DEV_MODE=true under any other NODE_ENV, startup throws rather than silently ignoring the flag. There is no configuration that makes it work in production or staging.

After authentication

Authentication establishes who the caller is. What they may reach is a separate decision, made by the dual ReBAC + ABAC authorization system:

  1. Identity — who the caller is (Clerk)
  2. Relationships — what they are connected to (ReBAC)
  3. Policies — under what conditions that connection permits the action (ABAC)

See Authorization.