# Authentication

Every API call carries a credential. An integration uses an **API key**. An
AI assistant that connects to the MCP server uses **OAuth**, and the MCP
server calls the API with that token for it.

## API keys

An API key belongs to one organization. It reaches the companies of that
organization, and nothing else.

```http
GET /api/organizations/ HTTP/1.1
Authorization: Bearer osk_live_...
```

- **Create a key** in the Oscar app, in the settings of your organization,
  under API keys. You need the permission `api_keys.manage` (an `owner` has
  it). Give the key a name, its scopes, and an optional expiry date.
- **The full key is shown once**, when you create it. Oscar stores only a
  hash of it. Keep it in a secret store, never in your code or in a log.
- A key starts with `osk_`, for example `osk_live_...`, so a secret scanner
  can find it.
- **A key acts for the person who created it.** It has the permissions of
  that person's role in the organization, narrowed by the scopes of the key
  and by what Oscar allows the clients of each company. When that person
  leaves the organization or is deactivated, the key is revoked.
- An owner sees every key of the organization in the settings, and can revoke
  one at any time. An unknown, revoked or expired key gets 401
  `authentication_failed`.

### Scopes

| Scope   | Allows                                                                                         |
| ------- | ---------------------------------------------------------------------------------------------- |
| `read`  | Every read: the organization, the books, the documents                                         |
| `write` | Every change that the role allows: record and issue invoices, create parties, upload documents |

A key needs `read` to read and `write` to change something. No key can
manage the organization, its members or its API keys: only a person signed in
to the app can do that.

A call that the role allows but the scopes of the key do not gets 403
`insufficient_scope`. A call that the role does not allow gets 403
`permission_denied`.

### Which permissions does my key have?

`GET /api/companies/{company_id}/` returns `permissions`: the effective
permissions of the caller in that company. Each operation of the
[API reference](/docs/api) names the permission it needs.

## OAuth

Oscar is an OAuth 2.1 authorization server for the MCP server. An MCP
client such as Claude or ChatGPT signs the user in, the user approves the
connection on a consent page and chooses one organization, and the client
gets an access token for that organization.

- The authorization code flow with PKCE `S256`, and nothing else.
- The metadata is at `/.well-known/oauth-authorization-server`. The
  authorization endpoint is `/oauth/authorize` and the token endpoint is
  `/oauth/token`.
- Each request names the MCP server as its `resource` (RFC 8707).
- The scopes are the same as for an API key: `read` and `write`. A request
  that names no `scope` gets `read` only; ask for `read write` to write.
- An access token lives for one hour. Refresh tokens rotate.
- The user sees every connection under "Connected apps" in the account
  settings, and can revoke one there.

An integration that is not an MCP client uses an API key. The details of the
flow are in [Connect an AI assistant](/docs/mcp).

## Requests without a session

A request with an API key or an OAuth token sends no cookie, so it needs no
CSRF token. Send JSON with `Content-Type: application/json`, and a file upload
as `multipart/form-data`.

Every response carries an `X-Request-Id` header. Give it to us when you report
a problem. You can also send your own `X-Request-Id`, and the API keeps it
when it is well formed.
