Files
GearBox/docs/authentication.md
Jean-Luc Makiola e34a2cad11
Some checks failed
CI / ci (push) Failing after 11s
docs: add authentication, API reference, and MCP server guides
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 14:00:03 +02:00

282 lines
5.7 KiB
Markdown

# Authentication
GearBox uses a public-read, authenticated-write model. All GET endpoints are publicly accessible with no credentials required. Any request that modifies data (POST, PUT, PATCH, DELETE) requires authentication.
This is a single-user app. There is exactly one admin account.
## Table of Contents
- [First-Time Setup](#first-time-setup)
- [Web UI Authentication](#web-ui-authentication)
- [API Keys](#api-keys)
- [Auth Middleware Behavior](#auth-middleware-behavior)
- [Auth API Reference](#auth-api-reference)
- [Frontend Behavior](#frontend-behavior)
---
## First-Time Setup
When no users exist, all write endpoints return `403` with `{ "error": "setup_required" }`. To create the admin account, visit `/login` in the browser and complete the setup form, or call the setup endpoint directly:
```http
POST /api/auth/setup
Content-Type: application/json
{
"username": "admin",
"password": "yourpassword"
}
```
Requirements:
- `username`: any non-empty string
- `password`: minimum 6 characters
This endpoint only works when no users exist. Subsequent calls return `403 { "error": "Setup already completed" }`.
On success, a session cookie is set and `201` is returned:
```json
{ "username": "admin" }
```
---
## Web UI Authentication
Sessions use an `httpOnly` cookie named `gearbox_session`.
| Property | Value |
|------------|--------------------|
| Cookie name | `gearbox_session` |
| httpOnly | true |
| sameSite | Lax |
| path | / |
| Max age | 30 days |
The session expiry is **automatically refreshed** on each authenticated request. As long as the app is used at least once every 30 days, the session stays active.
Passwords are hashed with **argon2** via `Bun.password`.
### Changing Your Password
Requires an active session cookie.
```http
PUT /api/auth/password
Content-Type: application/json
{
"currentPassword": "oldpassword",
"newPassword": "newpassword"
}
```
---
## API Keys
API keys are intended for programmatic access (scripts, MCP clients, integrations). They are managed under **Settings > API Keys** in the web UI, or via the API endpoints listed below.
### Key behavior
- Keys are shown **once** at creation time. Store them securely.
- Keys are stored as an argon2 hash. Only the 8-character prefix is stored in plaintext for display and lookup purposes.
- Pass the key via the `X-API-Key` request header on any write request.
```http
POST /api/items
X-API-Key: gbk_a1b2c3d4...
Content-Type: application/json
{ "name": "Revelate Tangle", "categoryId": 2 }
```
If both a session cookie and an `X-API-Key` header are present, the API key is checked first.
---
## Auth Middleware Behavior
The middleware applied to `/api/*` (excluding `/api/auth/*`) follows these rules:
1. `GET` requests — always allowed, no auth check.
2. No users exist — returns `403 { "error": "setup_required" }`.
3. `X-API-Key` header present — verified against stored hashes; `401` on failure.
4. `gearbox_session` cookie present — verified against sessions table; refreshed on success; `401` on failure.
5. Neither credential present — returns `401 { "error": "Authentication required" }`.
The `/api/auth/*` routes handle their own auth logic and are excluded from the global middleware.
---
## Auth API Reference
### `GET /api/auth/me`
Returns the current session state. Always public.
**Response when logged in:**
```json
{
"user": { "id": 1 },
"setupRequired": false
}
```
**Response when logged out, setup complete:**
```json
{
"user": null,
"setupRequired": false
}
```
**Response when no users exist:**
```json
{
"user": null,
"setupRequired": true
}
```
---
### `POST /api/auth/setup`
Create the first admin account. Only works when no users exist.
**Request:**
```json
{
"username": "admin",
"password": "yourpassword"
}
```
**Response:** `201`
```json
{ "username": "admin" }
```
Sets `gearbox_session` cookie.
---
### `POST /api/auth/login`
Log in with username and password.
**Request:**
```json
{
"username": "admin",
"password": "yourpassword"
}
```
**Response:** `200`
```json
{ "username": "admin" }
```
Sets `gearbox_session` cookie. Returns `401` on invalid credentials.
---
### `POST /api/auth/logout`
Clear the current session. No request body needed.
**Response:**
```json
{ "ok": true }
```
Clears the `gearbox_session` cookie and deletes the session from the database.
---
### `PUT /api/auth/password`
Change the admin password. Requires an active session cookie (not API key).
**Request:**
```json
{
"currentPassword": "oldpassword",
"newPassword": "newpassword"
}
```
**Response:**
```json
{ "ok": true }
```
Returns `401` if `currentPassword` is incorrect.
---
### `GET /api/auth/keys`
List all API keys. Returns name, prefix, and creation timestamp — never the full key.
Requires auth.
**Response:**
```json
[
{
"id": 1,
"name": "Claude Code",
"prefix": "gbk_a1b2",
"createdAt": "2025-03-01T10:00:00.000Z"
}
]
```
---
### `POST /api/auth/keys`
Create a new API key. The full key is returned **once** and cannot be retrieved again.
Requires auth.
**Request:**
```json
{ "name": "Claude Code" }
```
**Response:** `201`
```json
{
"id": 1,
"name": "Claude Code",
"key": "gbk_a1b2c3d4e5f6g7h8i9j0...",
"prefix": "gbk_a1b2"
}
```
---
### `DELETE /api/auth/keys/:id`
Revoke an API key by ID. Requires auth.
**Response:**
```json
{ "ok": true }
```
---
## Frontend Behavior
- A login button is shown in the top-right corner of the UI (Gitea-style).
- The floating action button (FAB) for adding items is hidden when not logged in.
- Edit and delete actions on items, threads, and setups require auth. Unauthenticated users see read-only views.
- When `setupRequired` is true, the UI redirects to the setup flow.