diff --git a/v2/swagger.yaml b/v2/swagger.yaml index c8035c4..163908a 100644 --- a/v2/swagger.yaml +++ b/v2/swagger.yaml @@ -27,86 +27,6 @@ info: {sessionId} - you will get this form /mobile/auth method {sessionSecret} - you will get this form /mobile/auth method the last one (x-hrbox-embed) is for opening web pages in WebView to remove website footer and header - - --- - - # Авторизация по личному API-токену (Personal Access Token, PAT) - - Для серверных интеграций (web-zaim и т.п.) удобнее не держать сессию, - а использовать постоянный токен. Токен работает **только на `/api/v2/*`** - (для `/api/v1/*`, `/api/v3/*`, `/admin/*` и веб-страниц — игнорируется). - - ## Получение токена - - 1. Юзеру, от имени которого будет работать интеграция, нужно право - `api-tokens-manage` (выдаётся точечно администратором). - 2. Юзер открывает `/profile/settings/api-tokens` в веб-интерфейсе и жмёт - «Создать токен» — задаёт название и (опционально) дату истечения. - Plain-секрет **показывается один раз** в этом окне, после закрытия - восстановить нельзя. - 3. Альтернативно — `POST /api/v2/user-api-token` под session-авторизацией - (см. ниже про management-эндпоинты). Plain также возвращается - один раз в поле `data.plain`. - - Формат plain-токена: `hrb_` + 32 url-safe символов = 36 символов всего. - В БД хранится только HMAC-SHA-256 хеш и видимый префикс (первые 12 - символов с `hrb_`). - - ## Использование токена - - Подписывайте каждый запрос заголовком `Authorization`: - - ``` - Authorization: Bearer hrb_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx - ``` - - Tenant авторезолвится по `Host`-заголовку запроса, поэтому - `x-hrbox-tenant-id` / `x-hrbox-tenant-domain` **необязательны**. - Если всё же передаёте — будут строго провалидированы, невалидный - идентификатор тенанта → 400. `x-hrbox-session-id` / `x-hrbox-session-code` - при Bearer-аутентификации **не нужны**. - - ## Права и scopes - - ⚠️ **Гранулярных scopes у токена нет.** Токен наследует **все права того - юзера**, под которым выпущен. Это означает что для интеграции нужно - создать **отдельного системного пользователя** и выдать ему ровно те - права, которые требуются (например, `wallets-transactions` для нового - `/api/v2/admin/wallet*`). Не используйте свой личный аккаунт. - - ## Отзыв и жизненный цикл - - - Юзер отзывает свой токен через `POST /api/v2/user-api-token/revoke` - (или из UI). - - Администратор с правом `api-tokens-admin` может посмотреть/отозвать - любой токен тенанта через `/api/v2/admin/user-api-token*`. Plain - админу **никогда не виден**, только префикс. - - При блокировке юзера (`reg_status_id = BLOCKED`) все его токены - автоматически отзываются. При разблокировке **обратно не восстанавливаются** — - нужно выпускать новые. - - Если у токена выставлен `expires_at` — после этой даты он перестаёт - работать сам (статус `EXPIRED`). - - ## Когда валидный токен всё равно даёт 401 - - `User::findIdentityByAccessToken` дополнительно вызывает - `User::isValidForDisplay()`, поэтому даже корректный live-токен - отдаёт `401 Login Required`, если у владельца: - - - `is_hidden = true` (юзер скрыт администратором), либо - - `reg_status_id` **не входит** в `RegStatus::validForDisplay()` - (например `INVITED`, `BLOCKED` и пр.). - - Для системного юзера-интегратора убедитесь, что он `is_hidden=false` - и в активном reg-статусе, иначе токен не пройдёт ни на одном - `/api/v2/*` эндпоинте. - - ## Управление токенами под Bearer запрещено - - Management-эндпоинты (`/user-api-token*`, `/admin/user-api-token*`) - отдают `403`, если запрос аутентифицирован Bearer-токеном — нельзя - выпускать или отзывать токены от имени токена. Управляйте только - под обычной web-сессией. contact: email: yuriy@hrbox.io @@ -147,16 +67,6 @@ tags: description: Админский API транзакций кошелька — проведение начислений/списаний (form/excel) и просмотр. - name: file-processing description: Статусы асинхронных обработок файлов (excel-импорт/экспорт, архивы). Видны только записи текущего пользователя. - - name: user-api-token - description: | - Личные API-токены (Personal Access Tokens) для серверных интеграций. - Юзер управляет только своими токенами. Permission `api-tokens-manage`. - Management-эндпоинты доступны **только под обычной session-авторизацией** - (Bearer запрещён). См. секцию «Авторизация по личному API-токену» выше. - - name: admin-user-api-token - description: | - Админский обзор и отзыв любых PAT тенанта. Permission `api-tokens-admin`. - Plain-секрет недоступен — виден только `token_prefix`. paths: /mobile/bind/{id}/{token}: @@ -7355,201 +7265,6 @@ paths: schema: $ref: '#/components/schemas/FileProcessing' - /user-api-token: - get: - tags: [user-api-token] - summary: Список своих API-токенов - description: | - Возвращает PAT текущего юзера. Plain-секрет уже недоступен — - для идентификации используется `token_prefix` (первые 12 символов, - начинаются с `hrb_`). - operationId: userApiTokenIndex - security: - - SessionAuth: [] - parameters: - - name: page - in: query - schema: { type: integer, minimum: 1, default: 1 } - - name: per-page - in: query - schema: { type: integer, minimum: 1, default: 20 } - - name: sort - in: query - schema: - type: string - enum: [created_at, "-created_at", last_used_at, "-last_used_at", expires_at, "-expires_at"] - description: По умолчанию `-created_at`. - responses: - 200: - description: Список токенов - content: - application/json: - schema: - $ref: '#/components/schemas/UserApiTokenList' - 403: - description: Запрос пришёл под Bearer-токеном (запрещено) или нет права `api-tokens-manage`. - - /user-api-token/create: - post: - tags: [user-api-token] - summary: Создать новый API-токен (plain возвращается один раз) - description: | - Создаёт PAT для текущего юзера. **Plain-секрет (`data.plain`) - возвращается только в этом ответе и больше нигде не доступен** — - сохраните его сразу. - - `expires_at` опционален; если задан, должен быть не в прошлом - (валидируется по началу текущего дня). Токен работает весь - указанный день включительно (23:59:59). - - Доступно только под session-авторизацией (запрос под Bearer → 403). - operationId: userApiTokenCreate - security: - - SessionAuth: [] - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/UserApiTokenCreateForm' - responses: - 200: - description: Токен создан (либо ошибки валидации в стандартном формате `httpJsonResponse`). - content: - application/json: - schema: - allOf: - - $ref: '#/components/schemas/httpJsonResponse' - - type: object - properties: - data: - $ref: '#/components/schemas/UserApiTokenCreated' - 403: - description: Запрос пришёл под Bearer-токеном или нет права `api-tokens-manage`. - - /user-api-token/revoke: - post: - tags: [user-api-token] - summary: Отозвать свой API-токен - description: | - Идемпотентно: повторный revoke уже отозванного токена просто ничего не делает. - Чужой токен отозвать нельзя — будет 403/404. - - Доступно только под session-авторизацией (запрос под Bearer → 403). - operationId: userApiTokenRevoke - security: - - SessionAuth: [] - requestBody: - required: true - content: - application/json: - schema: - type: object - required: [id] - properties: - id: - type: string - format: uuid - responses: - 200: - description: Успех - content: - application/json: - schema: - $ref: '#/components/schemas/httpJsonResponse' - 400: - description: Параметр `id` не строка или не uuid. - 403: - description: Токен принадлежит другому юзеру, либо запрос под Bearer, либо нет права `api-tokens-manage`. - 404: - description: Токен не найден. - - /admin/user-api-token: - get: - tags: [admin-user-api-token] - summary: Список API-токенов всех юзеров тенанта - description: | - Админский обзор PAT. Permission `api-tokens-admin`. Plain-секрет - здесь **никогда не возвращается** (только `token_prefix`). - - Доступно только под session-авторизацией (запрос под Bearer → 403). - operationId: adminUserApiTokenIndex - security: - - SessionAuth: [] - parameters: - - name: page - in: query - schema: { type: integer, minimum: 1, default: 1 } - - name: per-page - in: query - schema: { type: integer, minimum: 1, default: 20 } - - name: sort - in: query - schema: - type: string - enum: [created_at, "-created_at", last_used_at, "-last_used_at", expires_at, "-expires_at"] - - name: user_id - in: query - schema: { type: string, format: uuid } - description: Фильтр по владельцу токена. - - name: name - in: query - schema: { type: string, maxLength: 100 } - description: Like-поиск по названию токена. - - name: token_prefix - in: query - schema: { type: string, maxLength: 16 } - description: 'Like-поиск по префиксу (например `hrb_abc12345`).' - - name: status_id - in: query - schema: { type: string } - description: | - Comma-separated `UserApiTokenStatus`: `1` — Активен, `2` — Отозван, - `3` — Истёк. Без параметра — все статусы. - responses: - 200: - description: Список - content: - application/json: - schema: - $ref: '#/components/schemas/UserApiTokenAdminList' - 403: - description: Запрос под Bearer, либо нет права `api-tokens-admin`. - - /admin/user-api-token/revoke: - post: - tags: [admin-user-api-token] - summary: Отозвать любой токен тенанта - description: | - Идемпотентно. Доступно только под session-авторизацией (Bearer → 403). - operationId: adminUserApiTokenRevoke - security: - - SessionAuth: [] - requestBody: - required: true - content: - application/json: - schema: - type: object - required: [id] - properties: - id: - type: string - format: uuid - responses: - 200: - description: Успех - content: - application/json: - schema: - $ref: '#/components/schemas/httpJsonResponse' - 400: - description: Параметр `id` не строка или не uuid. - 403: - description: Запрос под Bearer, либо нет права `api-tokens-admin`. - 404: - description: Токен не найден. - components: securitySchemes: SessionAuth: @@ -7562,16 +7277,6 @@ components: in: header name: X-Hrbox-Client-Id description: "Авторизация с использованием API-ключа. Требуемые заголовки: Content-Type, X-Hrbox-Client-Id, X-Hrbox-Client-Secret." - BearerAuth: - type: http - scheme: bearer - bearerFormat: PAT - description: | - Personal Access Token (постоянный API-токен пользователя). Заголовок: - `Authorization: Bearer hrb_<32 url-safe>`. Tenant авторезолвится по - `Host`, `x-hrbox-tenant-id` опционален. Работает только на `/api/v2/*`. - Токен наследует все права юзера, под которым выпущен (granular scopes - не поддерживаются). Подробности — в описании API. schemas: httpJsonResponse: type: object @@ -12379,8 +12084,6 @@ components: type: array items: $ref: '#/components/schemas/Wallet' - _links: - $ref: '#/components/schemas/_links' _meta: $ref: '#/components/schemas/_meta' @@ -12413,8 +12116,6 @@ components: type: array items: $ref: '#/components/schemas/WalletTransaction' - _links: - $ref: '#/components/schemas/_links' _meta: $ref: '#/components/schemas/_meta' @@ -12494,13 +12195,10 @@ components: 1 — NEW, 2 — QUEUED, 3 — STARTED, 4 — FINISHED, 5 — ERROR, 6 — FATAL arguments: type: array - description: | - Аргументы воркера. Для wallet-excel: `[WalletExcelProcessor::class, mappings]`. - Для excel-экспорта: `[ReportClass::class, params]`. - items: {} result: + type: object description: | - Результат. Для wallet-excel: + Результат. Для wallet-excel содержит: ``` { "summary": { "totalRows": 4, "validCount": 1, "invalidCount": 3 }, @@ -12508,32 +12206,9 @@ components: "invalidRows": [{ "row": 2, "errors": {...} }, ...] } ``` - Для незавершённой обработки или экспорта — пустой массив `[]`. - oneOf: - - type: object - - type: array - items: {} created_at: { type: string } started_at: { type: string, nullable: true } finished_at: { type: string, nullable: true } - file: - type: object - nullable: true - description: | - Метаданные файла-источника. Возвращается всегда (не нужно `?expand=`). - Содержит `id, name, ext, fid, url, file_type, mime_type, size, - file_status_id, user_id, created_at` и др. - created: - type: string - description: 'Локализованная `created_at` (например `04.05.2026 at 13:56`).' - started: - type: string - nullable: true - description: Локализованная `started_at`. - finished: - type: string - nullable: true - description: Локализованная `finished_at`. FileProcessingList: type: object @@ -12542,134 +12217,6 @@ components: type: array items: $ref: '#/components/schemas/FileProcessing' - _links: - $ref: '#/components/schemas/_links' - _meta: - $ref: '#/components/schemas/_meta' - - UserApiTokenStatus: - type: integer - description: | - Статус личного API-токена (вычисляется по `revoked_at` / `expires_at`): - * `1` — Активен - * `2` — Отозван - * `3` — Истёк - enum: [1, 2, 3] - example: 1 - - UserApiToken: - type: object - description: | - Личный API-токен (PAT). Plain-секрет в этой схеме отсутствует — он - возвращается только в ответе на создание (см. `UserApiTokenCreated`). - properties: - id: { type: string, format: uuid } - user_id: { type: string, format: uuid } - name: - type: string - maxLength: 100 - description: Человекочитаемое название от юзера (HTML-теги вырезаются на бэке). - token_prefix: - type: string - description: | - Первые 12 символов токена с приставкой `hrb_`. Безопасно для отображения - и поиска (например `hrb_abc12345`). - example: "hrb_abc12345" - created_at: { type: string, format: date-time } - expires_at: - type: string - format: date-time - nullable: true - description: Если null — без срока. Срок включает указанный день целиком (до 23:59:59). - last_used_at: - type: string - format: date-time - nullable: true - description: Обновляется при использовании, не чаще раза в минуту. - revoked_at: - type: string - format: date-time - nullable: true - description: Заполняется при revoke; если null — токен не отозван. - - UserApiTokenList: - type: object - properties: - data: - type: array - items: - $ref: '#/components/schemas/UserApiToken' - _links: - $ref: '#/components/schemas/_links' - _meta: - $ref: '#/components/schemas/_meta' - - UserApiTokenCreated: - description: | - Расширение `UserApiToken` дополнительным полем `plain` — это - единственный момент, когда секрет возвращается клиенту. - allOf: - - $ref: '#/components/schemas/UserApiToken' - - type: object - required: [plain] - properties: - plain: - type: string - description: | - Полный plain-токен. Формат `hrb_<32 url-safe>`. **Сохраните - немедленно — повторно его получить невозможно.** - example: "hrb_aBcD3fGhIjKlMnOpQrStUvWxYz012345" - - UserApiTokenCreateForm: - type: object - required: [name] - properties: - name: - type: string - maxLength: 100 - description: Название токена. Сохраняется после HTML-purify. - example: "Интеграция web-zaim — wallet" - expires_at: - type: string - format: date - nullable: true - description: | - Дата истечения `yyyy-MM-dd`. Не может быть в прошлом (валидируется - по началу текущего дня). На бэке к ней приклеивается время - `23:59:59`, токен работает весь указанный день включительно. - Если опущено — токен бессрочный. - example: "2026-12-31" - - UserApiTokenAdmin: - description: | - Запись токена в админском списке: к базовым полям добавляются вложенные - `user` и `updatedByUser` (последний — кто последним менял запись; - для авто-revoke при блокировке — система). - allOf: - - $ref: '#/components/schemas/UserApiToken' - - type: object - properties: - user: - type: object - properties: - id: { type: string, format: uuid } - name: { type: string } - updatedByUser: - type: object - nullable: true - properties: - id: { type: string, format: uuid } - name: { type: string } - - UserApiTokenAdminList: - type: object - properties: - data: - type: array - items: - $ref: '#/components/schemas/UserApiTokenAdmin' - _links: - $ref: '#/components/schemas/_links' _meta: $ref: '#/components/schemas/_meta' @@ -12858,5 +12405,4 @@ components: security: - SessionAuth: [ ] - - ApiKeyAuth: [ ] - - BearerAuth: [ ] \ No newline at end of file + - ApiKeyAuth: [ ] \ No newline at end of file