# Authentication

> How MCP clients authenticate with OAuth 2.1 and PKCE: discovery, consent, the scope vocabulary, token lifetimes and what each error means.

> For the complete documentation index, see [llms.txt](https://helpdesk.orangescrum.com/llms.txt).

Source: https://helpdesk.orangescrum.com/guide/mcp/authentication

---
`/mcp/partner` authenticates with **OAuth 2.1 + PKCE**. Your client obtains its
own bearer token through a browser sign-in; there is no key to copy into a
config file.

> **This replaced X-API-KEY**
>
> Earlier releases authenticated MCP with the `X-API-KEY` header. The primary
> endpoint no longer accepts it. See [Legacy key path](#legacy-key-path) if you
> have an integration still on the old header.

## What you need before connecting

Two things, both handled once:

**MCP enabled for your workspace**

    An administrator has to switch MCP on for the company and choose which
    scopes it may ever grant. Until that happens every authorization attempt is
    refused, regardless of who signs in. Contact
    [support@orangescrum.com](mailto:support@orangescrum.com) or your account
    manager to have it enabled.

**An Orangescrum sign-in**

    You authorize as yourself, with email and password or Google sign-in. The
    assistant then acts with **your** permissions inside the workspace you
    picked. It cannot see projects you cannot see.

## The flow

Most clients run all of this for you after you paste the URL. It is worth
knowing what the steps are when one of them fails.

**Discovery**

    The client fetches the two well-known documents to learn where to send
    people and what scopes exist:

```
GET https://v4-api.orangescrum.com/.well-known/oauth-protected-resource
GET https://v4-api.orangescrum.com/.well-known/oauth-authorization-server
```

    The second advertises `authorization_endpoint`, `token_endpoint`,
    `registration_endpoint`, `scopes_supported`, and PKCE support (`S256`).

**Dynamic client registration**

    The client registers itself and receives a `client_id`: no client secret,
    because it is a public client protected by PKCE:

```
POST https://v4-api.orangescrum.com/oauth/register
```

    This is RFC 7591. You never do it by hand, and there is nothing to
    pre-provision on the Orangescrum side.

**Sign in and consent**

    The client opens `/oauth/authorize` in your browser. You sign in if you do
    not already have a session, then land on a consent screen that shows the
    connecting client, the scopes it is asking for, and the MCP-specific part:
    a **workspace picker** listing every workspace you belong to that has MCP
    enabled.

    Pick one and authorize. The grant is bound to that single workspace.

**Token exchange**

    The client exchanges its authorization code at `/oauth/token` with the PKCE
    verifier and receives an access token plus a refresh token.

**Calls**

    Every subsequent MCP request carries the token:

```
Authorization: Bearer <access-token>
```

### Token lifetimes

| Token | Lifetime | Notes |
| --- | --- | --- |
| Access token | 1 hour | Short on purpose, so revoking access takes effect quickly |
| Refresh token | 30 days | Rotated on every exchange; keeps you from re-consenting daily |

Clients refresh silently. You will only see the browser again if you go 30 days
without using the connection, or if access is revoked.

## Scopes

Two things have to agree before a scope is usable: your workspace must **allow**
it, and you must **approve** it on the consent screen. A client asking for more
than the workspace allows is clamped down to the allowed set rather than
refused.

`mcp:use` is the base gate. Every request needs it, and it is what a client
falls back to when it does not know the granular vocabulary.

| Scope | Grants |
| --- | --- |
| `mcp:use` | Connect at all, for the selected workspace. Required by every request |
| `mcp:projects.read` | Read projects and project metadata |
| `mcp:projects.write` | Create and update projects |
| `mcp:tasks.read` | Read tasks, task lists, statuses and types |
| `mcp:tasks.write` | Create, update, assign and close tasks |
| `mcp:epics.write` | Create epics, features, stories and subtasks |
| `mcp:sprints.read` | Read sprints and sprint plans |
| `mcp:sprints.write` | Create, update, start and complete sprints; assign tasks to them |
| `mcp:timelogs.read` | Read time entries and timesheets |
| `mcp:timelogs.write` | Create and update time entries |
| `mcp:users.read` | Read workspace members and user profiles |
| `mcp:tests.read` | Read test cases, scenarios, steps and defects |
| `mcp:tests.write` | Create, update, link and archive test cases, scenarios, steps and defects |
| `mcp:checklists.read` | Read checklists, checklist groups and templates |
| `mcp:checklists.write` | Create, update, complete and delete checklist items, groups and templates |
| `mcp:context.read` | Read saved project/company context ("memory") |
| `mcp:context.write` | Save project/company context ("memory") |
| `mcp:documents.read` | Search uploaded documents |

> **Reserved scopes in the discovery document**
>
> `scopes_supported` also advertises scopes with no tools behind them yet,
> `mcp:users.write`, `mcp:teams.*`, `mcp:wiki.*`, `mcp:tickets.*`,
> `mcp:reports.read` and others. They are registered ahead of the features that
> will use them. Granting one today grants nothing, and they are deliberately
> not offered in the workspace scope picker.

> **Users stay read-only**
>
> There is no tool to invite, deactivate or re-role a member. `mcp:users.write`
> exists in the vocabulary but nothing dispatches on it. Changing who has access
> to your workspace stays in the admin UI deliberately.

## Errors

Every failure carries a `WWW-Authenticate` header alongside a JSON-RPC error
body. Clients that follow the OAuth challenge restart the flow automatically on
`invalid_token`.

| Status | `error` | What happened | Fix |
| --- | --- | --- | --- |
| `401` | `invalid_request` | No bearer token was sent | Let the client run the OAuth flow; check it is not still sending `X-API-KEY` |
| `401` | `invalid_token` | Token expired, revoked or signature invalid | Reconnect, normally automatic on refresh |
| `401` | `invalid_token` | No consent recorded for this token | Re-authorize; the workspace selection never completed |
| `403` | `insufficient_scope` | Token lacks `mcp:use` | Re-authorize and approve the base scope |
| `403` | `invalid_token` | Audience mismatch | The token was issued for a different resource. Reconnect against this URL |
| `403` | `invalid_token` | Workspace entitlement disabled or revoked | Ask an administrator to re-enable MCP for the workspace |
| `403` | n/a | Tool called without its scope | Re-authorize with the scope named in the error |
| `429` | n/a | Rate limited | See [rate limits](#rate-limits) |

A per-tool scope failure names the scope it wanted, for example *"requires the
`mcp:sprints.write` scope"*. That is the signal to re-authorize with a wider
grant, or to ask an administrator to widen what the workspace allows, if the
scope is not on offer.

## Rate limits

**120 requests per minute** and **5,000 per day**, returned as JSON-RPC error
code `-32500` with HTTP `429`.

> **The MCP limit is counted per IP address**
>
> Unlike the [REST limits](https://helpdesk.orangescrum.com/guide/api/rate-limits), which are counted per API
> key, the MCP limiter keys on the calling IP, MCP clients do not always
> present a credential during the initialize handshake. Everyone connecting
> from the same office NAT or VPN egress shares one bucket, so a colleague's
> bulk run can rate-limit you.

## Protocol versions

The server negotiates these MCP spec revisions during `initialize`:

```
2025-11-25 · 2025-06-18 · 2025-03-26 · 2024-11-05
```

A client offering something newer will fail the handshake immediately after
OAuth succeeds, which looks like an auth problem but is not. If you see that
after a client update, say so when you report it.

## Legacy key path

A second endpoint still accepts the old header, for integrations mid-migration:

```
POST https://v4-api.orangescrum.com/mcp/partner-legacy
X-API-KEY: YOUR_KEY
```

It serves the identical tool set. Two things to know before you reach for it:

- It is **feature-flagged** and not guaranteed to stay available. OAuth is the
  supported path going forward.
- A partner key has no scope vocabulary and no consent screen, so the per-tool
  safety boundary described above does not apply to it in the same way.

> **Do not build new integrations against it**
>
> If you are connecting a client today, use `/mcp/partner` and OAuth. Treat
> `/mcp/partner-legacy` as a migration aid with a limited life.

## Where next

- [Client setup](https://helpdesk.orangescrum.com/guide/mcp/clients): Config snippets for every supported client.

- [Troubleshooting](https://helpdesk.orangescrum.com/guide/mcp/troubleshooting): Sign-in loops, 403s and tools that never appear.
