From 161dc83b214844198d5c71ade4f793dc97e5ce68 Mon Sep 17 00:00:00 2001 From: Denis Date: Fri, 22 May 2026 15:17:47 +0300 Subject: [PATCH 1/2] =?UTF-8?q?H-3657:=20PAT=20how-to=20=E2=86=92=20=D0=BE?= =?UTF-8?q?=D0=BF=D0=B8=D1=81=D0=B0=D0=BD=D0=B8=D0=B5=20=D0=BC=D0=B5=D1=82?= =?UTF-8?q?=D0=BE=D0=B4=D0=B0=20create,=20=D1=82=D1=8D=D0=B3=D0=B8/info=20?= =?UTF-8?q?=E2=86=92=20=D0=BA=D0=BE=D1=80=D0=BE=D1=82=D0=BA=D0=B8=D0=B5=20?= =?UTF-8?q?EN?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - info.description: убрал большой блок «Авторизация по личному API-токену» (он висел на стартовой странице Swagger UI). Вместо него — одна английская строка-указатель на user-api-token methods, в стиле остального вступления. - BearerAuth securityScheme: однострочное EN-описание. - Теги admin-wallet, admin-wallet-transaction, file-processing, user-api-token, admin-user-api-token: переведены в формат «Methods for ...» (как workflow, wallet, shop и т.д.) — короткая английская строка на тег. - POST /user-api-token/create description: подробный how-to (создание, Bearer-header, tenant-резолв, отсутствие scopes, lifecycle, isValidForDisplay-caveat, запрет на управление под Bearer) — теперь лежит здесь, на английском, и сворачивается в UI вместе с эндпоинтом. Co-Authored-By: Claude Opus 4.7 (1M context) --- v2/swagger.yaml | 178 ++++++++++++++++++++---------------------------- 1 file changed, 74 insertions(+), 104 deletions(-) diff --git a/v2/swagger.yaml b/v2/swagger.yaml index c8035c4..fcff3e6 100644 --- a/v2/swagger.yaml +++ b/v2/swagger.yaml @@ -28,85 +28,7 @@ info: {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-сессией. + For server-to-server integrations /api/v2/* endpoints also accept a Personal Access Token via "Authorization: Bearer hrb_". See user-api-token methods for issuing and lifecycle details. contact: email: yuriy@hrbox.io @@ -142,21 +64,15 @@ tags: - name: kedo description: Методы для работы с КЭДО. - name: admin-wallet - description: Админский API кошельков сотрудников (read-only). Permission `wallets-transactions`, требует `enableWallet=true` у тенанта. + description: Methods for admin access to employee wallets (read-only). Requires "wallets-transactions" permission and enableWallet tenant flag. - name: admin-wallet-transaction - description: Админский API транзакций кошелька — проведение начислений/списаний (form/excel) и просмотр. + description: Methods for admin wallet transactions — manual and excel-based credit/debit. - name: file-processing - description: Статусы асинхронных обработок файлов (excel-импорт/экспорт, архивы). Видны только записи текущего пользователя. + description: Methods for polling async file processing (excel import/export, archives). Scoped to current user's files. - name: user-api-token - description: | - Личные API-токены (Personal Access Tokens) для серверных интеграций. - Юзер управляет только своими токенами. Permission `api-tokens-manage`. - Management-эндпоинты доступны **только под обычной session-авторизацией** - (Bearer запрещён). См. секцию «Авторизация по личному API-токену» выше. + description: Methods for managing personal API tokens (PATs) for server-to-server access. Requires "api-tokens-manage" permission. - name: admin-user-api-token - description: | - Админский обзор и отзыв любых PAT тенанта. Permission `api-tokens-admin`. - Plain-секрет недоступен — виден только `token_prefix`. + description: Methods for admin oversight of personal API tokens. Requires "api-tokens-admin" permission. paths: /mobile/bind/{id}/{token}: @@ -7392,17 +7308,76 @@ paths: /user-api-token/create: post: tags: [user-api-token] - summary: Создать новый API-токен (plain возвращается один раз) + summary: Create a new personal API token (plain secret is returned once) description: | - Создаёт PAT для текущего юзера. **Plain-секрет (`data.plain`) - возвращается только в этом ответе и больше нигде не доступен** — - сохраните его сразу. + Creates a PAT for the current user. **The plain secret (`data.plain`) + is returned only in this response and cannot be recovered later** — + store it immediately. - `expires_at` опционален; если задан, должен быть не в прошлом - (валидируется по началу текущего дня). Токен работает весь - указанный день включительно (23:59:59). + ### How to use the token - Доступно только под session-авторизацией (запрос под Bearer → 403). + Sign every request with the `Authorization` header: + + ``` + Authorization: Bearer hrb_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + ``` + + Format: `hrb_` + 32 url-safe chars (36 chars total). The DB stores only + an HMAC-SHA-256 hash and the visible 12-char prefix (`hrb_xxxxxxxx`). + + Bearer is accepted on **`/api/v2/*` only**. It is ignored on + `/api/v1/*`, `/api/v3/*`, `/admin/*` and regular web pages. + + Tenant is auto-resolved from the request `Host`, so `x-hrbox-tenant-id` + and `x-hrbox-tenant-domain` are **optional**. If provided, they are + strictly validated (invalid tenant → 400). `x-hrbox-session-id` / + `x-hrbox-session-code` are **not needed** with Bearer. + + ### Scopes and permissions + + ⚠️ **There are no granular scopes.** The token inherits **all + permissions** of the user it was issued for. For integrations, create + a dedicated system user and grant only the required permissions + (e.g. `wallets-transactions` for `/api/v2/admin/wallet*`). Do not use + your personal account. + + ### Lifecycle and revocation + + - The user revokes their token via `POST /api/v2/user-api-token/revoke` + or from the UI. + - An admin with `api-tokens-admin` can list/revoke any token in the + tenant via `/api/v2/admin/user-api-token*`. The plain secret is + **never** visible to admins, only the prefix. + - When a user is blocked (`reg_status_id = BLOCKED`), all their tokens + are auto-revoked. They are **not** restored on unblock — new ones + must be issued. + - If `expires_at` is set, the token stops working after that date + (status `EXPIRED`). `expires_at` is optional and must not be in the + past (validated against the start of the current day); the token + works through the full given day until 23:59:59. + + ### When a valid token still returns 401 + + `User::findIdentityByAccessToken` also runs `User::isValidForDisplay()`, + so a live, non-revoked, non-expired token returns `401 Login Required` + if the owner has: + + - `is_hidden = true` (hidden by an admin), or + - `reg_status_id` is not in `RegStatus::validForDisplay()` + (e.g. `INVITED`, `BLOCKED`, etc.). + + Make sure the integration user is `is_hidden=false` and in an active + registration status. + + ### Token management endpoints reject Bearer + + Management endpoints (`/user-api-token*`, `/admin/user-api-token*`) + return `403` if called with a Bearer token — tokens cannot be issued + or revoked from a token. Use a regular web session for management. + + --- + + This endpoint itself is also session-only (Bearer → 403). operationId: userApiTokenCreate security: - SessionAuth: [] @@ -7566,12 +7541,7 @@ components: 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. + description: 'Personal Access Token. Header: "Authorization: Bearer hrb_". See user-api-token methods for details.' schemas: httpJsonResponse: type: object -- 2.54.0 From 92d9c73b0c16c6da1c051f08668ef2d337370019 Mon Sep 17 00:00:00 2001 From: Denis Date: Fri, 22 May 2026 15:39:40 +0300 Subject: [PATCH 2/2] =?UTF-8?q?H-3657:=20description/summary=20=D0=BC?= =?UTF-8?q?=D0=B5=D1=82=D0=BE=D0=B4=D0=B0=20create=20=E2=80=94=20=D0=BE?= =?UTF-8?q?=D0=B1=D1=80=D0=B0=D1=82=D0=BD=D0=BE=20=D0=BD=D0=B0=20=D1=80?= =?UTF-8?q?=D1=83=D1=81=D1=81=D0=BA=D0=B8=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Соглашение: info.description и теги — короткое EN (как workflow, wallet и др.), а внутри самого метода (summary + description) — русский, потому что туда смотрит уже сам интегратор и важно дать максимально понятный how-to. Возвращаю русский для POST /user-api-token/create. Co-Authored-By: Claude Opus 4.7 (1M context) --- v2/swagger.yaml | 98 +++++++++++++++++++++++++------------------------ 1 file changed, 51 insertions(+), 47 deletions(-) diff --git a/v2/swagger.yaml b/v2/swagger.yaml index fcff3e6..c29476c 100644 --- a/v2/swagger.yaml +++ b/v2/swagger.yaml @@ -7308,76 +7308,80 @@ paths: /user-api-token/create: post: tags: [user-api-token] - summary: Create a new personal API token (plain secret is returned once) + summary: Создать новый API-токен (plain-секрет возвращается один раз) description: | - Creates a PAT for the current user. **The plain secret (`data.plain`) - is returned only in this response and cannot be recovered later** — - store it immediately. + Создаёт PAT для текущего юзера. **Plain-секрет (`data.plain`) + возвращается только в этом ответе и больше нигде не доступен** — + сохраните его сразу. - ### How to use the token + ### Как пользоваться токеном - Sign every request with the `Authorization` header: + Подписывайте каждый запрос заголовком `Authorization`: ``` Authorization: Bearer hrb_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ``` - Format: `hrb_` + 32 url-safe chars (36 chars total). The DB stores only - an HMAC-SHA-256 hash and the visible 12-char prefix (`hrb_xxxxxxxx`). + Формат: `hrb_` + 32 url-safe символа (всего 36). В БД хранится + только HMAC-SHA-256 хеш и видимый 12-символьный префикс + (`hrb_xxxxxxxx`). - Bearer is accepted on **`/api/v2/*` only**. It is ignored on - `/api/v1/*`, `/api/v3/*`, `/admin/*` and regular web pages. + Bearer принимается **только на `/api/v2/*`**. На `/api/v1/*`, + `/api/v3/*`, `/admin/*` и обычных веб-страницах игнорируется. - Tenant is auto-resolved from the request `Host`, so `x-hrbox-tenant-id` - and `x-hrbox-tenant-domain` are **optional**. If provided, they are - strictly validated (invalid tenant → 400). `x-hrbox-session-id` / - `x-hrbox-session-code` are **not needed** with Bearer. + Tenant авторезолвится по `Host`-заголовку, поэтому + `x-hrbox-tenant-id` и `x-hrbox-tenant-domain` **необязательны**. + Если передаёте — будут строго провалидированы (невалидный + идентификатор → 400). `x-hrbox-session-id` / `x-hrbox-session-code` + при Bearer-аутентификации **не нужны**. - ### Scopes and permissions + ### Права и scopes - ⚠️ **There are no granular scopes.** The token inherits **all - permissions** of the user it was issued for. For integrations, create - a dedicated system user and grant only the required permissions - (e.g. `wallets-transactions` for `/api/v2/admin/wallet*`). Do not use - your personal account. + ⚠️ **Гранулярных scopes у токена нет.** Токен наследует **все + права** того юзера, под которым выпущен. Для интеграции заведите + отдельного системного пользователя и выдайте ему ровно те права, + которые требуются (например, `wallets-transactions` для + `/api/v2/admin/wallet*`). Не используйте свой личный аккаунт. - ### Lifecycle and revocation + ### Отзыв и жизненный цикл - - The user revokes their token via `POST /api/v2/user-api-token/revoke` - or from the UI. - - An admin with `api-tokens-admin` can list/revoke any token in the - tenant via `/api/v2/admin/user-api-token*`. The plain secret is - **never** visible to admins, only the prefix. - - When a user is blocked (`reg_status_id = BLOCKED`), all their tokens - are auto-revoked. They are **not** restored on unblock — new ones - must be issued. - - If `expires_at` is set, the token stops working after that date - (status `EXPIRED`). `expires_at` is optional and must not be in the - past (validated against the start of the current day); the token - works through the full given day until 23:59:59. + - Юзер отзывает свой токен через `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`). `expires_at` опционален, не может быть + в прошлом (валидируется по началу текущего дня); токен работает + весь указанный день включительно до 23:59:59. - ### When a valid token still returns 401 + ### Когда валидный токен всё равно даёт 401 - `User::findIdentityByAccessToken` also runs `User::isValidForDisplay()`, - so a live, non-revoked, non-expired token returns `401 Login Required` - if the owner has: + `User::findIdentityByAccessToken` дополнительно вызывает + `User::isValidForDisplay()`, поэтому живой, не отозванный и не + истёкший токен отдаёт `401 Login Required`, если у владельца: - - `is_hidden = true` (hidden by an admin), or - - `reg_status_id` is not in `RegStatus::validForDisplay()` - (e.g. `INVITED`, `BLOCKED`, etc.). + - `is_hidden = true` (юзер скрыт администратором), либо + - `reg_status_id` не входит в `RegStatus::validForDisplay()` + (например `BLOCKED`). - Make sure the integration user is `is_hidden=false` and in an active - registration status. + Для системного юзера-интегратора убедитесь, что он `is_hidden=false` + и в активном reg-статусе. - ### Token management endpoints reject Bearer + ### Управление токенами под Bearer запрещено - Management endpoints (`/user-api-token*`, `/admin/user-api-token*`) - return `403` if called with a Bearer token — tokens cannot be issued - or revoked from a token. Use a regular web session for management. + Management-эндпоинты (`/user-api-token*`, `/admin/user-api-token*`) + отдают `403`, если запрос аутентифицирован Bearer-токеном — нельзя + выпускать или отзывать токены от имени токена. Управляйте только + под обычной web-сессией. --- - This endpoint itself is also session-only (Bearer → 403). + Сам этот эндпоинт тоже доступен только под session-авторизацией + (Bearer → 403). operationId: userApiTokenCreate security: - SessionAuth: [] -- 2.54.0