81 lines
7.0 KiB
Markdown
81 lines
7.0 KiB
Markdown
# Эндпоинты, с которыми взаимодействует auth-flow-frontend
|
||
|
||
Документ описывает внешние эндпоинты, внутренние роуты и каналы межвкладочной коммуникации микрофронтенда аутентификации `auth-flow-frontend`.
|
||
|
||
## Как устроено взаимодействие
|
||
|
||
Приложение отвечает только за аутентификацию по протоколу **OIDC (Authorization Code Flow + PKCE)**. Прямых REST-запросов к бэкенд-сервисам Sarex у него **нет** — всё сетевое взаимодействие идёт с провайдером идентификации **Zitadel** через обёртку `@sarex-team/sdk-js/zitadel` (поверх `oidc-client`).
|
||
|
||
Клиент создаётся в `src/config/zitadel.ts` (`createZitadelAuth(configZitadel)`). Базовый адрес провайдера (`authority`, issuer) и `client_id` берутся из `localStorage` во время работы, а не задаются сборкой. OIDC-клиент сам находит конкретные эндпоинты issuer'а через discovery-документ `/.well-known/openid-configuration`.
|
||
|
||
## Провайдер идентификации (Zitadel) по окружениям
|
||
|
||
Фактический `authority` подставляется хостовым приложением через `localStorage` (`STORAGE.AUTHORITY`) — в самом `auth-flow-frontend` хосты не захардкожены. Ниже — известные для платформы Sarex значения (справочно):
|
||
|
||
| Окружение | `authority` (issuer) |
|
||
| --- | --- |
|
||
| `stage` | `https://idp.dev.stage.sarex.io` |
|
||
| `prod` | `https://login.sarex.io` |
|
||
|
||
## OIDC-эндпоинты провайдера
|
||
|
||
Обнаруживаются через discovery и вызываются `oidc-client` относительно `authority`. Итоговые пути определяются метаданными issuer'а.
|
||
|
||
| Эндпоинт (метаданные) | Метод | Где инициируется | Назначение |
|
||
| --- | --- | --- | --- |
|
||
| `/.well-known/openid-configuration` | GET | инициализация `UserManager` | Discovery метаданных провайдера |
|
||
| `authorization_endpoint` | GET (redirect) | `LoginPage` → `zitadel.authorize()` | Старт авторизации, редирект на форму входа |
|
||
| `token_endpoint` | POST | `AuthCallbackPage` → `zitadel.userManager.signinCallback()` | Обмен `code` → access/refresh/id токены |
|
||
| `jwks_uri` | GET | `oidc-client` | Ключи для проверки подписи токенов |
|
||
| `userinfo_endpoint` | GET | `oidc-client` (при необходимости) | Профиль пользователя |
|
||
| `end_session_endpoint` | GET (redirect) | `LogoutPage` → `zitadel.signout()` | Завершение сессии (логаут) |
|
||
|
||
Параметры OIDC-запросов (из `configZitadel`):
|
||
|
||
- `response_type`: `code`
|
||
- `scope`: `openid profile email offline_access urn:zitadel:iam:user:metadata`
|
||
- `redirect_uri`: `${window.location.origin}/auth/callback`
|
||
- `post_logout_redirect_uri`: `${window.location.origin}/login`
|
||
- `revokeTokensOnSignout`: `false`, `automaticSilentRenew`: `false`
|
||
|
||
## Внутренние роуты приложения
|
||
|
||
Диспетчеризация — в `src/App.tsx` по `window.location.pathname` (роуты из `src/config/urls.ts`).
|
||
|
||
| Роут | Страница | Метод | Назначение |
|
||
| --- | --- | --- | --- |
|
||
| `/auth/callback` | `AuthCallbackPage` | — | Обработка OIDC-колбэка: `signinCallback()`, установка токенов, рассылка события в `login_channel`. Дефолт для неизвестных путей |
|
||
| `/auth/error` | `AuthErrorPage` | — | Отображение ошибки аутентификации (параметры `error`, `error_description`, `state`, `message` из query) |
|
||
| `/login` | `LoginPage` (dev) | — | Кнопка входа (`zitadel.authorize()`) |
|
||
| `/logout` | `LogoutPage` (dev) | — | Кнопка выхода (`zitadel.signout()`) |
|
||
| `/` | `MainPage` (dev) | — | Dev-навигация (login/logout) |
|
||
| `/ping` | nginx | GET | Healthcheck, отдаёт `{"result": "ok"}` |
|
||
|
||
## Поток аутентификации (кратко)
|
||
|
||
1. `LoginPage` вызывает `zitadel.authorize()` → редирект на `authorization_endpoint` Zitadel.
|
||
2. Провайдер возвращает пользователя на `redirect_uri` = `/auth/callback` с `code`.
|
||
3. `AuthCallbackPage` вызывает `signinCallback()` → обмен `code` на токены через `token_endpoint`.
|
||
4. Токены сохраняются (`setTokensInfo` → `storage.setAccessToken/setRefreshToken/setIdentityToken`), снимается флаг логаута.
|
||
5. Результат рассылается остальным вкладкам, происходит закрытие overlay-окна (`window.opener`) или переход на `/` (`HOME`).
|
||
6. При ошибке — редирект на `/auth/error` с деталями.
|
||
|
||
## Межвкладочная и оконная коммуникация
|
||
|
||
| Канал | Ключ / имя | Назначение |
|
||
| --- | --- | --- |
|
||
| `BroadcastChannel` | `login_channel` | Сообщения `{ type: "login_success" }` и `{ type: "login_error", reason }` между вкладками |
|
||
| `localStorage` | `sarex_logout` (`LOGOUT_STORAGE_KEY`) | Состояние логаута между вкладками (`logoutAt`, `owner`, `reason`) |
|
||
| window events | `setTokensInfoIntoWindowEvents` (`@sarex-team/sdk-js`) | Оповещение хостового приложения об обновлении токенов (`reason: "auth_callback"`) |
|
||
| `window.opener` | — | Режим overlay: после успешного входа окно закрывается (`window.close()`) |
|
||
|
||
## Обработка ошибок
|
||
|
||
Логика — в `src/utils/authError.ts`; отображение — `AuthErrorPage`.
|
||
|
||
- Параметры ошибки читаются из query-строки колбэка: `error`, `error_description`, `state`, `message` (`parseAuthErrorFromSearch`).
|
||
- Причина ошибки: `error_description` → `message` → `error` → `"Unknown error"` (`getAuthErrorReason`).
|
||
- URL страницы ошибки собирается `buildAuthErrorUrl` (query из непустых параметров, иначе просто `/auth/error`).
|
||
- Если контекста ошибки нет — редирект на `/` (`HOME`).
|
||
- Пользователю доступны кнопки «Скопировать детали ошибки» (`formatAuthErrorForCopy`) и «Вернуться на форму входа» (`/login`), а также ссылка в поддержку `mailto:support@sarex.io`.
|