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

# Authentication

> Personal access tokens: creating them, scoping them, revoking them, and the limits and errors that apply.

Programmatic clients authenticate with a **personal access token**: a long-lived credential you
create once from your account and then hold in a script, a server, or a CI secret.

> [!WARNING]
>
> **`POST /api/auth/register` and `POST /api/auth/login` are browser-only flows and cannot be called
> from a script.** Both verify a reCAPTCHA v3 token, and reCAPTCHA v3 tokens are minted by Google's
> JavaScript inside a real browser, are bound to an action, and expire within minutes. No HTTP
> client can produce one. Registration also requires you to click an emailed verification link
> before your first login. Create your account in the browser, once, then use a token thereafter.
> The reasoning is recorded in [ADR-0006](/docs/adr/0006-programmatic-api-access.md).

## Creating a token

**1. Create a token**

Sign in at [haico.gr](https://haico.gr), open **Profile → API keys**, and choose **New key**.

Pick a **name** you will recognise later, an **access level**, and an **expiry**:

| Access | What it allows |
| - | - |
| `read` | Safe methods only (`GET`): listing conversations, reading the workspace. |
| `read,write` | Everything, including running agent turns and editing the workspace. |

The default expiry is 90 days. You can also choose 30 days, 1 year, or no expiry.

**2. Copy it immediately**

The token is displayed **once**. Only a SHA-256 hash of it is stored, so it genuinely cannot be
shown again. If you lose it, revoke the key and create another.

```
haico_pat_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
```

Store it the way you would any other secret: an environment variable, a secrets manager, or your
CI provider's encrypted variables. Never commit it. The fixed `haico_pat_` prefix exists so that
GitHub secret scanning and push protection can recognise a leaked key.

**3. Send it on every request**

```bash theme={null}
export HAICO_TOKEN="haico_pat_..."

curl -s https://haico.gr/api/auth/me \
  -H "Authorization: Bearer $HAICO_TOKEN"
```

```json theme={null}
{
  "id": 42,
  "username": "researcher",
  "email": "researcher@example.com",
  "role": "user",
  "email_verified": true
}
```

## Managing your tokens

The same operations are available over HTTP, but **only with a browser session token, never with a
personal access token**. If a token could mint tokens, a single leaked credential could issue
replacements, outlive its own revocation, and turn a read-only grant into a writable one.

| Method | Path | Purpose |
| - | - | - |
| `GET` | `/api/keys` | List your tokens (prefix, label, timestamps; never the secret) |
| `POST` | `/api/keys` | Create one; the plaintext is returned exactly once |
| `DELETE` | `/api/keys/{id}` | Revoke one, effective immediately |

Revocation is instant and independent: disabling one token has no effect on your other tokens or on
your browser session.

## Limits and error responses

| Status | Meaning | What to do |
| - | - | - |
| `401` | Missing, unknown, revoked, or expired token | Check the token; create a new one if it lapsed |
| `403` | A `read` token was used on a request that changes data | Create a `read,write` token |
| `429` | Over the per-token rate limit (120 requests per minute by default) | Back off; a `Retry-After` header is included |

Rate limiting is applied **per token**, not per IP address, so a CI host running several legitimate
tokens is not throttled as though it were one client.

> [!NOTE]
>
> The browser session JWT also authenticates every route, but it is an internal mechanism and not
> part of the public contract. It cannot be obtained without a browser, it expires every 24 hours,
> and it cannot be revoked individually. Do not build against it.

## Security notes

* **Treat a token like a password.** It carries your full account authority within its scope.
* **Prefer `read` when that is enough.** A read-only token cannot start an agent turn or modify the
  workspace, which bounds the damage if it leaks.
* **Set an expiry.** A forgotten token that never expires is a permanent liability.
* **Revoke rather than rotate secrets.** Revoking one token is instant and affects nothing else.
* **Never put a token in browser code.** Tokens are for confidential clients: servers, scripts, and
  CI. A browser cannot keep a secret, and anything in `localStorage` is reachable by any XSS.

> **[Check a token from CI](/docs/api-guide/recipes.md)**
>
> A ready-made shell snippet that fails your pipeline early on an expired token.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.