# Аутентификация: gnexus-auth (SSO)

Все пользовательские сервисы Gnexus подключаются к центральному SSO — gnexus-auth
(Laravel). Сервис не создаёт собственную систему пользователей и не имеет собственной
«страницы входа» — в сервисе только гейт (заглушка с кнопкой **Войти** по OAuth PKCE).

## Правила
- Регистрация OAuth-клиента в gnexus-auth (client_id + client_secret) — владелец делает в админке `/admin/clients`.
- redirect_uri — постоянный HTTPS-адрес сервиса (`<сервис>/auth/callback`).
- Секреты клиента — в `.env` сервиса и в gnexus-creds, не в git.
- Готовые клиентские библиотеки: `gnexus-auth-client-py` (Python), `gnexus-auth-client-php` (PHP).
- Личность пользователя — `sub` из gnexus-auth; локальная запись пользователя зеркалируется (`user_id`, email, имя, профиль), профиль gnexus-auth — источник истины.

## Что у gnexus-auth есть для сервиса
- OAuth 2.0 PKCE (`/auth/login` → callback), scopes `openid email profile roles permissions`.
- Webhook-события `user.*` с HMAC-подписью (см. ниже).
- Язык аккаунта (`profile.locale`) — источник языка интерфейса по умолчанию (см. [i18n.md](i18n.md)).
- Опциональный allowlist сервиса: пусто = пускаем любого залогиненного, иначе список email через запятую.

## Каркас клиента (паттерн gnexus-creds / hard-panel)
- Вход через `/auth/login` только **по явному клику** — никаких авто-редиректов на загрузку страницы.
- SPA-гейт: splash → `GET /me` → `denied` (гейт с кнопкой входа) или `ready` (интерфейс).
- Сессия — httpOnly-cookie своего имени (например `ghard_session`) из SQLite, TTL ~7 суток; state/PKCE тоже в SQLite (`oauth_states`).
- `401` из API → ивент `unauthenticated` → сессии нет → гейт (не редирект).
- `GET /me` возвращает `{auth_enabled, user: {user_id, email, display_name, avatar_url}, locale…}`.
- Личная настройка пользователя (`PATCH /me`) — **только по cookie-сессии**: у Bearer-токенов нет личности (Bearer-админ → 401).
- При auth-off (client_id пуст) панель/сервис открыты без логина, личные настройки — в localStorage браузера.

## Вебхуки gnexus-auth (обязательно для клиента)
Роут `/webhooks/gnexus-auth`, подпись HMAC в заголовках (`t=<ts>,v1=<hmac>`), секрет — `*AUTH_WEBHOOK_SECRET`:
- **profile.update** — обновить в локальной зеркальной записи имя, аватарку и профиль (`profile` хранится verbatim JSON). Не должен затирать локальные override-ы пользователя (например override языка).
- **global_logout** — удалить все сессии сервиса, чей user_id совпал (авто-логаут после смены пароля/выхода).
- Роут регистрируется со двумя спеллингами (со слэшем и без) — защита от SPA catch-all.

## Матрица доступа сервиса
| Кто | Как | Для чего |
|---|---|---|
| Браузер | cookie-сессия через SSO | UI, `PATCH /me` |
| Скрипты, MCP, ИИ-агенты | Bearer API-токен сервиса (см. [mcp.md](mcp.md)) | REST API |
| Машинные агенты | ключи агрегатов (`ghm_…`, `X-Server-Key`) | отдельные каналы (ingest) |

## Ссылки
- Репозиторий: https://git.gnexus.space/root/gnexus-auth
- Клиенты: `gnexus-auth-client-py`, `gnexus-auth-client-php`
- Факты о сервисе: gnexus-book → `10-systems/services/gnexus-auth.md`