---
title: "API Authentication"
description: "Authenticate with the ComStack API using OAuth 2.1, API keys, or Firebase tokens for various client types."
url: "https://comstack.ai/docs/api/authentication/"
---
## What is this

The ComStack API accepts three types of credentials. Which one to use depends on who is making the call and from where.

| Client | Credential | Notes |
|---|---|---|
| AI Assistants via MCP (Claude, Cursor) | OAuth 2.1 Bearer | Project routing per tool. |
| Headless services and CI via MCP | `x-api-key` + `x-project-id` headers | Limited to one project. |
| Web portal, Chrome extension, live voice | Firebase ID Token (`Authorization: Bearer`) | Used by dashboard SPAs and live voice. |

## How it works

### OAuth 2.1 (for AI agent clients)

OAuth 2.1 with PKCE (RFC 7636) and Dynamic Client Registration (RFC 7591):

1. **Discovery** — `GET /.well-known/oauth-authorization-server` returns endpoint URLs and the supported PKCE method (`S256`).
2. **Registration** — `POST /oauth/register` registers the client and returns a `client_id`. No client secret.
3. **Authorization** — `GET /oauth/authorize` displays the Firebase Auth login page.
4. **Code Issuance** — `POST /oauth/authorize/complete` issues an authorization code after login.
5. **Token Exchange** — `POST /oauth/token` returns an access token (1-hour TTL) and a refresh token (30-day TTL).
6. **Usage** — every `POST /mcp` includes `Authorization: Bearer <access_token>`.

Refresh tokens are auto-rotated on every use. Presenting a previously rotated refresh token revokes the entire token family (protection against replay attacks).

### API Keys (for machine clients)

Both headers are mandatory in every `POST /mcp` request:

```
x-api-key:    <raw_key>
x-project-id: <project_id>
```

Keys are scoped to a single project. A `project_id` argument that does not match the key's scope returns `InvalidRequest`. Service keys are the recommended long-term path for headless clients.

### Firebase ID Token (dashboard, Chrome extension)

All `/api/*` routes use Firebase Auth JWTs in `Authorization: Bearer <token>`. The token expires after 1 hour. Refresh using `user.getIdToken(true)`.

Role-based middleware verifies project membership on every request. The minimum role required by the endpoint is applied: `manager` for destructive operations, any member for reads.

## When to use each

- **OAuth**: Human-oriented integration where the user logs in; the standard path for Claude and Cursor.
- **API Key**: CI pipelines, scheduled tasks, server-to-server integrations.
- **Firebase Token**: Custom web interface built on Firebase Auth.

## Parameters / fields / inputs

OAuth endpoint summary:

| Endpoint | Method | Purpose |
|---|---|---|
| `/.well-known/oauth-authorization-server` | GET | Metadata discovery |
| `/.well-known/oauth-protected-resource` | GET | Protected resource metadata |
| `/oauth/register` | POST | Client registration — returns `client_id` |
| `/oauth/authorize` | GET | Firebase login page |
| `/oauth/authorize/complete` | POST | Issues authorization code |
| `/oauth/token` | POST | Code or refresh token exchange |

## Example

Using an API key to call the `get-project-state` MCP tool:

```bash
curl -X POST https://api.comstack.ai/mcp \
  -H "Content-Type: application/json" \
  -H "x-api-key: your-api-key" \
  -H "x-project-id: your-project-id" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "get-project-state",
      "arguments": { "project_id": "your-project-id" }
    }
  }'
```

## Common errors

**401 invalid_token** — access token expired or unknown. Use the refresh token via `POST /oauth/token` to obtain a new one.

**401 invalid_api_key** — API key not found or revoked. Regenerate it from project settings.

**403 Forbidden** — authenticated but with insufficient role for the requested operation.

**403 (scope mismatch)** — the `x-project-id` header does not match the `project_id` argument in the tool call.

**429 Too Many Requests** — OAuth endpoints are limited to 30 req/min/IP; authentication failures are limited to 10/min/IP.

## Related

- [MCP Server](/docs/mcp.md) — how AI agents connect and route tool calls
- [MCP OAuth](/docs/mcp/oauth.md) — OAuth storage model, token TTLs, refresh rotation
- [Permissions](/docs/concepts/permissions.md) — roles and what each can do
