Appearance
Логин — все responses бэкенда
POST /auth/login
Обязательные поля запроса:
json
{
"email": "user@example.com",
"password": "SecurePass123!"
}Успех — 200 OK
json
{
"data": {
"id": 1,
"email": "user@example.com",
"display_name": "Иван Петров",
"phone": null,
"account_type": "personal",
"email_verified": true,
"avatar_url": null,
"city_id": null,
"district_id": null,
"metro_station_id": null,
"rating": 4.8,
"reviews_count": 5,
"products_count": 12,
"is_active": true,
"is_admin": false,
"created_at": "2026-01-10T08:00:00+03:00"
}
}Побочные эффекты:
- Сессия регенерирована, установлены
user_id,is_admin,fingerprint - Создана запись UserSession (token hash, IP, User-Agent, TTL 30 дней)
- Счётчик
failed_login_attemptsсброшен в 0 - Запись в LoginAttempt с
success = true
Ошибки
Все ошибки возвращаются в формате:
json
{
"error": {
"code": "<error_code>",
"message": "<message>",
"details": { ... }
}
}CSRF — 422
Формат: { "error": { "code": "validation_error", "message": "Validation failed", "details": { "csrf": ["..."] } } }
| Backend message | Когда | Текст для фронта (RU) |
|---|---|---|
CSRF token is required | Нет CSRF-токена в cookie или заголовке | Ошибка безопасности. Перезагрузите страницу и попробуйте снова |
CSRF token mismatch | Токен в cookie не совпадает с X-CSRF-TOKEN | Ошибка безопасности. Перезагрузите страницу и попробуйте снова |
Invalid CSRF token | Невалидная подпись токена | Ошибка безопасности. Перезагрузите страницу и попробуйте снова |
Content-Type — 400
json
{ "error": { "code": "unsupported_media_type", "message": "Content-Type must be application/json or multipart/form-data" } }| Backend message | Текст для фронта (RU) |
|---|---|
Content-Type must be application/json or multipart/form-data | Произошла техническая ошибка. Попробуйте ещё раз |
Rate limit — 429
json
{ "error": { "code": "rate_limit_exceeded", "message": "Too many requests" } }Заголовки ответа: Retry-After: <seconds>, X-RateLimit-Limit: 5, X-RateLimit-Remaining: 0, X-RateLimit-Reset: <unix_timestamp>
Лимит: 5 попыток на email за 15 минут (sliding window, Redis DB 3).
| Backend message | Текст для фронта (RU) |
|---|---|
Too many requests | Слишком много попыток входа. Подождите 15 минут и попробуйте снова |
Неверные учётные данные — 401
Бэкенд возвращает одинаковый ответ для всех 4 случаев (не раскрывает причину):
json
{ "error": { "code": "authentication_required", "message": "Invalid email or password" } }| Фактическая причина | failure_reason в LoginAttempt | Backend message (одинаковый) | Текст для фронта (RU) |
|---|---|---|---|
| Email не найден | user_not_found | Invalid email or password | Неверный email или пароль |
| Неверный пароль | invalid_password | Invalid email or password | Неверный email или пароль |
| Аккаунт заблокирован | locked | Invalid email or password | Неверный email или пароль |
| Аккаунт деактивирован | deactivated | Invalid email or password | Неверный email или пароль |
Защита от брутфорса (при неверном пароле):
| Неудачных попыток | Задержка ответа | Действие |
|---|---|---|
| 1–3 | нет | — |
| 4–5 | 2 сек | — |
| 6–7 | 5 сек | — |
| 8–9 | 10 сек | — |
| 10+ | 10 сек | Аккаунт блокируется на 30 минут, отправляется email-уведомление |
Фронт не знает о блокировке — ответ всегда одинаковый Invalid email or password.
Валидация полей — 422
Формат: { "error": { "code": "validation_error", "message": "Validation failed", "details": { "<field>": ["..."] } } }
body
| Backend message | Когда | Текст для фронта (RU) |
|---|---|---|
Request body must be valid JSON | Тело запроса не JSON | Произошла техническая ошибка. Попробуйте ещё раз |
email
| Backend message | Когда | Текст для фронта (RU) |
|---|---|---|
Field "email" is required and must be a non-empty string | Отсутствует / пустой | Введите email |
Field "email" must be a valid email address | Невалидный формат | Введите корректный email |
password
| Backend message | Когда | Текст для фронта (RU) |
|---|---|---|
Field "password" is required and must be a non-empty string | Отсутствует / пустой | Введите пароль |
Серверная ошибка — 500
json
{ "error": { "code": "internal_error", "message": "Internal server error" } }| Backend message | Текст для фронта (RU) |
|---|---|
Internal server error | Произошла ошибка на сервере. Попробуйте позже |
Маппинг error code → действие фронта
error.code | HTTP | Действие фронта |
|---|---|---|
validation_error | 422 | Показать ошибки под соответствующими полями из details |
authentication_required | 401 | Показать общую ошибку над формой: «Неверный email или пароль» |
rate_limit_exceeded | 429 | Показать toast, заблокировать кнопку на Retry-After секунд |
unsupported_media_type | 400 | Показать общую ошибку (техническая) |
internal_error | 500 | Показать общую ошибку |