# OAuth for AI assistants

_Source: https://docs.neurotrading.io/en/api/oauth_

This page is for developers building an MCP client. To connect an assistant you already use, see [Trade from an AI assistant (MCP)](/api/mcp).

The Neurobot MCP server follows the [MCP authorization specification](https://modelcontextprotocol.io/specification/latest/basic/authorization): OAuth 2.1 with PKCE, dynamic client registration and resource indicators. A client that implements it connects without any Neurobot-specific code.

| Authorization server (issuer) | Protected resource |
| --- | --- |
| `https://api.neurotrading.io` | `https://api.neurotrading.io/mcp` |

## Discovery

A request to `/mcp` without a token answers `401` with a `WWW-Authenticate` header that points at the protected resource metadata:

```http
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer realm="neurobot", resource_metadata="https://api.neurotrading.io/.well-known/oauth-protected-resource/mcp"
```

| Document | URL |
| --- | --- |
| Protected resource metadata (RFC 9728) | `/.well-known/oauth-protected-resource/mcp` (also served at `/.well-known/oauth-protected-resource`) |
| Authorization server metadata (RFC 8414) | `/.well-known/oauth-authorization-server` |

The authorization server metadata lists the endpoints, all on the issuer's origin:

| Endpoint | Path |
| --- | --- |
| Authorization | `/authorize` |
| Token | `/token` |
| Dynamic client registration (RFC 7591) | `/register` |
| Revocation (RFC 7009) | `/revoke` |

## The flow

1. **Register** the client: `POST /register` with your `client_name` and `redirect_uris`. Public clients send `"token_endpoint_auth_method": "none"`; confidential clients get a `client_secret` and may send it in the body (`client_secret_post`) or as HTTP Basic (`client_secret_basic`). Redirect URIs must be `https`, `http` on `localhost` / `127.0.0.1` (any port), or your app's own scheme such as `cursor://…`. Show a real `client_name`: it's what the user sees.
2. **Authorize**: send the user's browser to `/authorize` with `response_type=code`, `client_id`, `redirect_uri`, `state`, a PKCE `code_challenge` with `code_challenge_method=S256`, and `resource=https://api.neurotrading.io/mcp`. Neurobot opens its consent screen on the web dashboard, where the user signs in, chooses Paper Trading only or live trading, and allows or denies.
3. **Callback**: the browser comes back to your `redirect_uri` with `code`, your `state` and `iss` (the issuer). A denial comes back with `error=access_denied`. The user has 10 minutes to answer; the code is good for 5 minutes and one exchange.
4. **Exchange** the code at `/token` (`grant_type=authorization_code`, `code`, `code_verifier`, `client_id`, `redirect_uri`, `resource`).
5. **Call** `/mcp` with `Authorization: Bearer <access_token>`.
6. **Refresh** at `/token` with `grant_type=refresh_token`. Every refresh returns a new refresh token and spends the old one, so store the new one.

```json
{
  "access_token": "nmcp_at_…",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "nmcp_rt_…",
  "scope": "trading:paper"
}
```

## Scopes

The user picks the access level on the consent screen; the token's `scope` says which one they chose.

| Scope | Meaning |
| --- | --- |
| `trading:paper` | Paper Trading only. Every wallet, balance and trade the connection sees is Paper Trading, whatever mode the account is in elsewhere, and it can't switch the account's mode. |
| `trading:live` | Acts in the account's current mode, real funds included. |

Request `trading:paper trading:live` (or no scope) to let the user choose. Request `trading:paper` alone and the consent screen offers Paper Trading only. A refresh can't widen the scope: to change it, the user connects again.

## Tokens

- Access tokens last 1 hour and are good for `/mcp` only. They aren't API session tokens, and the REST API refuses them.
- Refresh tokens last 30 days from their last use.
- A `401` with `error="invalid_token"` from `/mcp` means the token expired or the connection was ended: refresh, or send the user through the flow again.
- `POST /revoke` with either token ends the whole connection. The user can also end it from **Settings → AI connections** on the dashboard.

> **Info**
>
> The token endpoint, registration and revocation accept requests from any origin (CORS), so a browser-based client works too. `/mcp` never accepts the dashboard's session cookie, only the `Authorization` header.
