Skip to content

# 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):

    [ 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

    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

    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

    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

    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:

    {
      "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:

    {
      "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:

    {
      "email": "user@example.com",
      "password": "StrongPassword123",
      "display_name": "Alex"
    }

Response (201):

    {
      "user_id": "uuid",
      "email": "user@example.com",
      "display_name": "Alex",
      "roles": ["user"]
    }

### 4.2. `POST /api/auth/login`

Request:

    {
      "email": "user@example.com",
      "password": "StrongPassword123"
    }

Response (200):

    {
      "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:

    {
      "refresh_token": "<JWT_REFRESH>"
    }

Response (200):

    {
      "access_token": "<NEW_JWT_ACCESS>",
      "refresh_token": "<NEW_JWT_REFRESH>",
      "token_type": "Bearer",
      "expires_in": 1800
    }

### 4.4. `POST /api/auth/logout`

Request:

    {
      "refresh_token": "<JWT_REFRESH>"
    }

Response:

    {
      "status": "ok"
    }

### 4.5. `GET /api/auth/me`

Headers: `Authorization: Bearer <access_token>`

Response (200):

    {
      "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:

    {
      "token": "<JWT_ACCESS>"
    }

Response (200, valid):

    {
      "active": true,
      "sub": "user_id-uuid",
      "email": "user@example.com",
      "roles": ["user"],
      "exp": 1732591800
    }

Response (200, invalid):

    {
      "active": false
    }

## 6. HEALTHCHECK

### `GET /healthz`

    {
      "status": "ok",
      "service": "auth-service",
      "version": "1.0.0"
    }

## 7. CONFIGURATION (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.