Архитектура — Versola Docs
/docs
До 1.00.7.5versola.ioGitHub

Архитектура

Три уровня Versola (central, auth, edge), общая база Postgres, порты и путь запроса браузера или мобильного приложения через эти уровни.

Versola состоит из трех сервисов, сгруппированных в три уровня, и прокси, который маршрутизирует трафик и отдает консоль администратора. Здесь описано, чем владеет каждый уровень и как запрос проходит через них. Развертывание на этой странице не рассматривается: см. раздел Эксплуатация.

Три уровня

УровеньСервисЧем владеет
Управления (control)centralИсточник истины для конфигурации: тенанты, клиенты, scope, роли, разрешения, ресурсы, ключи подписи. Предоставляет Central API
Данных (data)authСервер OAuth 2.0 / OpenID Connect: вход, токены, сессии, пользователи и их учетные данные
Трафика (traffic)edgeОбратный прокси с аутентификацией и авторизацией перед вашими API. Служит шлюзом и для браузерных приложений (вход, сессии), и для нативных мобильных

auth и edge получают конфигурацию из central. Администраторы меняют конфигурацию только через central: в консоли администратора или через Central API.

Уровень управления: central

central хранит конфигурацию и обслуживает Central API (OpenAPI: central.yaml). На пустой базе он один раз применяет начальную конфигурацию (bootstrap). Дальше конфигурацию меняют через консоль.

Консоль администратора — статическое одностраничное приложение. Она собрана в образ versola-tools и отдается прокси по адресу /central/admin/. У консоли нет собственного сервера: ее вызовы API уходят на /central/* прокси, который направляет их через edge в central, то есть между консолью и central стоит edge.

Уровень данных: auth

auth реализует потоки OAuth 2.0 и OIDC: /authorize, /par, /token, /introspect, /revoke, /userinfo, выход и discovery. Он ведет диалог входа (пароль, OTP, passkey), выпускает и подписывает токены и хранит пользователей. Дополнительно он может поднять второй TLS-listener для mutual TLS (см. токены с привязкой к отправителю).

Уровень трафика: edge

У edge три задачи:

  • Сессии браузера. Он работает как OAuth-клиент для веб-приложений (/login/{presetId}, /complete). Токены остаются на стороне сервера, а браузер получает cookie EDGE_SESSION (HttpOnly, Secure, SameSite=Strict). Refresh-токены хранятся в схеме edge, а истекшие access-токены edge обновляет сам.
  • Прокси с политиками. Он проксирует /resources/{resourceId}/{path} к вашему upstream API. Для каждого запроса проверяются отзыв токена, его привязка, разрешения, audience и CEL-правила эндпоинта, после чего edge добавляет заголовки или параметры запроса, построенные из токена и данных пользователя. См. Edge.
  • Шлюз для нативных приложений. Мобильные приложения вызывают эндпоинты /native/*, а edge проводит авторизацию от их имени с помощью PAR и ключа DPoP, который хранится на устройстве. См. Нативные приложения.

Базы данных

Каждый сервис владеет своими данными и своей историей миграций, а друг с другом сервисы общаются только по HTTP API. В стандартной топологии у каждого сервиса своя база Postgres, поэтому они масштабируются, резервируются и отказывают независимо. В минимальном варианте все три сервиса работают в одной базе, каждый в своей схеме (auth, central, edge). Именно так устроены versola bootstrap local и деплой на VPS. Ни в одной из топологий сервис не читает таблицы другого сервиса.

flowchart TB
    admin[["👤 Administrator"]]
    user[["👤 End user"]]

    subgraph versola["⚡ Versola"]
        proxy["versola-proxy<br/><i>nginx</i><br/>Routing and admin console files"]
        edge["edge<br/><i>traffic plane</i><br/>Sessions, policies, native gateway"]
        auth["auth<br/><i>data plane</i><br/>OAuth 2.1 and OIDC server"]
        central["central<br/><i>control plane</i><br/>Configuration and Central API"]
        db[("Postgres<br/>one database<br/>schemas auth, central, edge")]
    end

    upstream{{"🔌 Upstream APIs"}}
    notifications{{"📧 OTP delivery"}}

    admin -->|Console and API| proxy
    user -->|Login and API calls| proxy

    proxy --> edge
    proxy --> auth
    edge -->|Token, PAR, userinfo| auth
    edge -->|Console API calls| central
    edge -.->|Sync| central
    auth -.->|Sync| central
    edge -->|Proxy| upstream
    auth -->|Request OTP| notifications

    central --> db
    auth --> db
    edge --> db

    style admin fill:#92400e,stroke:#92400e,color:#fff
    style user fill:#166534,stroke:#166534,color:#fff
    style proxy fill:#334155,stroke:#e6edf3,color:#fff
    style central fill:#155e75,stroke:#e6edf3,color:#fff
    style edge fill:#155e75,stroke:#e6edf3,color:#fff
    style auth fill:#155e75,stroke:#e6edf3,color:#fff
    style db fill:#0e4a5c,stroke:#e6edf3,color:#fff
    style upstream fill:#334155,stroke:#e6edf3,color:#fff
    style notifications fill:#334155,stroke:#e6edf3,color:#fff
    style versola fill:#eaf3f5,stroke:#155e75,stroke-width:2px,color:#15171c

Порты

ПортПеременнаяЧто обслуживает
8080PORTAPI сервиса (auth)
8081DPORT/metrics, /liveness, /readiness
8082APORTВнутренний API (auth: настройки аккаунта)
8083MPORTListener для mutual TLS у auth и у edge (для /resources), каждый только если настроен его блок mutual-tls

В серверном развертывании (vps), созданном через CLI, central слушает 8090 (диагностика 8091), edge — 8095 (диагностика 8096), а versola-proxy — 2821. Локальный стек тоже публикует прокси на 127.0.0.1:2821.

Путь запроса

flowchart TB
    admin[["👤 Admin<br/><i>Manages platform</i>"]]
    user[["👤 End User<br/><i>Accesses apps</i>"]]

    versola["⚡ Versola<br/><b>Identity & Authorization Platform</b>"]

    upstream{{"🔌 Upstream<br/>Backend APIs"}}
    notifications{{"📧 Notification Channel<br/>Notifications"}}

    admin -->|Manage| versola
    user -->|Auth| versola
    versola -->|Proxy| upstream
    versola -->|Request Notification| notifications

    style admin fill:#92400e,stroke:#92400e,color:#fff
    style user fill:#166534,stroke:#166534,color:#fff
    style versola fill:#155e75,stroke:#e6edf3,color:#fff,stroke-width:3px
    style upstream fill:#334155,stroke:#e6edf3,color:#fff
    style notifications fill:#334155,stroke:#e6edf3,color:#fff

Браузерное приложение

  1. Браузер открывает GET /login/{presetId} на edge.
  2. Если клиенту нужен PAR, edge отправляет запрос авторизации в auth, затем перенаправляет браузер на /authorize в auth с PKCE и state.
  3. auth выполняет вход пользователя и перенаправляет обратно на /complete в edge с кодом.
  4. edge обменивает код на токены через /token, сохраняет refresh-токен и устанавливает cookie EDGE_SESSION.
  5. Каждый вызов API идет с этим cookie. edge проверяет токен, применяет политику и проксирует запрос.
sequenceDiagram
    autonumber
    participant B as Browser
    participant E as edge
    participant A as auth
    participant U as Upstream

    B->>E: GET /login/:presetId
    E->>A: POST /par (when the client requires PAR)
    E-->>B: 302 → auth /authorize (PKCE, state)

    note over B,A: Challenge flow (password / OTP / passkey)

    A-->>B: 302 → edge /complete?code=…&state=…
    B->>E: GET /complete?code=…
    E->>A: POST /token (code + PKCE verifier)
    A-->>E: access_token + refresh_token
    E->>E: Store refresh token in DB
    E-->>B: 302 → app  +  Set-Cookie: EDGE_SESSION

    note over B,E: Session active — every request carries the cookie

    B->>E: GET /resources/api/v1/data
    E->>E: Validate token, check revocation, evaluate CEL rules
    E->>U: Forward + inject Authorization header (Basic / Bearer)
    U-->>E: 200 OK
    E-->>B: 200 OK (upstream Set-Cookie stripped)

Мобильное приложение через edge

У нативного клиента за edge нет собственного клиентского секрета. edge аутентифицируется в auth как клиент по сертификату на listener mTLS, а токены привязывает к ключу DPoP, который хранится на устройстве. Redirect выполняется через App Link, а не через собственную схему URI.

sequenceDiagram
    autonumber
    participant M as Mobile app
    participant E as edge
    participant A as auth
    participant U as Upstream

    M->>E: POST /native/start/{clientId} + DPoP proof (device key)
    E->>A: POST /par as the client (PKCE, state, dpop_jkt)
    E-->>M: request_uri, sealed blob

    note over M,A: System browser opens auth /authorize, user signs in

    A-->>M: Redirect to the App Link with code and state
    M->>E: POST /native/complete/{clientId} + blob + DPoP proof
    E->>A: POST /token (code + PKCE verifier from blob)
    A-->>E: DPoP-bound access_token + refresh_token
    E-->>M: Token response relayed unchanged
    M->>M: Store tokens and device key (Keychain / Keystore)

    note over M,E: Session active — app sends DPoP-bound calls

    M->>E: GET /resources/api/v1/data + Authorization: DPoP + DPoP proof
    E->>E: Check revocation, token binding, permissions and CEL rules
    E->>U: Forward + inject Authorization header
    U-->>E: 200 OK
    E-->>M: 200 OK

    note over M,E: Refresh

    M->>E: POST /native/token/{clientId} (refresh_token) + DPoP proof
    E->>A: POST /token as the client
    A-->>E: new tokens
    E-->>M: new tokens

Нативное приложение может быть и публичным клиентом, который обращается к auth напрямую, но только в тенанте с профилем standard (профили безопасности).

См. также