← ПроектыAuth · SSO · 2025
HanDev Identity
Центральный сервис управления пользователями и SSO для всей платформы. Выпускает HttpOnly JWT-cookie на .handev.org, публикует JWKS для верификации в других сервисах, держит каталог пользователей, сервисов и доступов, поддерживает refresh-token-rotation и GitLab OAuth для связанных аккаунтов.
- RS256 JWT + JWKS на /.well-known/jwks.json, ключи ротируются
- 15-мин access + 30-дневный refresh, HttpOnly cookies SameSite=lax
- Тройной refresh: retry на 401, тик каждые 12 минут, visibilitychange
- Матрица доступов user × service, GitLab OAuth, isAdmin-derivation
Node 22FastifyDrizzlePostgreSQLReact 18

Задача
Платформе нужен единый центр аутентификации: один логин на все сервисы, ротация ключей подписи, корректное обновление токенов из background-вкладок, gate доступа per-service, админ-панель для управления пользователями и доступами.
Что сделали
- Backend на Fastify + Drizzle с собственной верификацией (без зависимости от jsonwebtoken), bcrypt для паролей.
- JWT claim-shape: iss, sub, exp, iat, email, name, isAdmin, globalRole, services. Подпись RS256, ключи ротируются, публичные ключи отдаются как стандартный JWKS на /.well-known/jwks.json.
- 15-минутный access + 30-дневный refresh, оба — HttpOnly cookies на .handev.org с SameSite=lax.
- Тройной refresh: /auth/refresh retry на 401, тик каждые 12 минут, refresh на visibilitychange.
- Админ-страницы: /admin/users (управление пользователями + global role), /admin/services (каталог сервисов), /admin/access (матрица доступов user × service).
- Service-access gate: грант доступа в user_service_access + проверка payload.services в каждом сервисе.
- isAdmin-derivation: globalRole === admin || payload.isAdmin === true — защита от случайного Boolean(undefined) = false.
- GitLab OAuth для связывания корпоративных GitLab-аккаунтов с Identity-пользователями. CORS callback допускает любой *.handev.org.
Результат
- Единый логин на 3 сервиса; добавление нового сервиса — пара SQL-вставок и build-deploy.
- Production-ready SSO с правильным refresh и обработкой 401.
- Чёткое разделение global role (admin/devops/qa/...) и service-internal role (admin/viewer/maintainer/...).