Skip to content

Аутентификация

Механизм 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 автоматически включает соль и устойчив к атакам по времени.