# OAuth 2.1

Both **K-AI MCP** and the **Audit API** use OAuth 2.1 for authentication. Two kinds of callers:

* **Browsers** — use the `kai_auth` HttpOnly cookie set by `https://auth.kai-studio.ai` after login. Transparent to your application code. See [Cookies](/knowledge-ai/authentication/cookies.md).
* **MCP clients & custom integrations** — use the full OAuth 2.1 Authorization Code + PKCE flow with Dynamic Client Registration. This page documents that flow.

## Authorization Server

All OAuth endpoints live on **`https://auth-api.kai-studio.ai`**, with a discovery document mirrored on each API:

* `GET https://api-retrieval.kai-studio.ai/.well-known/oauth-authorization-server`
* `GET https://api-audit.kai-studio.ai/.well-known/oauth-authorization-server`

Both discovery documents return identical metadata pointing to the same Authorization Server. A token issued via either surface is accepted on both APIs.

## Flow overview

```mermaid
sequenceDiagram
    participant C as MCP client
    participant A as K-AI Auth Server
    participant U as User browser
    C->>A: POST /auth/oauth/register
    A-->>C: client_id, client_secret
    C->>U: open /auth/oauth/authorize with PKCE challenge
    U->>A: Sign in (magic code or Microsoft SSO)
    A-->>U: Redirect with authorization code
    U-->>C: Deliver code
    C->>A: POST /auth/oauth/token (code + code_verifier)
    A-->>C: access_token + refresh_token
```

## Flow for MCP clients & custom integrations

### 1. Discover

Fetch the Authorization Server metadata from the API you want to use:

```http
GET https://api-retrieval.kai-studio.ai/.well-known/oauth-authorization-server
```

Response:

```json
{
  "issuer": "https://auth-api.kai-studio.ai",
  "authorization_endpoint": "https://auth-api.kai-studio.ai/auth/oauth/authorize",
  "token_endpoint": "https://auth-api.kai-studio.ai/auth/oauth/token",
  "registration_endpoint": "https://auth-api.kai-studio.ai/auth/oauth/register",
  "revocation_endpoint": "https://auth-api.kai-studio.ai/auth/oauth/revoke",
  "response_types_supported": ["code"],
  "grant_types_supported": ["authorization_code", "refresh_token"],
  "code_challenge_methods_supported": ["S256"],
  "token_endpoint_auth_methods_supported": ["client_secret_basic", "client_secret_post"],
  "scopes_supported": ["mcp"]
}
```

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

Register your client to obtain a `client_id` and `client_secret`:

```http
POST https://auth-api.kai-studio.ai/auth/oauth/register
Content-Type: application/json

{
  "client_name": "My MCP Client",
  "redirect_uris": ["https://my-app.example.com/callback"],
  "grant_types": ["authorization_code", "refresh_token"],
  "token_endpoint_auth_method": "client_secret_post"
}
```

Response (`201 Created`):

```json
{
  "client_id": "<generated-uuid>",
  "client_secret": "<generated-secret>",
  "client_name": "My MCP Client",
  "redirect_uris": ["https://my-app.example.com/callback"],
  "grant_types": ["authorization_code", "refresh_token"],
  "token_endpoint_auth_method": "client_secret_post"
}
```

{% hint style="info" %}
**Store `client_secret` securely.** It is returned only once and cannot be retrieved later.
{% endhint %}

Registration is rate-limited (5 requests per minute per IP). In production, localhost redirect URIs are rejected.

### 3. Authorize (Authorization Code + PKCE)

Generate a PKCE code verifier and challenge:

1. Create a random `code_verifier` (43-128 characters, `[A-Za-z0-9\-._~]`).
2. Compute `code_challenge = BASE64URL(SHA256(code_verifier))`.
3. Generate a random `state` parameter for CSRF protection.

Redirect the user's browser to:

```
https://auth-api.kai-studio.ai/auth/oauth/authorize
  ?response_type=code
  &client_id=<client_id>
  &redirect_uri=https://my-app.example.com/callback
  &code_challenge=<code_challenge>
  &code_challenge_method=S256
  &state=<state>
  &scope=mcp
```

If the user is not logged in, they are redirected to the K-AI login page. Local sign-in is passwordless: users request a one-time code by email, type it on the K-AI login screen, and receive a session. Microsoft SSO is the alternative for tenants that have configured it. After authentication, the Authorization Server issues an authorization code and redirects back:

```
https://my-app.example.com/callback?code=<authorization_code>&state=<state>
```

Verify that `state` matches the value you sent. Authorization codes expire after **10 minutes** and are single-use.

### 4. Exchange code for tokens

```http
POST https://auth-api.kai-studio.ai/auth/oauth/token
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code
&code=<authorization_code>
&redirect_uri=https://my-app.example.com/callback
&client_id=<client_id>
&client_secret=<client_secret>
&code_verifier=<code_verifier>
```

Response:

```json
{
  "access_token": "<jwt>",
  "refresh_token": "<opaque-token>",
  "token_type": "Bearer",
  "expires_in": 900
}
```

* **Access token**: JWT, valid for **15 minutes** (`expires_in: 900`).
* **Refresh token**: opaque, valid for **7 days**. Rotated on every use (see below).

Client authentication supports both `client_secret_post` (credentials in form body) and `client_secret_basic` (HTTP Basic `Authorization` header).

{% hint style="warning" %}
**Validate tokens server-side.** Do not attempt to verify tokens client-side. Treat the access token as an opaque Bearer credential and let the resource API perform validation.
{% endhint %}

### 5. Call the API

Include the access token as a Bearer token:

```http
POST https://api-retrieval.kai-studio.ai/retrieval/semantic-nodes/search
Authorization: Bearer <access_token>
Content-Type: application/json

{
  "query": "What are the safety requirements?",
  "instance_id": "<instance-id>"
}
```

The same token works on both `api-retrieval.kai-studio.ai` and `api-audit.kai-studio.ai`.

### 6. Refresh

When the access token expires, use the refresh token to obtain a new pair:

```http
POST https://auth-api.kai-studio.ai/auth/oauth/token
Content-Type: application/x-www-form-urlencoded

grant_type=refresh_token
&refresh_token=<refresh_token>
&client_id=<client_id>
&client_secret=<client_secret>
```

Response: same shape as step 4, with a **new** access token and a **new** refresh token.

{% hint style="warning" %}
**Forced rotation.** The old refresh token is revoked immediately upon use. You must store the new refresh token from each response. If a revoked refresh token is presented again, the entire token chain is revoked and the user must re-authorize — this is a security measure against token theft.
{% endhint %}

### 7. Revoke (optional, on logout)

```http
POST https://auth-api.kai-studio.ai/auth/oauth/revoke
Content-Type: application/x-www-form-urlencoded

token=<refresh_token>
```

Returns `200 OK` regardless of whether the token was valid (per RFC 7009).

## Microsoft SSO

Microsoft SSO is supported transparently to your OAuth flow. From the OAuth client's perspective nothing changes — you hit `/auth/oauth/authorize`, the user lands on the K-AI login page, and the Authorization Server returns an authorization code that exchanges for a K-AI access token. The user-visible difference is a "Sign in with Microsoft" button on the login page alongside the default magic-code form; users with a matching K-AI account complete sign-in through their Microsoft tenant. K-AI does not auto-provision accounts.

## Why not a simple API key for end-users?

The KAI Instance API uses static API keys because it serves machine-to-machine pipelines with no user identity. For human users and LLM agents acting on behalf of humans, OAuth 2.1 provides what API keys cannot: per-user identity (enabling group-aware access control), token expiration and revocation (limiting blast radius if a credential leaks), and audit trails (knowing which user accessed which instance and when).

## MCP-specific notes

* Both `api-audit.kai-studio.ai` and `api-retrieval.kai-studio.ai` publish their own `/.well-known/oauth-authorization-server` document, but both point to the **same** Authorization Server. Register your client once.
* Access tokens are accepted on both APIs without re-registration or re-authorization.
* MCP clients should transparently refresh access tokens every \~15 minutes. Claude Desktop, Cursor, and Le Chat handle this automatically when configured with a [K-AI MCP](/knowledge-ai/k-ai-mcp/mcp.md) server URL.
* The MCP endpoints (`/mcp` on each API) use Bearer token authentication, not cookies. Cookie auth is reserved for browser-based applications — see [Cookies](/knowledge-ai/authentication/cookies.md).


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://k-ai.gitbook.io/knowledge-ai/authentication/oauth.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
