> ## Documentation Index
> Fetch the complete documentation index at: https://docs.dev.gojinko.com/llms.txt
> Use this file to discover all available pages before exploring further.

# OAuth

> Browser-based auth for MCP clients (DCR) and the CLI (device flow).

Jinko supports two distinct OAuth flows. Both go through Jinko Auth at `auth.gojinko.com`.

| Flow                                                 | Used by                                          | Issuer                                      |
| ---------------------------------------------------- | ------------------------------------------------ | ------------------------------------------- |
| **MCP OAuth** with Dynamic Client Registration (DCR) | Claude Desktop, ChatGPT, Cursor, Codex, Openclaw | AuthKit (`auth.gojinko.com`)                |
| **CLI device flow**                                  | `@gojinko/cli` (`jinko auth login`)              | Jinko Auth user pool (Jinko Auth user pool) |

<Warning>
  These tokens are **not interchangeable.** A token from `jinko auth login` will fail with `unexpected iss claim` if you paste it into an MCP client's `Authorization: Bearer` header. Use an [API key](/authentication/api-keys) for programmatic MCP access.
</Warning>

## MCP OAuth (DCR)

Best path for end-user-facing MCP clients. Zero config, the client discovers Jinko's auth server, registers itself dynamically, and runs OAuth 2.1 + PKCE in the user's browser.

### Supported clients

* **Claude Desktop** / Claude Web, Settings → Connectors → Add custom connector. Just enter `https://mcp.builders.gojinko.com/mcp` and leave OAuth fields blank.
* **Claude Code**, `claude mcp add --transport http jinko https://mcp.builders.gojinko.com/mcp`
* **ChatGPT**, Add the connector in the desktop or web app's MCP settings.
* **Cursor**, Settings → MCP Servers → Add Server with the endpoint URL.

### What happens under the hood

<Steps>
  <Step title="Discovery">
    Client GETs `https://mcp.builders.gojinko.com/.well-known/oauth-authorization-server` to learn the auth server (`auth.gojinko.com`).
  </Step>

  <Step title="Dynamic Client Registration">
    Client POSTs to the registration endpoint to mint itself a client\_id + secret. No human in the loop.
  </Step>

  <Step title="Authorization with PKCE">
    Client opens a browser to `auth.gojinko.com`, user signs in or signs up. Jinko Auth redirects back with an auth code.
  </Step>

  <Step title="Token exchange">
    Client trades the code for an access token (and refresh token). Stored locally per the client's conventions.
  </Step>

  <Step title="Account auto-provision">
    On first use, our API pulls the JWT `sub` claim and provisions a Jinko devplatform user, no waitlist, no manual approval.
  </Step>
</Steps>

Tokens auto-refresh on the client side; you don't manage anything.

## CLI OAuth (device flow)

Used when you run `jinko auth login` and pick the OAuth path (default).

```bash theme={null}
jinko auth login
# → "Open this URL in any browser to sign in: https://auth.gojinko.com/device"
# → "Code: ABCD-1234"
```

Works over SSH and remote sessions (the URL + code are decoupled from the local browser). Tokens land in `~/.jinko/config.yaml`. The SDK and CLI both pick them up.

The CLI auto-refreshes tokens before each request when `expires_at` is near.

To clear: `jinko auth logout` (removes both OAuth tokens and any saved API key from the config).

## WorkOS OAuth on the REST API

Every `/v1` route on `api.gojinko.com` accepts a WorkOS OAuth access token as a bearer (the same token the CLI device flow mints) alongside `jnk_` API keys:

```bash theme={null}
curl https://api.gojinko.com/v1/flight_search \
  -H "Authorization: Bearer <oauth_token>" \
  -H "Content-Type: application/json" \
  -d '{ "origin": "JFK", "destination": "CDG", "trip_type": "oneway", "departure_date": "2026-06-15" }'
```

The REST gateway forwards the bearer to the BFF, which verifies it and resolves your user identity. So the two REST auth methods are **`jnk_` via `X-API-Key`** and **WorkOS OAuth via `Authorization: Bearer`**, both of which work on every `/v1` route. The SDK and CLI use a token from `jinko auth login` automatically once you're logged in.

<Note>
  This is distinct from the MCP endpoint. The "issuer mismatch" caveat above is specific to pasting a CLI token into an **MCP** client's `Authorization: Bearer` header. On the REST `/v1` surface the bearer is forwarded and verified by the BFF.
</Note>

## Which auth should I use?

| Scenario                                     | Recommended                                                |
| -------------------------------------------- | ---------------------------------------------------------- |
| Building an MCP server / agent for end users | **MCP OAuth** (DCR), zero config                           |
| Server-side script, CI, agent backend        | **API key**, long-lived, no refresh logic                  |
| Local dev with the CLI                       | **CLI OAuth** (device flow), your account, no separate key |
| Single-script automation on a workstation    | Either works; OAuth keeps you out of the keys dashboard    |

When in doubt, an API key is the most portable option.

## Common failures

| Symptom                                    | Cause                                                              | Fix                                                                         |
| ------------------------------------------ | ------------------------------------------------------------------ | --------------------------------------------------------------------------- |
| `401 unexpected iss claim` on MCP endpoint | You pasted a CLI OAuth token where a JWT-from-AuthKit was expected | Use an API key (`jnk_...`) on MCP, or use a client that supports DCR        |
| MCP client can't reach the auth server     | Network / proxy blocking `auth.gojinko.com`                        | Whitelist `auth.gojinko.com`, `mcp.builders.gojinko.com`, `api.gojinko.com` |
| CLI device flow times out                  | Code expired before user completed the browser step (\~10 min)     | Re-run `jinko auth login`                                                   |
| Token refresh fails after long idle        | Refresh token also expired                                         | `jinko auth login` again                                                    |

See [Errors & troubleshooting](/concepts/errors) for HTTP-level debugging.
