> For the complete documentation index, see [llms.txt](https://docs.kula.digital/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.kula.digital/for-developers/oauth.md).

# OAuth

Kula Intelligence ships a standards-based **OAuth 2.1** authorization server so MCP clients can sign a user in and receive an access token, with no token-pasting. It implements the discovery and security RFCs the MCP ecosystem relies on.

For end users, the flow is invisible — they click "connect" and sign in. This page is the detail for client developers.

> **Not every client does OAuth.** Clients without a custom-connector flow (ChatGPT, Cursor, Lovable, the Claude API, custom agents) connect with a **role-scoped access token** minted in console.kula.digital instead — the same minted MCP credential, presented as a bearer header against `https://mcp.kula.digital/mcp`. See [Connect](/for-developers/connect.md). This page covers the OAuth path used by Claude's custom connector.

## The two hosts

| Role                                 | Host               | Serves                                                                                                  |
| ------------------------------------ | ------------------ | ------------------------------------------------------------------------------------------------------- |
| **Resource server** (the MCP server) | `mcp.kula.digital` | the per-connector resource `/connect/{…}/mcp`, and its protected-resource metadata                      |
| **Authorization server**             | `app.kula.digital` | discovery, registration, authorize, token (connectors themselves are created in `console.kula.digital`) |

Clients are pointed at a **role-scoped connect link** (`https://mcp.kula.digital/connect/{…}/mcp`) created in console.kula.digital — there is no open `/mcp` endpoint to connect to. The resource advertises the authorization server, so a compliant client only needs the connect link to discover everything else. For a connect link, the protected-resource metadata is path-scoped: `/.well-known/oauth-protected-resource/connect/{…}/mcp`.

## Discovery

1. **Protected-resource metadata** (RFC 9728):

   ```
   GET https://mcp.kula.digital/.well-known/oauth-protected-resource
   ```

   Returns the canonical resource URL and the `authorization_servers` list (pointing at `app.kula.digital`).
2. **Authorization-server metadata** (RFC 8414):

   ```
   GET https://app.kula.digital/.well-known/oauth-authorization-server
   ```

   Returns the `authorization_endpoint`, `token_endpoint`, `registration_endpoint`, `code_challenge_methods_supported` (`["S256"]`), `grant_types_supported` (`authorization_code`, `refresh_token`), and `scopes_supported`.

## Dynamic client registration (RFC 7591)

Clients may self-register:

```
POST https://app.kula.digital/oauth/register
{ "redirect_uris": ["https://your-app.example/callback"], "client_name": "…" }
```

Returns a `client_id` (and a secret only for confidential clients; public clients use `token_endpoint_auth_method: "none"` with PKCE).

For Claude's hosted clients, register the callback `https://claude.ai/api/mcp/auth_callback`. For Claude Code, **loopback redirects** on `http://localhost:<port>` are accepted with port-agnostic matching.

## Authorization + token

* **Authorize** (`GET /oauth/authorize`) requires `response_type=code`, `code_challenge`, and `code_challenge_method=S256` (**PKCE is mandatory**). The user is signed in (delegated to our identity provider), consents, and is redirected back with a `code`.
* **Token** (`POST /oauth/token`) accepts `application/x-www-form-urlencoded` for the `authorization_code` grant (with `code_verifier`) and the `refresh_token` grant. Refresh tokens are **rotated** on use. Responses carry `Cache-Control: no-store`.

The access token is the same minted MCP token the runtime verifies — OAuth adds consent and discovery without introducing a new token type.

## Scopes

The OAuth `scope` maps to Kula's [permission levels](/connect-claude-and-access/scopes.md):

| Scope            | Means                                                        |
| ---------------- | ------------------------------------------------------------ |
| `analytics`      | Aggregates only; no personal data                            |
| `operations`     | Member/staff names visible; contact + payment details hidden |
| `admin`          | Emails/phones visible; payment details hidden                |
| `full`           | Everything; every call recorded                              |
| `offline_access` | Issue a refresh token                                        |

Request the **lowest** scope the integration needs.

## Audience binding

Tokens are bound to the canonical MCP resource URL (RFC 8707 resource indicator). The runtime verifies the token's audience, so a token minted for Kula can't be replayed against a different server.

## Revocation

Connectors are revocable from console.kula.digital and stop working within about a minute. Clients should handle a `401` by re-running the OAuth flow; if the connect link itself has been revoked or used up, the user creates a fresh connector.
