> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mesh.texturehq.com/llms.txt
> Use this file to discover all available pages before exploring further.

# External authentication

> Delegate operator sign-in while preserving explicit identity and access boundaries.

Mesh defaults to local email-and-password login. External mode delegates browser
sign-in to a trusted service that implements Mesh's **launch-code protocol**.
Mesh verifies its signed assertion and creates a short-lived local session.
This is not a generic OIDC discovery, OAuth login, or SAML integration; an identity
provider needs an adapter that implements the protocol below.

External mode disables local password login, first-administrator setup, and local
invitation flows. Configure and test the external service before switching the
instance. It changes operator authentication, not a conversational participant's
[identity links](/runtime/identity-linking).

## Configuration

Set these on the Mesh process and restart it:

| Variable | Purpose |
| - | - |
| `MESH_AUTH_MODE` | `external` enables launch login; default is `local`. |
| `PUBLIC_URL` | Browser-facing HTTPS origin, without a path, query, user information, or fragment. |
| `MESH_INSTANCE_ID` | Instance identifier shared with the external service. |
| `MESH_AUTH_ISSUER` | Exact expected assertion issuer (`iss`). |
| `MESH_AUTH_AUDIENCE` | Exact expected assertion audience (`aud`). |
| `MESH_AUTH_AUTHORIZE_URL` | Browser authorization endpoint that starts the external login. |
| `MESH_AUTH_EXCHANGE_URL` | Server endpoint that exchanges a launch code for an assertion. |
| `MESH_AUTH_EXCHANGE_SECRET` | Secret sent as a Bearer credential to the exchange endpoint. |
| `MESH_AUTH_JWKS_URL` | Endpoint supplying public signing keys in JWKS format. |

Every field is required in external mode. `PUBLIC_URL` must be HTTPS even for a
development instance using this flow. Other endpoint URLs require HTTPS except
that configuration permits HTTP in `MESH_ENV=development` or `test`, or for hosts
ending in `.internal`. That hostname exception is a deployment assumption, not
proof that the network is private.

Register the exact callback `PUBLIC_URL/auth/callback` with the external service.
The authorization endpoint must be reachable by the browser; exchange and JWKS
endpoints must be reachable by the Mesh server. Keep the exchange secret out of
browser configuration and source control.

## Launch protocol

1. The browser opens `GET /api/auth/external/start`. Mesh creates a five-minute
   launch cookie containing a random state and verifier.
2. Mesh redirects to the authorization URL with `instance_id`, `state`,
   `challenge` (base64url SHA-256 of the verifier), and `redirect_uri`.
3. The external service authenticates the operator and redirects to
   `/auth/callback?code=...&state=...`.
4. Mesh checks the returned state, then POSTs JSON containing `code`,
   `code_verifier`, and `instance_id` to the exchange URL, authenticated with
   `Authorization: Bearer MESH_AUTH_EXCHANGE_SECRET`.
5. The exchange service returns HTTP 200 with `{"assertion":"SIGNED_JWT"}`.
   Mesh verifies it, consumes its unique ID against replay, and opens a local
   session before redirecting to `/agents`.

The external service must bind its codes to the instance, redirect, and challenge
and validate the verifier during exchange. Its implementation is outside this
repository. JWKS and exchange HTTP calls each have a ten-second client timeout.

## Assertion requirements

Mesh accepts an ES256 JWT with header `typ: mesh-launch+jwt` and a `kid` selecting
an EC P-256 key from the configured JWKS. The payload must contain:

* Matching `iss`, string `aud`, and `instance_id`.
* Nonempty `sub` and single-use `jti`.
* `token_use: mesh_launch` and `schema_version: 1`.
* `email_verified: true` and an email for first-time profile creation.
* A `capabilities` array containing `mesh:admin`.
* `iat`, `nbf`, and `exp` compatible with the verifier's time checks: maximum
  declared lifetime 90 seconds and 30 seconds of allowed clock skew.

The external service is responsible for deciding who may receive that capability.
Mesh's operator roles and agent-access checks still govern the resulting user's
API access; see the [operator API](/operator-api).

## Accounts and sessions

An external user is identified by **`(issuer, subject)`**, never by email.
Different external identities can share an email, and an external identity can
share one with a local account. Sign-in does not claim the older account, change
its password, transfer its API tokens, or rewrite its attribution. The operator
roster can therefore show distinct users with the same email.

External sessions last **15 minutes** and use the secure, HttpOnly, host-only
`__Host-mesh_session` cookie. Session records are held by Mesh. Logout or local
session revocation ends that Mesh session; this flow does not implement logout
from the external identity provider. Disabling a Mesh operator also blocks their
session access.

Switching back to local mode does not give external users passwords. Local
password and invitation lookups consider local accounts only. Preserve existing
identity mappings and use a compatible database/binary when changing auth modes;
do not repair a login issue by merging accounts on email.

Implementation: [`internal/admin/auth_external.go` (repository)](https://github.com/TextureHQ/mesh/blob/main/internal/admin/auth_external.go),
[`internal/admin/jwt.go` (repository)](https://github.com/TextureHQ/mesh/blob/main/internal/admin/jwt.go),
and [`internal/config/config.go` (repository)](https://github.com/TextureHQ/mesh/blob/main/internal/config/config.go).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.