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

# Authentication

> Bearer credentials — Clerk session JWTs for browser clients, Archyon Personal Access Tokens for everything else.

Every non-public endpoint requires a Bearer credential in the `Authorization` header. Two credential types are accepted; the server distinguishes them by token shape, so no scheme selection is required by the caller.

```http theme={null}
Authorization: Bearer <credential>
```

| Credential                                 | Audience                                                                                  | Lifetime                        |
| ------------------------------------------ | ----------------------------------------------------------------------------------------- | ------------------------------- |
| Clerk session JWT                          | Browser clients using the official Clerk SDK                                              | Short (≤1 hour, auto-refreshed) |
| Archyon Personal Access Token (`an_pat_…`) | Scripts, CI jobs, and any other non-browser client                                        | Until explicitly revoked        |
| MCP access token (`an_mcp_…`)              | Hosted MCP Connector — issued by the OAuth flow described under [Connectors](/connectors) | \~1 hour, auto-refreshed        |

The two endpoints exempt from authentication are `POST /api/waitlist` (public marketing form) and `GET /api/auth/notion/callback` (OAuth redirect, validated by state nonce).

## Personal access tokens

Personal access tokens (PATs) are the right credential for scripts, CI jobs, and direct API access from outside a browser. For connecting Claude as an assistant, prefer the hosted [Connector flow](/connectors), which manages tokens automatically.

### Format

```
an_pat_<random>
```

The `an_pat_` prefix identifies the token type. The remainder is opaque to the client and must not be parsed. Server-side, only a SHA-256 hash of the token is stored — the plaintext value is unrecoverable after the response that mints it.

### Creating a token

1. Sign in at [archyon.app](https://archyon.app).
2. Use the organization switcher in the application header to activate the organization the token should act in.
3. Navigate to **Account → Tokens**.
4. Click **New token** and provide a descriptive name.
5. Copy the returned `an_pat_…` value immediately. It is displayed once.

Alternatively, mint a token programmatically from a session that already has a Clerk JWT:

```bash theme={null}
curl -X POST https://archyon.app/api/me/tokens \
  -H "Authorization: Bearer <clerk_jwt>" \
  -H "Content-Type: application/json" \
  -d '{"name": "ci-deploy-pipeline"}'
```

```json theme={null}
{
  "token": "an_pat_…",
  "prefix": "an_pat_abc12",
  "name": "ci-deploy-pipeline",
  "orgId": "org_2abc...",
  "hint": "Active in the ACME organization."
}
```

### Organization binding

A PAT is bound to whichever organization is active in the minting session, and the binding is permanent. Switching organizations in the application has no effect on existing tokens. To act in a different organization from a non-browser client, mint a new token while that organization is active.

Tokens minted before the binding was introduced have a `null` `orgId` and can only call endpoints that operate at instance scope. These legacy tokens should be revoked and replaced.

The application surfaces the bound organization in the token list and marks the currently-active organization in green.

### Using a token

<CodeGroup>
  ```bash curl theme={null}
  curl https://archyon.app/api/me \
    -H "Authorization: Bearer $ARCHYON_TOKEN"
  ```

  ```javascript Node.js theme={null}
  const res = await fetch("https://archyon.app/api/me", {
    headers: {
      Authorization: `Bearer ${process.env.ARCHYON_TOKEN}`,
    },
  });
  const me = await res.json();
  ```

  ```python Python theme={null}
  import os, requests

  res = requests.get(
      "https://archyon.app/api/me",
      headers={"Authorization": f"Bearer {os.environ['ARCHYON_TOKEN']}"},
  )
  me = res.json()
  ```
</CodeGroup>

The response confirms which organization the credential is acting in:

```json theme={null}
{
  "id": 42,
  "displayName": "Ada Lovelace",
  "isAdmin": false,
  "provider": "clerk",
  "createdAt": 1716566400000,
  "session": {
    "orgId": "org_2abc...",
    "orgRole": "org:admin",
    "orgSlug": "acme",
    "isApiToken": true
  }
}
```

### Listing tokens

```bash theme={null}
curl https://archyon.app/api/me/tokens \
  -H "Authorization: Bearer $ARCHYON_TOKEN"
```

The response includes the prefix, the bound organization, and the last-used timestamp for each token. Plaintext values are never returned.

### Revoking a token

Revocation is immediate. Subsequent requests with the revoked token receive `401 Unauthorized`.

```bash theme={null}
curl -X DELETE https://archyon.app/api/me/tokens/<id> \
  -H "Authorization: Bearer $ARCHYON_TOKEN"
```

The token list in the application provides an equivalent **Revoke** action.

### Security considerations

* Treat PATs as passwords. Store them in a secret manager and never commit them to source control.
* Issue separate tokens per client (one per CI pipeline, one per laptop, one per MCP installation). The cost of revoking a single compromised credential then equals the cost of re-minting one token.
* Tokens are not scoped by permission today; a PAT inherits the full role of the user who minted it within the bound organization. Apply the principle of least privilege at the user level — mint tokens from accounts whose role matches the intended use.

## Clerk session JWTs

Browser applications authenticate with short-lived JWTs minted by the [Clerk](https://clerk.com) SDK and attached to every request.

```typescript theme={null}
import { useAuth } from "@clerk/clerk-react";

function useArchyonFetch() {
  const { getToken } = useAuth();
  return async (path: string, init?: RequestInit) => {
    const jwt = await getToken();
    return fetch(`https://archyon.app${path}`, {
      ...init,
      headers: {
        ...(init?.headers ?? {}),
        Authorization: `Bearer ${jwt}`,
      },
    });
  };
}
```

For organization-scoped endpoints, the Clerk session template must include the `org_id`, `org_role`, and `org_slug` claims so that the API can derive organization context from the JWT. The hosted Archyon instance at `archyon.app` is configured correctly out of the box. Self-hosted deployments must configure the session template manually; see [`DEPLOYMENT.md`](https://github.com/Alex-Johnson-1/archyon/blob/main/DEPLOYMENT.md) in the repository.

## No active organization

Resources scoped to an organization — workspaces, people, teams, stakeholder roles, the Notion integration — return `400 Bad Request` with `code: "no_active_org"` when the caller's session has no organization context:

```json theme={null}
{
  "error": "Active organization required to create or modify org-scoped entities.",
  "code": "no_active_org"
}
```

Resolution depends on the credential type:

* **Browser clients** should prompt the user to select an organization in the Clerk organization switcher.
* **Personal access tokens** must be re-minted while the desired organization is active in the application.

Instance superadministrators bypass this check on read endpoints to support cross-organization investigations, but write endpoints still require an explicit organization context.
