Files
auth-portal/docs/integrate-cfdm.md
DenozordecandCursor 57e34ff5e9
Build and Push Auth Portal Docker Image / build-and-push (push) Successful in 1m46s
Build and Push Auth Portal Docker Image / create-release (push) Skipped
feat(admin): ingest аудита из apps и users 1:1 с Sheet журнала
Добавлен POST /api/v1/ingest/audit, фильтры source_app/user_id, last_login_at; таблица пользователей по solution-users-1 с журналом в Sheet.

Co-authored-by: Cursor <[email protected]>
2026-07-21 13:24:28 +07:00

4.8 KiB
Raw Permalink Blame History

Интеграция auth-portal ↔ Cloudflare Domain Manager (CFDM)

Единый вход: пользователь логинится на auth-portal, получает JWT, переходит в CFDM с токеном в URL fragment. CFDM API проверяет JWT и права cfdm:*.

Архитектура

Browser → CFDM UI (нет token)
       → redirect AUTH_PORTAL_URL/?return_to=…/auth/callback
       → login
       → redirect return_to#access_token=…
       → CFDM /auth/callback сохраняет token (cfdm_token)
       → API Authorization: Bearer …

Общий секрет: JWT_SECRET / AUTH_JWT_SECRET (HS256). Issuer: ISSUER / AUTH_ISSUER.

App id в портале: cfdm (уже в каталоге permissions).

Локальный запуск

1. auth-portal

cd auth-portal
pnpm install
# JWT_SECRET=dev-secret-change-me
# RETURN_TO_ALLOWLIST=.shnt.top,localhost,http://localhost:5173,http://localhost:5174
pnpm --filter @authportal/api dev   # :8080
pnpm --filter web dev               # :5175

В apps/web/.env.local:

VITE_CFDM_APP_URL=http://localhost:5174

Bootstrap: [email protected] / admin. В админке выдайте app cfdm и permissions cfdm:*.

2. cloudflare-domain-manager

cd cloudflare-domain-manager
pnpm install

Корень / API:

AUTH_REQUIRED=true
AUTH_JWT_SECRET=dev-secret-change-me
AUTH_ISSUER=https://auth.shnt.top
AUTH_PORTAL_URL=http://localhost:5175

apps/web/.env.local:

VITE_AUTH_ENABLED=true
VITE_AUTH_PORTAL_URL=http://localhost:5175

Порт Vite web — см. apps/web/vite.config.ts (часто 5174). Добавьте origin в RETURN_TO_ALLOWLIST портала.

pnpm --filter api dev
pnpm --filter web dev

Откройте CFDM → редирект на portal → после логина NavUser показывает имя/email.

Permissions ↔ API / UI

Иерархия: adminwriteread в рамках одной секции.

Permission API UI
cfdm:domains:read GET /api/v1/domains*, monitors /, /domains
cfdm:domains:write мутации domains, sync create/edit/sync
cfdm:dns:read GET dns, subdomains DNS на карточке домена
cfdm:dns:write мутации dns/subdomains формы DNS
cfdm:certificates:read GET certificates /certificates
cfdm:certificates:write мутации certificates действия сертификатов
cfdm:groups:read GET groups, service-groups /groups
cfdm:groups:write мутации groups формы групп
cfdm:services:read GET services, bindings /services
cfdm:services:write мутации services формы сервисов
cfdm:settings:admin settings, notifications, health-check /settings/*

Без app cfdm в JWT apps403 на защищённые /api/v1/*.

AUTH_REQUIRED=false — локальный login (ADMIN_*) для тестов/dev без portal; UI /login.

App Switcher

Публичный конфиг: GET {AUTH_PORTAL_URL}/api/v1/app-switcher (CORS open). CFDM chrome (AppSwitcher / AppsMenu) читает его через ensureAuthConfig().portalUrl; offline fallback — hardcoded defaults с ids cfdm | vps | bgp.

Редактор только на портале: Админка → Ссылки приложений (/admin/apps). В CFDM Settings → Integrations — read-only ссылка на портал.

CURRENT_APP_ID = cfdm. Если в JWT есть apps[] — в меню только пересечение с каталогом.

Audit ingest

Dual-write локального журнала в portal: integrate-audit-ingest.md (source_app: cfdm).

UI аккаунта

SidebarFooter → NavUser (app-shell-1): Настройки, Тема, Выйти → AUTH_PORTAL_URL/logout.

Logout (SSO)

Очистить cfdm_token → редирект на /logout портала (не на /?return_to=… — иначе portal сразу выдаст новый SSO-токен).

Troubleshooting

Симптом Причина
SSO loop / «Сессия не принята» разный JWT_SECRET или ISSUER у portal и CFDM
403 «Нет доступа к приложению» у пользователя нет app cfdm в portal
403 «Недостаточно прав» нет нужного cfdm:… permission
return_to rejected origin CFDM не в RETURN_TO_ALLOWLIST
«Выйти» сразу возвращает в CFDM клиент должен открывать /logout, не login с return_to