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

# Authentication

> OAuth 2.1, client registration, the four scopes, and the limit on what any token can do.

Docket runs an OAuth 2.1 resource server, with the authorization server on the same origin at
`/api/auth/*`.

## Discovery

Fetch these two and you need nothing else to start.

| Document                      | Path                                        | Standard |
| ----------------------------- | ------------------------------------------- | -------- |
| Protected Resource Metadata   | `/.well-known/oauth-protected-resource/mcp` | RFC 9728 |
| Authorization Server Metadata | `/.well-known/oauth-authorization-server`   | RFC 8414 |

The AS metadata lists the authorize, token, and registration endpoints, `S256` for
`code_challenge_method`, and URL-form client IDs.

## Registering a client

<Tabs>
  <Tab title="Dynamic registration">
    Classic Dynamic Client Registration, RFC 7591:

    ```http theme={"dark"}
    POST /api/auth/mcp/register
    ```

    Returns a `client_id`.
  </Tab>

  <Tab title="Client ID Metadata Document">
    Serve a metadata document at an HTTPS URL and use that URL as your `client_id`. Register
    nothing ahead of time.

    Docket fetches, DNS-checks, and validates it during the authorize preflight, then shows the
    validated `client_name` and `logo_uri` on the consent screen.
  </Tab>
</Tabs>

## The token exchange

<Steps>
  <Step title="Authorize">
    Send the browser to `/oauth/authorize` with `client_id`, `scope`, and `code_challenge`. Docket
    sends anyone unauthenticated to `/sign-in` first.
  </Step>

  <Step title="Exchange the code">
    PKCE, with `resource` set to the MCP resource URL per RFC 8707.
  </Step>

  <Step title="Call with the token">
    `Authorization: Bearer <token>` on every request.
  </Step>
</Steps>

## Token lifetimes

|               |            |
| ------------- | ---------- |
| Access token  | 15 minutes |
| Refresh token | 30 days    |

## Scopes

Four capability scopes, plus `offline_access`. The "Grants" column is the exact wording a user
sees on the consent screen when your client requests that scope.

| Scope             | Grants                                                                                          |
| ----------------- | ----------------------------------------------------------------------------------------------- |
| `work:read`       | View your tasks, projects, programs, initiatives, and cycles.                                   |
| `work:write`      | Create tasks, update and organize projects, post comments and status updates, and archive work. |
| `agents:run`      | Start and cancel agent work sessions, and approve or reject the actions an agent proposes.      |
| `connectors:link` | Connect other tools you use and link items from them to your work.                              |
| `offline_access`  | Keep working on your behalf without asking you to sign in again.                                |

Ask for the narrowest set that does the job. People decline a read-only integration that asks for
`work:write` and `agents:run`.

### Insufficient scope

Docket rejects a write operation from a `work:read` token with a `403` and:

```http theme={"dark"}
WWW-Authenticate: Bearer error="insufficient_scope"
```

Authorize again for the wider scope, then retry the call.

## The limit on every token

<Warning>**A token can never do more than the human who consented to it.**</Warning>

Docket checks the scope first, then that person's own grants. Someone with `view` on "Launch v2"
cannot write to it with a `work:write` token. People revoke in **Settings → Connected apps**,
which deletes the consent and its access tokens. Handle it: ask for authorization again.

## What is not available

No API keys. No long-lived static credentials. The web app's Better Auth session cookie
authenticates first-party requests only.
