1. Auth
Раздел описывает аутентификацию, авторизацию и модель доступа в Smart Parking API.
1.1 Общие правила
Авторизация запросов
Для защищённых эндпоинтов необходимо передавать токен доступа в заголовке:
Authorization: Bearer <access_token>
В MVP используется только access_token.
refresh_token не используется.
Доступ к карте
В MVP подписки не используются.
Все авторизованные пользователи имеют доступ к базовому клиентскому функционалу, включая просмотр карты.
Общие ошибки авторизации
| Код | Тип | Описание |
|---|---|---|
| 400 | Bad Request | Невалидное тело запроса или отсутствуют обязательные поля. |
| 401 | Unauthorized | Токен отсутствует, невалиден, истёк или сессия завершена. |
| 403 | Forbidden | Токен валиден, но у субъекта недостаточно прав для выполнения действия. |
| 409 | Conflict | Конфликт данных, например email уже используется. |
| 422 | Unprocessable Entity | Ошибка валидации. |
| 429 | Too Many Requests | Слишком много попыток входа. |
Пример ответа:
{
"error_description": "Missing or invalid access token"
}
1.2 Модель доступа
Доступ к API определяется через:
- глобальные роли пользователя;
- членство в партнёрских организациях;
- разрешения (
permissions); - область доступа к данным (
scope).
Глобальные роли
user— обычный пользователь;admin— администратор платформы.
Роли в партнёрской организации
partner_ownerpartner_adminpartner_managerpartner_analystpartner_viewer
Разрешения (permissions)
Базовый клиентский доступ
users.me.viewusers.me.updateusers.password.updatemap.viewzones.viewoccupancy.viewforecasts.viewrouting.createfeedback.create
Источники данных
sources.createsources.viewsources.updatesources.delete
Камеры
cameras.createcameras.viewcameras.updatecameras.delete
Парковочные зоны
zones.createzones.updatezones.delete
Статистика и аналитика
analytics.viewpartner_statistics.view
Управление пользователями партнёра
partner_members.viewpartner_members.invitepartner_members.updatepartner_members.disablepartner_access.manage
Административные права платформы
admin.users.viewadmin.users.manageadmin.partners.viewadmin.partners.manageadmin.system.viewadmin.system.manageadmin.monitoring.viewadmin.analytics.view
Область доступа к данным (scope)
Для операций чтения, изменения и удаления используется область доступа:
none— доступ отсутствует;own— только объекты, созданные пользователем;assigned— только объекты, явно назначенные пользователю;own_or_assigned— собственные и назначенные объекты;partner_all— все объекты партнёрской организации;global_all— все объекты системы.
Правило проверки доступа
Для защищённого эндпоинта сервер проверяет:
- валидность токена;
- наличие требуемого разрешения;
- принадлежность ресурса нужной области доступа.
1.3 Модель PartnerMembership
Используется в ответах Auth API для описания прав пользователя внутри партнёрской организации.
partner_id(integer) — идентификатор партнёрской организации.role(string) — роль пользователя в организации.permissions(string[]) — список разрешений в рамках этой организации.read_scope(string) — область доступа на чтение.write_scope(string) — область доступа на изменение.delete_scope(string) — область доступа на удаление.
Пример:
{
"partner_id": 10,
"role": "partner_manager",
"permissions": [
"sources.create",
"sources.view",
"sources.update",
"cameras.create",
"cameras.view",
"cameras.update",
"zones.create",
"zones.view",
"zones.update"
],
"read_scope": "own_or_assigned",
"write_scope": "own_or_assigned",
"delete_scope": "own"
}
1.4 POST /auth/register
Регистрирует нового обычного пользователя и создаёт новую сессию.
Эндпоинт предназначен для публичной формы регистрации на сайте или в приложении.
Request body (required)
email(string) — email пользователя.password(string) — пароль пользователя.full_name(string, optional) — имя пользователя.phone(string, optional) — номер телефона пользователя.
Пользователь, зарегистрированный через этот эндпоинт, создаётся с глобальной ролью
user.
Пример запроса
POST /api/v1/auth/register HTTP/1.1
Host: api.parktrack.live
Content-Type: application/json
{
"email": "user@example.com",
"password": "secret_123",
"full_name": "Иван Петров"
}
Response (201)
access_token(string) — токен доступа.token_type(string) — всегдаBearer.expires_in(integer) — срок жизни токена в секундах.user(object) — краткая информация о пользователе:user_id(integer)email(string)full_name(string | null)global_roles(string[])
Пример ответа (201)
{
"access_token": "<token>",
"token_type": "Bearer",
"expires_in": 86400,
"user": {
"user_id": 123,
"email": "user@example.com",
"full_name": "Иван Петров",
"global_roles": ["user"]
}
}
Ошибки
| Код | Тип | Описание |
|---|---|---|
| 400 | Bad Request | Невалидное тело запроса. |
| 409 | Conflict | Пользователь с таким email уже существует. |
| 422 | Unprocessable Entity | Ошибка валидации полей регистрации. |
| 429 | Too Many Requests | Слишком много попыток регистрации. |
Пример ответа (409)
{
"error_description": "User with this email already exists"
}
1.5 POST /auth/login
Аутентифицирует пользователя и создаёт новую сессию.
Request body (required)
login(string) — логин пользователя.password(string) — пароль пользователя.
Пример запроса
POST /api/v1/auth/login HTTP/1.1
Host: api.parktrack.live
Content-Type: application/json
{
"login": "user@example.com",
"password": "secret"
}
Response (200)
access_token(string) — токен доступа.token_type(string) — всегдаBearer.expires_in(integer) — срок жизни токена в секундах.user(object) — краткая информация о пользователе:user_id(integer)email(string)full_name(string | null)global_roles(string[])
Пример ответа (200)
{
"access_token": "<token>",
"token_type": "Bearer",
"expires_in": 86400,
"user": {
"user_id": 123,
"email": "user@example.com",
"full_name": "Иван Петров",
"global_roles": ["user"]
}
}
Ошибки
| Код | Тип | Описание |
|---|---|---|
| 400 | Bad Request | Невалидное тело запроса. |
| 401 | Unauthorized | Неверный логин или пароль. |
| 429 | Too Many Requests | Слишком много попыток входа. |
Пример ответа (401)
{
"error_description": "Invalid login or password"
}
1.6 POST /auth/password-reset/request
Создаёт запрос на восстановление пароля.
Эндпоинт используется, когда пользователь не может войти в аккаунт и нажимает «Забыли пароль?».
Эндпоинт публичный и не требует авторизации.
Если пользователь с указанным email существует и активен, сервер создаёт одноразовый reset-token, сохраняет его хеш в базе и отправляет письмо со ссылкой для сброса пароля.
Если пользователя с таким email нет или аккаунт неактивен, сервер всё равно возвращает успешный ответ. Это нужно, чтобы нельзя было проверить, зарегистрирован ли email в системе.
Request body (required)
email(string) — email пользователя.
Пример запроса
POST /api/v1/auth/password-reset/request HTTP/1.1
Host: api.parktrack.live
Content-Type: application/json
{
"email": "user@example.com"
}
Response (200)
ok(boolean) — всегдаtrue, если запрос обработан.reset_token(string | null) — reset-token. В production обычноnull; может возвращаться в dev-режиме, если SMTP не настроен или явно включён возврат токена.
Пример ответа в production
{
"ok": true,
"reset_token": null
}
Пример ответа в dev-режиме
{
"ok": true,
"reset_token": "Q9a2QY7V2uF9yJj..."
}
Поведение
- reset-token создаётся только для существующего активного пользователя;
- в базе хранится не сам token, а его хеш;
- срок действия token задаётся настройкой
PASSWORD_RESET_TTL_MINUTES; - значение по умолчанию —
30минут; - если SMTP настроен, пользователю отправляется письмо со ссылкой восстановления;
- если SMTP не настроен, token может быть возвращён в ответе для локальной разработки.
Настройки окружения
PASSWORD_RESET_TTL_MINUTES— срок действия reset-token в минутах.PASSWORD_RESET_LOGIN_URL— frontend URL страницы логина/сброса пароля.PASSWORD_RESET_RETURN_TOKEN— разрешает возвращать reset-token в ответе.SMTP_HOST— SMTP host.SMTP_PORT— SMTP port.SMTP_USERNAME— SMTP username.SMTP_PASSWORD— SMTP password.SMTP_FROM_EMAIL— email отправителя.SMTP_FROM_NAME— имя отправителя.SMTP_USE_TLS— использовать TLS.SMTP_USE_SSL— использовать SSL.
Ошибки
| Код | Тип | Описание |
|---|---|---|
| 400 | Bad Request | Невалидное тело запроса. |
| 422 | Unprocessable Entity | Email отсутствует или не прошёл валидацию. |
| 429 | Too Many Requests | Слишком много запросов восстановления. |
Пример ответа при ошибке валидации
{
"error_description": "Invalid email"
}
1.7 POST /auth/password-reset/confirm
Подтверждает сброс пароля и устанавливает новый пароль.
Эндпоинт используется после того, как пользователь перешёл по ссылке из письма или ввёл reset-token вручную.
Эндпоинт публичный и не требует авторизации.
Request body (required)
token(string) — reset-token из письма или dev-ответаPOST /auth/password-reset/request.new_password(string) — новый пароль пользователя.
Пример запроса
POST /api/v1/auth/password-reset/confirm HTTP/1.1
Host: api.parktrack.live
Content-Type: application/json
{
"token": "Q9a2QY7V2uF9yJj...",
"new_password": "new_secret_456"
}
Response (200)
ok(boolean) —true, если пароль успешно изменён.
Пример ответа
{
"ok": true
}
Поведение
- сервер хеширует переданный token и ищет его в таблице reset-token-ов;
- token должен существовать;
- token не должен быть использован ранее;
- token не должен быть истёкшим;
- пользователь, которому принадлежит token, должен существовать и быть активным;
- после успешной смены пароля token помечается использованным;
- повторное использование того же token невозможно.
Ошибки
| Код | Тип | Описание |
|---|---|---|
| 400 | Bad Request | Reset-token невалиден, уже использован или истёк. |
| 422 | Unprocessable Entity | Новый пароль не прошёл валидацию. |
| 429 | Too Many Requests | Слишком много попыток подтверждения сброса. |
Пример ответа при невалидном или истёкшем token
{
"error_description": "Reset token is invalid or expired"
}
Пример ответа при ошибке валидации нового пароля
{
"error_description": "Password must be at least 8 characters long"
}
1.8 POST /auth/logout
Завершает текущую сессию.
Headers
Authorization: Bearer <access_token>
Пример запроса
POST /api/v1/auth/logout HTTP/1.1
Host: api.parktrack.live
Authorization: Bearer <token>
Response (204) Тело ответа отсутствует.
Ошибки
| Код | Тип | Описание |
|---|---|---|
| 401 | Unauthorized | Токен отсутствует, невалиден или истёк. |
1.9 GET /auth/me
Возвращает информацию о текущем пользователе и его эффективных правах доступа.
Headers
Authorization: Bearer <access_token>
Response (200)
user_id(integer) — идентификатор пользователя.email(string) — email пользователя.full_name(string | null) — имя пользователя.global_role(string) — глобальная роль пользователя.permissions(string[]) — глобальные разрешения пользователя.partner_memberships(PartnerMembership[]) — список членств в партнёрских организациях.
Пример запроса
GET /api/v1/auth/me HTTP/1.1
Host: api.parktrack.live
Authorization: Bearer <token>
Пример ответа (200)
{
"user_id": 123,
"email": "user@example.com",
"full_name": "Иван Петров",
"global_role": "user",
"permissions": [
"users.me.view",
"users.me.update",
"users.password.update",
"map.view",
"zones.view",
"occupancy.view",
"forecasts.view",
"routing.create",
"feedback.create"
],
"partner_memberships": [
{
"partner_id": 10,
"role": "partner_manager",
"permissions": [
"sources.create",
"sources.view",
"sources.update",
"cameras.create",
"cameras.view",
"cameras.update",
"zones.create",
"zones.view",
"zones.update"
],
"read_scope": "own_or_assigned",
"write_scope": "own_or_assigned",
"delete_scope": "own",
"is_active": true
}
]
}
Ошибки
| Код | Тип | Описание |
|---|---|---|
| 401 | Unauthorized | Токен отсутствует, невалиден или истёк. |
1.10 Требования к защищённым эндпоинтам
Каждый защищённый эндпоинт должен явно указывать:
- требуется ли авторизация;
- какие разрешения нужны для выполнения действия;
- какая область доступа применяется к ресурсу.
Пример оформления в документации раздела:
- Требуемые разрешения:
cameras.update - Требуемая область доступа:
write_scopeдолжен включать целевую камеру
1.11 Совместимость
Auth API v1 фиксирует следующую модель для MVP:
-
используется только
access_token; -
refresh_tokenне используется; -
публичная регистрация выполняется через
POST /auth/register; -
публичное восстановление пароля выполняется через:
POST /auth/password-reset/request;POST /auth/password-reset/confirm;
-
карта доступна всем авторизованным пользователям;
-
доступ определяется ролями, разрешениями и областью доступа к данным.