> For the complete documentation index, see [llms.txt](https://k-ai.gitbook.io/knowledge-ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://k-ai.gitbook.io/knowledge-ai/k-ai-mcp/oauth-flow.md).

# OAuth flow (detailed)

This page is the reference for anyone implementing a custom MCP client or debugging OAuth issues against K-AI. Both MCP servers (`api-retrieval` and `api-audit`) share a single Authorization Server at `https://auth-api.kai-studio.ai`. A token obtained against either resource server is accepted on both.

## Sequence diagram

```mermaid
sequenceDiagram
    participant C as MCP Client
    participant A as K-AI Resource API
    participant S as K-AI Auth Server
    participant U as User browser

    C->>A: GET /.well-known/oauth-authorization-server
    A-->>C: discovery metadata
    C->>S: POST /auth/oauth/register
    S-->>C: client_id, client_secret
    C->>U: open /auth/oauth/authorize with PKCE challenge
    U->>S: Login
    S-->>U: Redirect with code
    U-->>C: Deliver code
    C->>S: POST /auth/oauth/token
    S-->>C: access_token, refresh_token
    C->>A: API call with Bearer access_token
    A-->>C: Response
```

Every \~15 minutes the client refreshes the access token by calling `/auth/oauth/token` with `grant_type=refresh_token`; the response contains a new access token and a rotated refresh token.

## Step-by-step

### 1. Discovery

`GET https://api-retrieval.kai-studio.ai/.well-known/oauth-authorization-server` (or the `api-audit` equivalent — both return identical metadata). The response contains `registration_endpoint`, `authorization_endpoint`, `token_endpoint`, `revocation_endpoint`, supported response/grant types, PKCE methods, and scopes.

### 2. Dynamic Client Registration (RFC 7591)

`POST` to `/auth/oauth/register` with `client_name`, `redirect_uris`, `grant_types`, and `token_endpoint_auth_method`. The server returns a fresh `client_id` and `client_secret`. K-AI Auth supports confidential clients only — every MCP client (Claude Desktop, Cursor, Le Chat) registers with a `client_id` + `client_secret` and stores the secret locally.

### 3. Authorization request

Generate a `code_verifier` (43–128 chars), derive `code_challenge = BASE64URL(SHA256(code_verifier))`, pick a random `state`, and open the user's browser at `/auth/oauth/authorize` with `response_type=code`, `client_id`, `redirect_uri`, `scope=mcp`, `state`, `code_challenge`, `code_challenge_method=S256`. The user signs in via magic code or Microsoft SSO.

### 4. Authorization code delivery

The Authorization Server redirects to `redirect_uri?code=<code>&state=<state>`. The client must verify `state` matches what it sent.

### 5. Token exchange

`POST` to `/auth/oauth/token` with `grant_type=authorization_code`, `code`, `redirect_uri`, `client_id`, and `code_verifier`. The server returns `access_token` (JWT, 15 min TTL) and `refresh_token` (7 days TTL).

### 6. Authenticated tool calls

Subsequent tool invocations go to `https://api-retrieval.kai-studio.ai/mcp` or `https://api-audit.kai-studio.ai/mcp` with the header `Authorization: Bearer <access_token>`.

### 7. Refresh

When the access token nears expiry, `POST` to `/auth/oauth/token` with `grant_type=refresh_token`. The server returns a new access token **and** a rotated refresh token. The previous refresh token is invalidated immediately.

{% hint style="warning" %}
Token verification is performed server-side by K-AI's resource APIs, not by clients. Treat the access token as an opaque bearer credential.
{% endhint %}

## Spec details

* **PKCE:** `S256` required. Plaintext (`plain`) not accepted.
* **Token lifetimes:** access token 15 min, refresh token 7 days.
* **Refresh rotation:** mandatory. Each refresh call returns a new refresh token and invalidates the old one immediately. If a revoked refresh token is presented again, the entire token chain is revoked and the user must re-authorize.
* **Authorization code TTL:** 10 minutes, single-use.
* **Token endpoint auth methods supported:** `client_secret_basic`, `client_secret_post`. Confidential clients only — the token endpoint rejects requests without a `client_secret` with `invalid_client 401`.
* **Scope:** `mcp`.
* **DCR rate limit:** 5 requests per minute per IP.

## Endpoints

| Purpose                          | URL                                                    | Method |
| -------------------------------- | ------------------------------------------------------ | ------ |
| Discovery (from either K-AI API) | `https://<api>/.well-known/oauth-authorization-server` | GET    |
| Dynamic Client Registration      | `https://auth-api.kai-studio.ai/auth/oauth/register`   | POST   |
| Authorization                    | `https://auth-api.kai-studio.ai/auth/oauth/authorize`  | GET    |
| Token exchange and refresh       | `https://auth-api.kai-studio.ai/auth/oauth/token`      | POST   |
| Revocation                       | `https://auth-api.kai-studio.ai/auth/oauth/revoke`     | POST   |

Both `api-retrieval.kai-studio.ai` and `api-audit.kai-studio.ai` publish their own discovery document, but both point to the same Authorization Server. Register your client once; the resulting tokens are accepted on both APIs.

## Troubleshooting

* **`401` after 15 min:** access token expired. Refresh it. Most MCP clients do this automatically.
* **`invalid_grant` on refresh:** the stored refresh token is stale — an older one was used after a successful rotation. Always replace the stored refresh token with the latest one returned.
* **CSRF / state mismatch:** the `state` returned to `redirect_uri` does not match what the client sent. Persist `state` for the lifetime of the flow.
* **Microsoft SSO loop:** confirm the user's browser is not blocking third-party cookies on `auth-api.kai-studio.ai`.
* **DCR rejected (`429`):** the rate limit of 5 registrations per minute per IP was exceeded. Wait and retry.
* **`invalid_client` on token exchange:** the `client_id` does not match the one returned by DCR, or the `client_secret` is wrong or missing. K-AI Auth supports confidential clients only — every token request must carry a `client_secret`.
* **`invalid_request` with `code_verifier`:** the `code_verifier` does not match the `code_challenge` used at the authorization step. Regenerate both as a pair.

For the higher-level narrative on K-AI authentication, see [OAuth 2.1](/knowledge-ai/authentication/oauth.md).
