Кейс · Go-бэкенд
Ключница: сервис аутентификации
Сервис аутентификации и авторизации на Go: EdDSA-JWT с ротацией ключей и JWKS, refresh-токены с ротацией и обнаружением кражи, TOTP-2FA (RFC 6238) с резервными кодами, RBAC, блокировка при переборе, сброс пароля по одноразовому токену, журнал аудита, список устройств, openapi.yaml. Не прошёл независимый аудит, не production-IdP.
- Go
- stdlib crypto
- SQLite
- modernc.org/sqlite (без CGO)
- JWT EdDSA/Ed25519
- JWKS
- PBKDF2
- TOTP
- RBAC
- REST
- OpenAPI 3
- Vanilla JS
- embed
- Docker
- GitHub Actions
01 · Как выглядит
Скриншоты


02 · О проекте
Что это и зачем
«Ключница» — сервис аутентификации и авторизации на Go: регистрация и вход, короткоживущие JWT с ротацией ключей и JWKS, refresh-токены с ротацией и обнаружением кражи, TOTP-2FA с резервными кодами, RBAC, защита от перебора, сброс пароля, журнал аудита и управление устройствами.
Стандартная библиотека плюс modernc.org/sqlite (без CGO), интерфейс на ванильном JS встроен через embed, API описан в openapi.yaml. Это учебный проект: он не проходил независимого аудита безопасности и не является production-IdP, ограничения перечислены ниже.
Ограничения
Не прошёл независимый аудит и не production-IdP. Нет OAuth 2.0 и OIDC, WebAuthn, подтверждения почты, входа через соцсети. Пароли хешируются PBKDF2, а не argon2id, потому что argon2 нет в stdlib.
Секреты TOTP и приватные ключи подписи лежат в БД открытым текстом: с дампом БД можно подделать токены. Письмо для сброса пароля это заглушка (лог и файл), QR-кода для 2FA нет.
Мгновенный отзыв работает только внутри самого сервиса: сторонний потребитель JWT узнает об отзыве не раньше exp (10 минут). Лимитер хранится в памяти одного процесса, масштабирования нет.
Демо-пароли публичные, они показаны в интерфейсе и помечены плашкой, пользоваться ими вне демонстрации нельзя. Тесты с -race проходят только в CI, Docker-образ не собирался.
Что внутри
- Access-токен JWT с alg=EdDSA (Ed25519): подпись и разбор написаны на stdlib, none и HS256 отклоняются до проверки подписи, проверяются exp, nbf, iss, aud и typ
- Ротация ключей через API и публичный JWKS (RFC 7517/8037): чужой сервис проверяет токены сам, старый ключ живёт ещё access_ttl + 1 минуту
- Refresh-токены хранятся хешем SHA-256; повторное предъявление использованного токена отзывает всю семью токенов и пишет token.reuse_detected в аудит
- TOTP по RFC 6238 на stdlib, проверен тестовыми векторами RFC, окно ±1 шаг, защита от повтора кода, 8 одноразовых резервных кодов
- Пароли: PBKDF2-HMAC-SHA256, 600 000 итераций, сравнение за постоянное время, фиктивный хеш для неизвестного логина, чтобы не раскрывать, есть ли такой пользователь
- Блокировка при переборе с экспоненциальной задержкой (429 и Retry-After), плюс лимит запросов на IP
- RBAC: права берутся из БД на каждом запросе, нельзя оставить систему без администратора и отключить самого себя
- Сброс пароля одноразовым токеном, после сброса все сессии завершаются; журнал аудита только на дозапись (триггеры БД запрещают UPDATE и DELETE)
- Список устройств с отзывом сессий, CSP без unsafe-inline, HttpOnly + SameSite=Strict cookie, CSRF-токен, проверка Origin
03 · Как запустить
Запуск одной командой
git clone <репозиторий по запросу> auth-service
cd auth-service
SEED_DEMO=1 go run ./cmd/server # http://localhost:8101, публичные демо-учётки показаны на странице входа04 · Код
Репозиторий приватный
Исходники лежат в приватном репозитории. Открою доступ по запросу: напишите, и пришлю приглашение.
Запросить код