> ## Documentation Index
> Fetch the complete documentation index at: https://devs.izap.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Authentication

> OAuth 2.0 and JWT bearer tokens for the iZap API and MCP server.

Both the REST API and the MCP server are protected by the same OAuth 2.0
authorization server, mounted at `{origin}/oauth`. Every request carries a JWT as
a Bearer token.

## Quick token (server-to-server)

For backend services and scripts, exchange account credentials for a JWT:

```bash theme={null}
curl -X POST "https://api.izap.ai/api/v1/auth/jwt/login" \
     -H "Content-Type: application/x-www-form-urlencoded" \
     -d "username=$IZAP_EMAIL&password=$IZAP_PASSWORD"
# -> {"access_token":"<JWT>","token_type":"bearer"}
```

Then send it on every request:

```
Authorization: Bearer <access_token>
```

## OAuth 2.0 (third-party apps)

Use the authorization-code + PKCE flow for clients that act on behalf of a user.

### Discovery

Clients discover the authorization server via standard metadata documents:

| Document                          | Path                                        |
| --------------------------------- | ------------------------------------------- |
| Authorization server metadata     | `/.well-known/oauth-authorization-server`   |
| Protected resource metadata (MCP) | `/.well-known/oauth-protected-resource/mcp` |

The MCP endpoint returns `401` with a `WWW-Authenticate` header, so spec-compliant
MCP clients bootstrap the OAuth flow automatically.

### Flow

1. `GET /oauth/authorize` with `response_type=code`, `client_id`, `redirect_uri`,
   `code_challenge`, `code_challenge_method=S256`, and `state`.
2. The user authenticates and approves; iZap redirects back with `code`.
3. `POST /oauth/token` with `grant_type=authorization_code`, `code`,
   `redirect_uri`, and `code_verifier` → returns an `access_token` (JWT) and a
   `refresh_token`.

Public clients may self-register via `POST /oauth/register`. Refresh an expired
token with `grant_type=refresh_token`.

## Token notes

* The access token is a JWT — treat it as a secret and read it from an environment
  variable, never hardcode it.
* Tokens expire. Refresh (re-login or the OAuth refresh grant) when a request
  returns `401`.
