# Kapso authentication

Kapso supports OAuth Authorization Code with PKCE S256 for MCP clients. A user must sign in, select a project they can access, and approve the connection in their browser. This guide documents existing OAuth behavior; it does not advertise WorkOS agent-auth compatibility.

## Discover the MCP resource

The MCP endpoint is `https://api.kapso.ai/mcp`.

1. Read `https://api.kapso.ai/.well-known/oauth-protected-resource/mcp`. An unauthenticated MCP request also returns a 401 challenge with a `resource_metadata` URL in `WWW-Authenticate`.
2. Use the returned `resource` as the OAuth `resource` parameter. Read the authorization server's `/.well-known/oauth-authorization-server` metadata using the URL in `authorization_servers`.
3. Use the advertised `registration_endpoint`, `authorization_endpoint`, `token_endpoint`, and `revocation_endpoint`. Validate that the metadata `issuer` matches the authorization server you discovered.

Keep the same resource URL throughout authorization, token exchange, and refresh. If you use another supported Kapso API domain, start discovery on that domain and keep its returned URLs together.

## Register an MCP client

POST JSON to `registration_endpoint`, for example:

```json
{
  "client_name": "My MCP client",
  "redirect_uris": ["http://localhost:8765/callback"],
  "token_endpoint_auth_method": "none",
  "grant_types": ["authorization_code", "refresh_token"],
  "response_types": ["code"]
}
```

Use a callback your client controls. Redirect URIs must use HTTPS, except localhost HTTP callbacks. The response contains a `client_id`; public clients receive no client secret. Use the exact registered redirect URI, including its port and path.

Dynamic registration grants only `mcp:project` (use project MCP tools). The server also advertises `native:project`, `native:inbox`, and `native:workers` for configured first-party native clients; these scopes are not available through dynamic MCP registration. Client registration alone grants no project access.

## Request user consent

Generate a fresh cryptographically random PKCE `code_verifier` and a `code_challenge` equal to BASE64URL(SHA256(code_verifier)), without padding. Generate a random `state` and retain both values securely for this authorization attempt.

Open `authorization_endpoint` in the user's browser with URL-encoded query parameters:

```text
response_type=code
client_id=<registered client_id>
redirect_uri=<exact registered redirect URI>
scope=mcp:project
resource=<resource from discovery>
code_challenge=<PKCE challenge>
code_challenge_method=S256
state=<random state>
```

The user signs in and approves one selected project. All-project access is not supported. At your callback, verify `state` matches the value you stored before accepting the authorization `code`.

## Exchange the code and call MCP

POST form-encoded fields to `token_endpoint`:

```text
grant_type=authorization_code
code=<callback code>
client_id=<registered client_id>
redirect_uri=<exact registered redirect URI>
code_verifier=<original PKCE verifier>
resource=<resource from discovery>
```

The response includes `access_token`, `token_type` (`Bearer`), `expires_in` (seconds), `refresh_token`, and `scope`. Authorization codes are short-lived and single-use.

Send the access token to the MCP endpoint in the `Authorization: Bearer <access_token>` header. Access is bound to the approved project and scope.

## Refresh and revoke

Before the access token expires, POST form-encoded `grant_type=refresh_token`, `refresh_token=<current refresh token>`, and `resource=<same resource>` to `token_endpoint`.

Refresh rotates the tokens. Securely replace the stored access and refresh tokens with the returned pair, and serialize refresh requests for each connection. Reusing an older refresh token outside the short retry window revokes the grant. If refresh returns `invalid_grant`, start a new user authorization flow instead of repeatedly retrying the old token. Loss of project app access also prevents refresh.

To disconnect, POST form-encoded `token=<access or refresh token>` to `revocation_endpoint`. Revoking a recognized token revokes the entire associated grant, including its access and refresh tokens. The endpoint returns 200 for unknown tokens too; this does not prove a token was previously valid.

## Errors and credential handling

- Invalid registration metadata returns `invalid_client_metadata`; correct the registration request.
- Token errors include `invalid_grant`, `invalid_target`, and `unsupported_grant_type`. For `invalid_target`, check that the resource matches the authorization request. Do not retry unchanged invalid requests indefinitely.
- Rate-limited requests return 429; back off before retrying.
- Keep tokens and PKCE verifiers out of logs, URLs, source control, and shared transcripts. Store credentials securely and transmit them over HTTPS.
- User consent happens in the browser. There is no claim or device polling flow in this OAuth integration.
- Anonymous agent access, `/agent/identity`, ID-JAG assertions, and agent-auth event endpoints are not supported by this flow.

Existing project API key connections are also supported by MCP. Use the project API key as a Bearer token, keep it private, and follow the MCP documentation at https://docs.kapso.ai/docs/whatsapp/mcp. Project API keys are separate from OAuth tokens and do not use the OAuth refresh or revocation endpoints.
