# `unauthorized`: No usable credential

> HTTP 401. The request carried no credential the API accepts: none at all, a malformed one, or one that is unknown, revoked or expired.

Every operation except `GET /status` needs a credential in the `Authorization` header, as `Authorization: Bearer <credential>`. The credential is either an API key (it starts `cmn_sk_`) or an OAuth access token (it starts `cmn_at_`). This error means the API could not turn what you sent into a working credential.

**Every reason answers identically, down to the wording.** A key that was revoked, one that expired and one that never existed produce the same response, so that a leaked string cannot be tested for whether it was once real. The response cannot tell you which case you are in; the causes below tell you how to find out.

The response carries a `WWW-Authenticate` header whose `resource_metadata` parameter points at the API's OAuth protected resource metadata. An MCP client or any OAuth client uses it to discover where to authorise. A client holding an API key can ignore it.

## Why it happens, and how to fix it

### 1. No Authorization header, or the wrong scheme

The header is missing, or the credential was sent some other way: as `Token <key>`, `Basic ...`, `X-Api-Key`, a query parameter, or a bare key with no `Bearer ` in front. There is no fallback to any of these. A request made from a browser page with a Commune session cookie is not authenticated either; the API ignores cookies.

**Fix:** Send exactly `Authorization: Bearer cmn_sk_...` (or `cmn_at_...` for an OAuth token). Check that a proxy or HTTP library is not stripping the `Authorization` header, which some do on redirects.

### 2. A malformed or truncated credential

A credential is its prefix followed by 32 letters and digits. It fails when it was cut short on copy, carries surrounding quotes or a line break from an environment file, or was taken from the key's display prefix on the keys page (which is not the secret).

**Fix:** Print the length of what you send: an API key is 39 characters. The full secret is shown once, when the key is minted. If you no longer have it, mint a new key on [Settings, API keys](https://usecommune.com/settings/api-keys) and store the secret as shown.

### 3. The API key was revoked or has expired

Keys are turned off by their owner on the keys page, by a newsletter owner or admin cutting a key off from their newsletter's API access page, or by a `DELETE /api-keys/{key}` call (which an integration may make on itself). A key also stops working at the expiry date chosen when it was minted.

**Fix:** Open [Settings, API keys](https://usecommune.com/settings/api-keys) as the key's owner and check its state. A revoked or expired key cannot be brought back: mint a new one, and choose an expiry you will notice.

### 4. The OAuth access token has expired

An access token lives one hour. After that every request with it answers `401`, while the refresh token issued with it keeps working for 90 days.

**Fix:** Exchange the refresh token at the authorisation server's token endpoint (`grant_type=refresh_token`) for a new access token, then retry. Refresh proactively using `expires_in` rather than waiting for the `401`. The flow is in [Build an app every creator can connect](https://usecommune.dev/use-cases/build-an-integration).

### 5. The OAuth grant was revoked, or the token was issued for another resource

When the creator disconnects your app, every token under that grant stops working on the next request, refresh tokens included. A token also fails when the authorisation that produced it named a different `resource` than this API, or the client registration was disabled.

**Fix:** If refreshing also fails, send the creator through authorisation again, with `resource` set to the API's origin, `https://api.usecommune.com`. An MCP client does this by itself when it follows `resource_metadata`; see [Connect an assistant](https://usecommune.dev/guides/mcp).

## Retrying

No: the same credential fails the same way, so fix the header, refresh the token or use a new key first.

## Headers

- `WWW-Authenticate`: Bearer realm="Commune API", resource_metadata="https://api.usecommune.com/.well-known/oauth-protected-resource". The metadata URL is where an OAuth or MCP client starts discovery.

## Example response

```json
{
  "error": {
    "code": "unauthorized",
    "message": "No usable credential. Send an API key or an OAuth access token as `Authorization: Bearer <credential>`. A credential that has been revoked or has expired reports the same way as one that was never issued.",
    "request_id": "req_01j9c8h1q7m3n4p5r6s7t8u9v0",
    "docs_url": "https://usecommune.dev/errors/unauthorized"
  }
}
```

Often confused with: [`forbidden`](https://usecommune.dev/errors/forbidden.md), [`insufficient_scope`](https://usecommune.dev/errors/insufficient_scope.md).
