# Authentication (https://docs.ctxpipe.ai/docs/self-hosting/authentication)

ctxpipe uses [Better Auth](https://www.better-auth.com) for identity management.
All browser sign-in, provider callbacks, sessions, and MCP OAuth flow through the
same public backend origin.

## Required auth boundary

| Variable               | Requirement                                                                            |
| ---------------------- | -------------------------------------------------------------------------------------- |
| `AUTH_SECRET`          | A stable random value of at least 32 characters. Generate with `openssl rand -hex 32`. |
| `AUTH_BASE_URL`        | The public HTTPS backend origin users and providers can reach.                         |
| `AUTH_ALLOWED_ORIGINS` | Optional comma-separated extra browser origins. Keep this list narrow.                 |
| `SMTP_CONNECTION_URL`  | Required for email verification, password reset, and invitation email delivery.        |
| `EMAIL_FROM_ADDRESS`   | The sender address for transactional email.                                            |

`AUTH_SECRET` protects sessions and encrypted auth material. Do not generate a
new value on every deploy. Rotating it can invalidate sessions and prevent
existing encrypted signing keys from being read; treat rotation as a planned
operational change.

<Callout type="warn" title="One public origin">
  Open the product through `AUTH_BASE_URL`. Do not send browser users directly
  to the private UI service. Provider callbacks, MCP OAuth, cookies, and the API
  rely on a consistent origin.
</Callout>

## Email and password

Email/password sign-in is available by default. Configure SMTP before inviting a
team so verification, invitation, and password-reset messages leave the
deployment reliably.

With SMTP and `EMAIL_FROM_ADDRESS` set, new email/password accounts verify
their address before they can sign in. An unverified account that signs in is
sent a fresh link. Resetting a password also verifies the address, and signs
out the account's other sessions. Without SMTP, messages are only logged, so
verification is not required and the backend logs a warning at startup.

## Social providers (OAuth)

ctxpipe supports GitHub, Google, and Microsoft social sign-in.
Each provider is enabled conditionally - if the corresponding client ID and
secret are set in the backend environment, the sign-in option appears.

| Provider  | Env vars required                                |
| --------- | ------------------------------------------------ |
| GitHub    | `GITHUB_CLIENT_ID`, `GITHUB_CLIENT_SECRET`       |
| Google    | `GOOGLE_CLIENT_ID`, `GOOGLE_CLIENT_SECRET`       |
| Microsoft | `MICROSOFT_CLIENT_ID`, `MICROSOFT_CLIENT_SECRET` |

<Callout type="info">
  GitHub social sign-in credentials are separate from the deployment-owned
  [GitHub App](/docs/self-hosting/github) used for repositories and connector
  writes.
</Callout>

Register each provider callback under `AUTH_BASE_URL`. Test sign-in through the
same public origin users will use in production.

## Passkeys and two-factor authentication

Passkeys are available on compatible browsers and platforms. Users can also
enable TOTP two-factor authentication with a standard authenticator app. Verify
both through your production TLS domain; WebAuthn credentials are origin-bound.

## MCP OAuth and API keys

ctxpipe is an OAuth provider for downstream MCP clients. It supports discovery,
dynamic client registration, and device authorization for compatible headless
clients.

Configure the client with:

```text
{AUTH_BASE_URL}/mcp
```

Each OAuth grant holds a set of organizations. The user selects the organizations
on the consent screen, and the user can change the set later on the
**Connected apps** page (`/.auth/account/connected-apps`). Each tool call names
one organization with the `org` argument. The server allows the call only when
the organization is in the grant set and the user is still a member of it.

For the old `?orgSlug=` URL parameter, see [MCP](/docs/self-hosting/mcp).

OAuth is the normal MCP flow for people. The consent screen grants
`ctxpipe:read` and `offline_access`. It also offers **Also allow changes**
(`ctxpipe:write`) when a client asks for it. The MCP tools need only
`ctxpipe:read`. API keys never hold `ctxpipe:write`.

| Token                                   | Lifetime                                                   |
| --------------------------------------- | ---------------------------------------------------------- |
| Browser session                         | 30 days                                                    |
| OAuth access token                      | 4 hours, renewed with the refresh token (`offline_access`) |
| OAuth access token with `ctxpipe:write` | 1 hour                                                     |

API keys are stored in the database of this deployment, so there is no
operator secret to configure. For personal and organization keys, the headers,
and the client setup, see [API keys](/docs/mcp/api-keys). When discovery or
authorization fails, see [MCP diagnostics](/docs/self-hosting/mcp).

## Production checks

* `AUTH_SECRET` is stable across backend instances and deploys.
* `AUTH_BASE_URL` exactly matches the browser origin.
* Provider callbacks use HTTPS and the same host.
* Extra trusted origins are explicit rather than wildcarded.
* SMTP can deliver invitation and reset messages.
* Passkey registration and TOTP sign-in work on the production domain.
* An MCP client can discover OAuth and complete authorization.
