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

249 lines
7.3 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
## Документация по аутентификации (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: 515 минут
- refreshToken: 730 дней
## 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
- Сброс пароля через почту