# Authentication
> Complete end-to-end guide to MCP OAuth authentication, credential separation, provider flows, and token lifecycle across Claude Code, OpenCode, and OMP.
Source: https://ivar.run/docs/guide/mcp/oauth

import { Callout } from 'fumadocs-ui/components/callout';
import { Step, Steps } from 'fumadocs-ui/components/steps';

Model Context Protocol (MCP) servers using remote HTTP transports frequently require OAuth 2.0 authentication to securely access user resources. In Ivar, MCP authentication balances central management with provider-native security models: authentication is coordinated across providers while preserving strict isolation between public metadata, client secrets, and runtime tokens.

## The end-to-end OAuth lifecycle

OAuth authentication in Ivar proceeds through a clear multi-stage lifecycle separating discovery, registration, browser authorization, storage, and runtime materialisation.

<Steps>
<Step>
### Discover endpoints
Inspect the canonical server HTTP endpoint in `ivar.json` and query RFC 8414 / OAuth 2.0 metadata to discover authorization, token (`token_url`), and dynamic registration endpoints.
</Step>
<Step>
### Resolve or reuse client registration
Determine client credentials by either performing Dynamic Client Registration (DCR) for supported public clients (e.g. Linear) or reusing pre-registered client IDs and configured secrets for allowlisted services (e.g. Figma).
</Step>
<Step>
### Browser authorization with PKCE
Launch the local loopback callback server and open a browser to the authorization endpoint using Authorization Code Flow with PKCE (`S256` code challenge).
</Step>
<Step>
### Token exchange and data placement
Exchange the authorization code and PKCE verifier at the token endpoint, then partition credentials across public manifest metadata (`ivar.json`), secrets (`.ivar/secrets/mcp.env`), and provider/broker token stores.
</Step>
<Step>
### Configuration materialisation and runtime refresh
Materialise provider configuration files (`.mcp.json`, `opencode.json`, `mcp.json`) with qualified server names, enabling native token managers or OMP auth brokers to maintain and refresh active tokens.
</Step>
</Steps>

### 1. Endpoint discovery

For Ivar-managed flows (OMP for both services, OpenCode for Figma), running `ivar mcp auth <name>` inspects the server's canonical HTTP endpoint defined in `ivar.json` (such as `https://mcp.linear.app/mcp` or `https://mcp.figma.com/mcp`). Ivar sends discovery requests (RFC 8414 / OAuth 2.0 Protected Resource Metadata) to identify authorization endpoints, token exchange endpoints (`token_url`), supported code challenge methods (`S256`), and dynamic client registration (DCR) endpoints. Provider-native flows (Claude Code and OpenCode with Linear) manage discovery independently and remain opaque to Ivar.

### 2. Client registration (optional)

Depending on the service and provider:
- **Dynamic Client Registration (DCR):** Services supporting open public DCR (such as Linear) allow Ivar or native providers to register a client ID on the fly.
- **Pre-registered OAuth Apps:** Services enforcing strict redirect URL allowlists (such as Figma) reject dynamic public client registration. Ivar preregisters or provisions app credentials with predetermined client IDs and redirect URIs.

### 3. Browser authorization and PKCE

All interactive authentication managed by Ivar uses the OAuth 2.0 Authorization Code Flow with **PKCE (Proof Key for Code Exchange, RFC 7636)** using the `S256` code challenge method:
1. A cryptographically random code verifier and code challenge are generated.
2. A browser window opens directing the user to the service's authorization endpoint with requested scopes.
3. The user approves access, and the service redirects back to a local loopback callback server (e.g. `http://localhost:<port>/callback`).

### 4. Token exchange

The authorization code received at the callback server is exchanged with the service's `token_url` alongside the PKCE code verifier (and client secret if confidential client credentials are required). The authorization server returns access and refresh tokens.

### 5. Multi-store data placement

Credentials and configuration parameters are partitioned across three distinct storage tiers:
- **Public configuration (`ivar.json`):** Non-sensitive client and endpoint metadata.
- **Secret environment (`.ivar/secrets/mcp.env`):** Sensitive client secrets (if any).
- **Runtime token stores:** Short-lived access tokens and refresh tokens stored exclusively in provider-managed credential stores or OMP auth brokers.

### 6. Configuration materialisation

Running `ivar sync` or completing an authentication command materialises the provider-specific configurations (`.mcp.json`, `opencode.json`, or hall-root `mcp.json`) using hall-qualified server names (`<hall>-<name>`).

### 7. Runtime execution and token refresh

When an agent session runs, the provider uses stored tokens to sign MCP requests. Token refresh behavior depends on the flow owner:
- **OMP:** OMP's auth broker relies on the persisted `token_url` and bound credentials to renew expiring tokens.
- **Claude Code & OpenCode:** Native token managers maintain and refresh tokens using their internal provider mechanisms.

## Provider × Service ownership matrix

Different providers and services handle registration and authentication with distinct levels of native support.

| Service | Provider | Registration | Auth flow owner | Token storage |
| --- | --- | --- | --- | --- |
| **Linear** | `claude-code` | Public DCR | Native (`claude mcp login`) | Claude Code internal store |
| **Linear** | `opencode` | Public DCR | Native (`opencode mcp auth`) | OpenCode internal store (`mcp-auth.json`) |
| **Linear** | `omp` | Ivar generic registration | Ivar internal PKCE | `omp auth-broker` profile binding |
| **Figma** | `claude-code` | Provider-owned / Preconfigured | Native (`claude mcp login`) | Claude Code internal store |
| **Figma** | `opencode` | Ivar preregistration | Ivar internal PKCE | OpenCode internal store (`mcp-auth.json`) |
| **Figma** | `omp` | Ivar preregistration | Ivar internal PKCE | `omp auth-broker` profile binding |

## Service architectural differences

### Why Figma differs from Linear

- **Linear (`https://mcp.linear.app/mcp`):** Linear supports standard public-client Dynamic Client Registration (RFC 7591). Claude Code and OpenCode can register ephemeral client IDs and execute their built-in native login flows directly without prior setup.
- **Figma (`https://mcp.figma.com/mcp`):** Figma enforces server-controlled redirect URI allowlists and strict OAuth application registration. OpenCode's dynamic registration attempts are rejected by Figma. Consequently, Ivar handles Figma authentication via internal preregistered OAuth metadata and executes an internal PKCE flow for OpenCode before injecting the resulting token into OpenCode's credential storage (`mcp-auth.json`). Claude Code maintains its own first-party integration and manages Figma natively.

### Why OMP always uses Ivar's flow

Unlike Claude Code and OpenCode, **Oh My Pi (OMP)** has no native interactive MCP login command or built-in OAuth browser orchestrator. OMP expects pre-configured MCP endpoints in its hall-root `mcp.json` accompanied by credentials bound through `omp auth-broker`.

For every service on OMP (both Linear and Figma):
1. Ivar manages discovery and OAuth client registration.
2. Ivar executes the local PKCE browser flow.
3. Ivar binds the resulting tokens to the OMP profile and endpoint via `omp auth-broker`.
4. In `mcp.json`, Ivar generates the auth configuration with type `oauth`, ensuring `token_url` is persisted for runtime token maintenance.

## Data-placement table

To guarantee security and avoid credential leakage, Ivar strictly partitions MCP configuration and secrets:

| Artifact | Location | Contains | Committed to Git? |
| --- | --- | --- | --- |
| **Manifest metadata** | `ivar.json` (`oauth` block) | `client_id`, `client_secret_env`, `token_url`, `resource` | Yes |
| **Client secrets** | `.ivar/secrets/mcp.env` | Client secret values referenced by `client_secret_env` | No (`.gitignore`) |
| **Claude tokens** | Claude config directory / Keychain | Access and refresh tokens for `claude-code` | No |
| **OpenCode tokens** | OpenCode auth storage (`mcp-auth.json`) | Access and refresh tokens for `opencode` | No |
| **OMP tokens** | OMP auth broker store | Bound credentials per profile and endpoint | No |

### Supported OAuth metadata fields

The `oauth` block under an HTTP server entry in `ivar.json` supports only canonical fields. In this example, the Figma server entry uses a confidential client secret environment variable:

```json title="ivar.json (OAuth metadata snippet)"
{
  "name": "figma",
  "type": "http",
  "url": "https://mcp.figma.com/mcp",
  "oauth": {
    "client_id": "<generated_client_id>",
    "client_secret_env": "IVAR_MCP_ACME_FIGMA_SECRET",
    "token_url": "<discovered_token_endpoint>",
    "resource": "https://mcp.figma.com/mcp"
  }
}
```

<Callout type="warn" title="No unsupported fields or plain secrets">
  - **`auth_url` is rejected:** Authorization URLs are dynamically discovered from the server endpoint. Do not configure `auth_url` in `ivar.json`.
  - **No secrets in `ivar.json`:** Use `client_secret_env` to name the environment variable containing the secret. Store the raw secret in `.ivar/secrets/mcp.env`.
</Callout>

## Running authentication

Authenticate individual providers or all configured providers using the `ivar mcp auth` CLI command.

### Authenticate a specific provider

```bash
# Authenticate Linear for Claude Code
ivar mcp auth linear --provider claude-code

# Authenticate Figma for OpenCode (uses Ivar PKCE + OpenCode store injection)
ivar mcp auth figma --provider opencode

# Authenticate Linear for OMP (uses Ivar PKCE + omp auth-broker binding)
ivar mcp auth linear --provider omp
```

### Batch authentication (`--all-providers`)

```bash
# Run authentication across all configured providers in the hall
ivar mcp auth figma --all-providers
ivar mcp auth linear --all-providers
```

Running `ivar mcp auth <server> --all-providers` orchestrates authentication across every provider in `providers.available`:
1. **Provider ordering:** Runs `claude-code` first (via native `claude mcp login`), followed by remaining providers sequentially.
2. **Skip authenticated:** Any provider already in the `authenticated` state is skipped automatically.
3. **Automatic browser opening:** For Ivar-driven OAuth legs, Ivar opens the authorization URL directly in the default browser (`xdg-open` / `open` / `start`) and prints the URL to terminal output (as an OSC 8 clickable link when stderr is a TTY).
4. **Post-run grant verification:** When two or more legs were not skipped, Ivar performs a post-run dropped-grant check (live for Claude Code and OpenCode, `omp token` for OMP) to verify earlier grants were not revoked by subsequent authorizations. If an earlier grant is dropped, an `mcp.grant_dropped` warning is emitted.
## Token refresh and reauthentication

Token maintenance is governed by the owner of the authentication flow:
- **OMP:** The OMP auth broker uses the persisted `token_url` and refresh token stored in its profile binding to renew expired access tokens.
- **Provider-native tools:** Claude Code and OpenCode refresh tokens through their own internal token storage and upstream exchange endpoints.
- **Reauthentication:** If a refresh token expires or is revoked upstream, run `ivar mcp auth <name> --provider <provider>` (or the provider's native auth command) to trigger a new browser PKCE authorization cycle.
- **Provider Sync:** After updating authentication or adding new endpoints, execute `ivar sync` to re-materialise configuration files across all provider harnesses.

## Troubleshooting

### Browser authorization fails or times out

- **Port Conflicts:** Ensure the local loopback port for the OAuth callback is not blocked by a local firewall or another running process.
- **Browser Not Opening:** In headless or remote development environments, copy the printed authorization URL from the terminal into your local browser, complete the consent prompt, and ensure redirect traffic reaches the callback listener.

### Figma authentication error in OpenCode

- **Symptom:** OpenCode native auth fails with an unauthorized client or redirect URI mismatch.
- **Resolution:** Do not use `opencode mcp auth acme-figma`. Run `ivar mcp auth figma --provider opencode`. Ivar will use its preregistered application metadata and store the issued token directly in OpenCode's credential repository (`mcp-auth.json`).

### Missing token URL on OMP

- **Symptom:** OMP session fails to refresh tokens or reports missing OAuth token endpoint.
- **Resolution:** Verify that `token_url` is populated in the `oauth` section of `ivar.json` or discovered during authentication. Run `ivar mcp auth <name> --provider omp` and `ivar sync`. If the upstream service updated its OAuth endpoints or registration policy, re-run `ivar mcp auth` to diagnose and obtain updated endpoints.

## Related documentation

- [MCP Overview Reference](/docs/reference/mcp) — Complete manifest schema, supported transports, and provider translation.
- [MCP Providers Guide](/docs/guide/mcp/providers) — Provider-specific details for Claude Code, OpenCode, and OMP.
- [Figma Integration](/docs/guide/mcp/integrations/figma) — Setting up and authenticating the Figma MCP server.
- [Linear Integration](/docs/guide/mcp/integrations/linear) — Setting up and authenticating the Linear MCP server.
- [Ivar CLI Reference](/docs/reference/cli) — CLI commands for `ivar mcp auth` and `ivar sync`.
