## Документация по аутентификации (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`.

Запрос:

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

Успех:

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

Ошибки:

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

Пример (fetch):

```js
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

Запрос:

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

Успех:

-   200 OK

```json
{
    "accessToken": "<JWT>",
    "tokenType": "Bearer",
    "refreshToken": "<refresh-token>"
}
```

Ошибки:

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

Пример (fetch):

```js
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

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

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

Успех:

-   200 OK

```json
{
    "accessToken": "<new-jwt>",
    "tokenType": "Bearer",
    "refreshToken": "<new-refresh-token>"
}
```

Ошибки:

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

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

```js
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-стратегия):

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

### Ротация refreshToken

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

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

-   accessToken: 5–15 минут
-   refreshToken: 7–30 дней

## Logout

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

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

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

```
Authorization: Bearer <JWT>
```

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

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

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

```json
{
    "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):

```bash
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!"}'
```

Вход:

```bash
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
-   Сброс пароля через почту
