Аутентификация
Механизм JWT токенов
SLOzy использует два типа JWT токенов для аутентификации:
Access token
Короткоживущий токен (8 часов по умолчанию):
json
{
"user_id": 42,
"organization_id": 1,
"email": "user@example.com",
"name": "Иван Петров",
"exp": 1750000000,
"iat": 1749971200,
"iss": "slozy"
}Передаётся в заголовке:
http
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...Refresh token
Токен для обновления access token, живёт 30 дней:
http
POST /api/v1/auth/refresh
Content-Type: application/json
{
"refresh_token": "eyJhbGciOiJIUzI1NiIs..."
}Ответ:
json
{
"access_token": "eyJhbGci...",
"refresh_token": "eyJhbGci...",
"token_type": "Bearer",
"expires_at": "2026-06-12T20:00:00Z",
"user": {
"id": 42,
"email": "user@example.com",
"name": "Иван Петров"
}
}Хранение сессий
Токены сохраняются в таблице user_sessions:
sql
INSERT INTO user_sessions (user_id, session_token, refresh_token, ip_address, user_agent, expires_at)
VALUES ($1, $2, $3, $4, $5, $6);Поток аутентификации
1. POST /api/v1/auth/register — создание пользователя
2. POST /api/v1/auth/login — получение access + refresh токенов
3. API запросы с Bearer token
4. POST /api/v1/auth/refresh — обновление токенов по истечении
5. POST /api/v1/auth/logout — удаление сессииСброс пароля
Реализован через миграцию 000014_password_reset:
http
POST /api/v1/auth/password-reset/request
Content-Type: application/json
{
"email": "user@example.com"
}Сервер генерирует UUID-токен с TTL 1 час и сохраняет в password_reset_tokens.
http
POST /api/v1/auth/password-reset/reset
Content-Type: application/json
{
"token": "uuid-токен-из-письма",
"new_password": "newSecurePassword123"
}Токен одноразовый — после использования помечается как used = TRUE.
OAuth2
Миграция 000013_oauth2_persistence добавляет поддержку OAuth2:
sql
CREATE TABLE oauth2_tokens (
id SERIAL PRIMARY KEY,
user_id INT REFERENCES users(id),
provider VARCHAR(50) NOT NULL,
access_token TEXT NOT NULL,
refresh_token TEXT,
expires_at TIMESTAMP
);Аудит входов
Все попытки входа логируются в login_attempts:
sql
INSERT INTO login_attempts (user_id, ip_address, user_agent, success, failure_reason, created_at)
VALUES ($1, $2, $3, $4, $5, NOW());Успешные и неуспешные попытки сохраняются для анализа безопасности.
bcrypt
Пароли хэшируются алгоритмом bcrypt с дефолтной стоимостью:
go
hash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)bcrypt автоматически включает соль и устойчив к атакам по времени.