feat: Add Auth Service with JWT authentication

This commit is contained in:
Apple
2025-11-26 11:47:00 -08:00
parent 2c4eb7d432
commit 5aaf6cbf21
23 changed files with 3522 additions and 26 deletions

349
docs/security/AUTH_SPEC.md Normal file
View File

@@ -0,0 +1,349 @@
# AUTH SPEC — DAARION.city
Version: 1.0.0
---
## 0. PURPOSE
Цей документ описує базову систему автентифікації та авторизації для DAARION.city:
- єдину модель користувача (`user_id`) для:
- фронтенду (web/PWA),
- Matrix/chat інтеграції,
- MicroDAO governance,
- Agents Service,
- SecondMe.
- механізм логіну/логауту (JWT access + refresh tokens),
- базову RBAC (roles/permissions),
- інтеграцію з існуючими сервісами (agents, microdao, city, secondme).
Фокус цієї версії — **MVP-рівень**:
- Password-based login (email + password) + готовність до OAuth (Google/Telegram) як наступний крок.
- JWT токени (access + refresh).
- Мінімальний набір ролей (`user`, `admin`, `agent-system`).
- Захист основних API (governance, agents, secondme private).
---
## 1. ARCHITECTURE OVERVIEW
### 1.1. Auth Service
Окремий сервіс `auth-service` (порт: **7020**):
```text
[ Web / PWA / Matrix Gateway ]
[ Auth Service (7020) ]
[ PostgreSQL (auth tables) + Redis (sessions cache) ]
[ JWT токени для інших сервісів ]
```
Auth Service:
* реєструє користувачів,
* зберігає хеші паролів,
* видає JWT access/refresh токени,
* перевіряє токени (через shared secret / public key),
* надає API для інших сервісів (`/auth/introspect`).
### 1.2. Інші сервіси
* `Agents Service`, `MicroDAO Service`, `SecondMe`, `City Service`:
* отримують JWT у `Authorization: Bearer <token>`,
* валідують його (прямо або через Auth Service),
* витягують `user_id`, `roles`, `scopes`.
---
## 2. DATA MODEL (PostgreSQL)
### 2.1. auth_users
```sql
CREATE TABLE auth_users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
email TEXT UNIQUE NOT NULL,
password_hash TEXT NOT NULL,
display_name TEXT,
avatar_url TEXT,
is_active BOOLEAN NOT NULL DEFAULT TRUE,
is_admin BOOLEAN NOT NULL DEFAULT FALSE,
locale TEXT DEFAULT 'uk',
timezone TEXT DEFAULT 'Europe/Kyiv',
meta JSONB DEFAULT '{}'::jsonb,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE INDEX ix_auth_users_email ON auth_users(email);
```
### 2.2. auth_roles
```sql
CREATE TABLE auth_roles (
id TEXT PRIMARY KEY, -- 'user' | 'admin' | 'agent-system'
description TEXT
);
INSERT INTO auth_roles (id, description) VALUES
('user', 'Regular user'),
('admin', 'Administrator'),
('agent-system', 'System agent');
```
### 2.3. auth_user_roles
```sql
CREATE TABLE auth_user_roles (
user_id UUID NOT NULL REFERENCES auth_users(id) ON DELETE CASCADE,
role_id TEXT NOT NULL REFERENCES auth_roles(id) ON DELETE CASCADE,
PRIMARY KEY (user_id, role_id)
);
```
### 2.4. auth_sessions
```sql
CREATE TABLE auth_sessions (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL REFERENCES auth_users(id) ON DELETE CASCADE,
user_agent TEXT,
ip_address INET,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
expires_at TIMESTAMPTZ NOT NULL,
revoked_at TIMESTAMPTZ,
meta JSONB DEFAULT '{}'::jsonb
);
CREATE INDEX ix_auth_sessions_user_id ON auth_sessions(user_id);
CREATE INDEX ix_auth_sessions_expires ON auth_sessions(expires_at);
```
---
## 3. TOKEN MODEL (JWT)
### 3.1. Access token
* Формат: JWT (HS256).
* Термін дії: 30 хвилин.
* Payload:
```json
{
"sub": "user_id-uuid",
"email": "user@example.com",
"name": "Display Name",
"roles": ["user"],
"iat": 1732590000,
"exp": 1732591800,
"iss": "daarion-auth",
"type": "access"
}
```
### 3.2. Refresh token
* Формат: JWT (HS256).
* Термін дії: 7 днів.
* Payload:
```json
{
"sub": "user_id-uuid",
"session_id": "session-uuid",
"iat": 1732590000,
"exp": 1733194800,
"iss": "daarion-auth",
"type": "refresh"
}
```
---
## 4. HTTP API (PUBLIC)
Базовий шлях: `/api/auth/...`.
### 4.1. `POST /api/auth/register`
**Request:**
```json
{
"email": "user@example.com",
"password": "StrongPassword123",
"display_name": "Alex"
}
```
**Response (201):**
```json
{
"user_id": "uuid",
"email": "user@example.com",
"display_name": "Alex",
"roles": ["user"]
}
```
### 4.2. `POST /api/auth/login`
**Request:**
```json
{
"email": "user@example.com",
"password": "StrongPassword123"
}
```
**Response (200):**
```json
{
"access_token": "<JWT_ACCESS>",
"refresh_token": "<JWT_REFRESH>",
"token_type": "Bearer",
"expires_in": 1800,
"user": {
"id": "uuid",
"email": "user@example.com",
"display_name": "Alex",
"roles": ["user"]
}
}
```
### 4.3. `POST /api/auth/refresh`
**Request:**
```json
{
"refresh_token": "<JWT_REFRESH>"
}
```
**Response (200):**
```json
{
"access_token": "<NEW_JWT_ACCESS>",
"refresh_token": "<NEW_JWT_REFRESH>",
"token_type": "Bearer",
"expires_in": 1800
}
```
### 4.4. `POST /api/auth/logout`
**Request:**
```json
{
"refresh_token": "<JWT_REFRESH>"
}
```
**Response:**
```json
{
"status": "ok"
}
```
### 4.5. `GET /api/auth/me`
**Headers:** `Authorization: Bearer <access_token>`
**Response (200):**
```json
{
"id": "uuid",
"email": "user@example.com",
"display_name": "Alex",
"avatar_url": null,
"roles": ["user"],
"created_at": "2025-11-26T10:00:00Z"
}
```
---
## 5. HTTP API (INTERNAL)
### 5.1. `POST /api/auth/introspect`
**Request:**
```json
{
"token": "<JWT_ACCESS>"
}
```
**Response (200, valid):**
```json
{
"active": true,
"sub": "user_id-uuid",
"email": "user@example.com",
"roles": ["user"],
"exp": 1732591800
}
```
**Response (200, invalid):**
```json
{
"active": false
}
```
---
## 6. HEALTHCHECK
### `GET /healthz`
```json
{
"status": "ok",
"service": "auth-service",
"version": "1.0.0"
}
```
---
## 7. CONFIGURATION (ENV)
```env
AUTH_SERVICE_PORT=7020
AUTH_DB_DSN=postgresql://user:pass@postgres:5432/daarion
AUTH_JWT_SECRET=your-very-long-secret-key-here
AUTH_ACCESS_TOKEN_TTL=1800
AUTH_REFRESH_TOKEN_TTL=604800
AUTH_BCRYPT_ROUNDS=12
```
---
## 8. SECURITY NOTES
* Паролі зберігати тільки як `bcrypt` hash.
* JWT secret — довгий (мінімум 32 символи), збережений у `.env`.
* Rate limiting для `/auth/login` (захист від brute force).
* Логи не повинні писати паролі / токени.
* HTTPS обов'язковий у production.
---
## 9. ROADMAP (POST-MVP)
* OAuth2 / OIDC (Google, GitHub, Telegram).
* WebAuthn / passkeys.
* Device-level identity (звʼязок із Matrix devices).
* On-chain identity (wallet + DID).
* Email verification.
* Password reset flow.