Files
2025-09-15 09:31:51 +05:00

7.3 KiB
Raw Permalink Blame History

Документация по аутентификации (Frontend)

Обзор

JWT-аутентификация. Публичные и админские эндпоинты:

  • POST /api/auth/signin — вход и выдача JWT + refreshToken
  • POST /api/auth/refresh — обновление пары токенов (ротация)
  • POST /api/auth/logout — выход (инвалидация refreshToken)
  • POST /api/admin/users — создать пользователя (только ROLE_ADMIN)

Все запросы и ответы — JSON (Content-Type: application/json).

Базовый URL

  • Прод: укажите боевой домен/порт
  • Dev локально: https://api.konturai.kz

Переменные окружения (frontend)

  • REACT_APP_API_URL или NEXT_PUBLIC_API_URL: базовый URL API
  • Храните токен безопасно (HttpOnly cookie предпочтительно; если localStorage — учитывайте XSS риски)

Создание пользователя (Admin)

POST /api/admin/users

Требует: Authorization: Bearer <admin_access_token> и роль ROLE_ADMIN.

Запрос:

{
    "email": "user@example.com",
    "password": "StrongPass123!"
}

Успех:

  • 200 OK, пустой ответ

Ошибки:

  • 400 Bad Request — невалидный email/пароль
  • 401/403 — нет прав администратора
  • 409 Conflict — email уже зарегистрирован

Пример (fetch):

await fetch(`${API_URL}/api/admin/users`, {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json',
        Authorization: `Bearer ${adminAccessToken}`
    },
    body: JSON.stringify({ email, password })
});

Вход

POST /api/auth/signin

Запрос:

{
    "email": "user@example.com",
    "password": "StrongPass123!"
}

Успех:

  • 200 OK
{
    "accessToken": "<JWT>",
    "tokenType": "Bearer",
    "refreshToken": "<refresh-token>"
}

Ошибки:

  • 400/401 — неверные учетные данные

Пример (fetch):

const res = await fetch(`${API_URL}/api/auth/signin`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ email, password })
});
const { accessToken, refreshToken } = await res.json();
// Сохраните токен и используйте в Authorization заголовке

Обновление токена (Refresh Token)

Общая схема

  • При успешном входе фронт получает пару токенов: accessToken (короткоживущий) и refreshToken (длинноживущий).
  • accessToken используется в Authorization: Bearer <JWT>.
  • Когда accessToken истекает (HTTP 401), фронт вызывает /api/auth/refresh с refreshToken, получает новую пару токенов (ротация) и повторяет запрос.

Рекомендации по хранению

  • refreshToken предпочтительно хранить в HttpOnly Secure SameSite cookie (сервер ставит Set-Cookie).
  • Альтернатива (менее безопасная): хранить в памяти/secure storage и передавать в теле запроса.

POST /api/auth/refresh

Запрос (вариант с телом):

{
    "refreshToken": "<refresh-token>"
}

Успех:

  • 200 OK
{
    "accessToken": "<new-jwt>",
    "tokenType": "Bearer",
    "refreshToken": "<new-refresh-token>"
}

Ошибки:

  • 400 — отсутствует/некорректный refreshToken
  • 401 — просрочен/отозван/невалиден

Пример (fetch, с телом):

const res = await fetch(`${API_URL}/api/auth/refresh`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ refreshToken })
});
if (!res.ok) throw new Error('Refresh failed');
const { accessToken: newAccess, refreshToken: newRefresh } = await res.json();

Пример (cookie-стратегия):

const res = await fetch(`${API_URL}/api/auth/refresh`, {
    method: 'POST',
    credentials: 'include'
});
const { accessToken } = await res.json();

Ротация refreshToken

  • При каждом refresh возвращайте новый refreshToken и инвалидируйте старый.
  • На фронте заменяйте сохранённый refreshToken на новый.

TTL (рекомендации)

  • accessToken: 515 минут
  • refreshToken: 730 дней

Logout

  • Если refreshToken хранится в cookie: POST /api/auth/logout — сервер чистит cookie и отмечает refreshToken как отозванный.
  • Если в хранилище фронта — удалите локальные токены и по возможности вызовите logout для аннулирования на бэке.

Авторизация последующих запросов

Передавайте JWT в заголовке:

Authorization: Bearer <JWT>

Пример защищенного вызова:

await fetch(`${API_URL}/api/private/profile`, {
    headers: { Authorization: `Bearer ${token}` }
});

Формат ошибок (пример)

{
    "timestamp": "2025-09-11T12:34:56Z",
    "status": 409,
    "error": "Conflict",
    "message": "Email already registered",
    "path": "/api/auth/signup"
}

Валидация на фронте

  • Email: RFC-проверка и нормализация в lowercase
  • Пароль: минимум 8 символов, цифра, буква, спецсимвол
  • Обработайте статусы 400/401/409 и показывайте человекочитаемые сообщения

Хранение токена

  • Предпочтительно: HttpOnly Secure cookie, получаемое от бэкенда
  • Альтернатива: localStorage/sessionStorage (учтите XSS; не вставляйте токен в DOM)

Примеры cURL

Создание пользователя (admin):

curl -X POST "$API_URL/api/admin/users" \
  -H "Authorization: Bearer $ADMIN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"email":"user@example.com","password":"StrongPass123!"}'

Вход:

curl -X POST "$API_URL/api/auth/signin" \
  -H "Content-Type: application/json" \
  -d '{"email":"user@example.com","password":"StrongPass123!"}'

Заметки по безопасности

  • Не логируйте пароли и JWT
  • Реализуйте logout (инвалидация на клиенте или список отозванных токенов на бэке, если нужно)
  • Рекомендуется троттлинг/капча для /signin и создания пользователя

Изменения в будущем

  • Ротация refresh-токенов реализована; можно добавить список отозванных токенов
  • Подтверждение email
  • Сброс пароля через почту