[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"docs-keys-auth\u002Foauth":3,"docs-tabs-keys-auth\u002Foauth":6},{"content":4,"lastmod":5},"# Авторизация пользователей приложения\n\nПорядок OAuth-авторизации для приложений, работающих от лица разных пользователей портала. Пользователь входит через Битрикс24, приложение получает токен сессии и дальше обращается к API от его имени. AI-агент, которому передали ключ авторизации, проходит весь этот поток самостоятельно — по шагам ниже.\n\n**Скоуп:** не требуется | **Базовый URL:** `https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1` | **Авторизация:** `X-Api-Key: YOUR_APP_KEY`\n\n## Когда нужна авторизация пользователя\n\nКлюч авторизации `vibe_app_` работает от лица конкретного пользователя, установившего приложение. Чтобы платформа знала, от чьего имени обращаться к Битрикс24, к запросу прикладывается токен сессии в заголовке `Authorization: Bearer`. Токен выдаётся в конце этого потока.\n\nЛичный ключ `vibe_api_` работает от лица своего владельца и токен сессии не использует. Для фоновых сценариев без пользователя у экрана берите его, а не ключ авторизации — [Передача ключа](\u002Fdocs\u002Fkeys-auth#передача-ключа).\n\nВсе эндпоинты `\u002Fv1\u002Foauth\u002F*` отвечают по одному заголовку `X-Api-Key` с ключом авторизации, без `Authorization: Bearer`.\n\n## Шаг 1. Отправьте пользователя на авторизацию\n\nСгенерируйте `state` — криптослучайную строку 16–512 символов. Это защита от подделки межсайтового запроса по RFC 6749 §10.12: значение генерирует клиент, а на возврате сверяет, что пришло то же самое. Сервер сгенерировать `state` за вас не может.\n\nСоберите ссылку на `GET \u002Fv1\u002Foauth\u002Fauthorize` и перенаправьте на неё браузер пользователя. Это переход верхнего уровня, а не фоновый запрос — страница согласия Битрикс24 отдаёт заголовок `X-Frame-Options` и внутри `iframe` не открывается.\n\n```javascript\nconst state = crypto.randomUUID()\n\u002F\u002F Сохраните state в сессии пользователя, чтобы сверить его на возврате\nconst url = new URL('https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Foauth\u002Fauthorize')\nurl.searchParams.set('app_key', 'YOUR_APP_KEY')\nurl.searchParams.set('state', state)\nurl.searchParams.set('redirect_uri', 'https:\u002F\u002Fmyapp.example.com\u002Fcallback')\nwindow.location.href = url.toString()\n```\n\nПлатформа проверит `app_key` и `redirect_uri` и перенаправит пользователя на страницу авторизации Битрикс24. После авторизации Битрикс24 вернёт пользователя на зарегистрированный обработчик приложения, а платформа — на ваш `redirect_uri`.\n\n## Шаг 2. Примите возврат на `redirect_uri`\n\nПосле авторизации платформа перенаправляет браузер на ваш `redirect_uri` с одноразовым кодом и вашим `state`:\n\n```\nhttps:\u002F\u002Fmyapp.example.com\u002Fcallback?code=VIBE_AUTH_CODE&state=YOUR_STATE\n```\n\nСверьте `state` с тем, что сохранили на шаге 1. Если значения не совпадают, прервите авторизацию. Разбор ошибок в этом адресе — [Что приходит на redirect_uri](#что-приходит-на-redirect_uri).\n\n## Шаг 3. Обменяйте код на токен сессии\n\nС сервера приложения обменяйте `code` на токен сессии. `redirect_uri` в теле **точно** равен тому, что был на шаге 1.\n\n### cURL\n\n```bash\ncurl -X POST https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Foauth\u002Ftoken \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\n    \"app_key\": \"YOUR_APP_KEY\",\n    \"code\": \"VIBE_AUTH_CODE\",\n    \"redirect_uri\": \"https:\u002F\u002Fmyapp.example.com\u002Fcallback\"\n  }'\n```\n\n### JavaScript\n\n```javascript\nconst res = await fetch('https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Foauth\u002Ftoken', {\n  method: 'POST',\n  headers: { 'Content-Type': 'application\u002Fjson' },\n  body: JSON.stringify({\n    app_key: 'YOUR_APP_KEY',\n    code: 'VIBE_AUTH_CODE',\n    redirect_uri: 'https:\u002F\u002Fmyapp.example.com\u002Fcallback',\n  }),\n})\nconst { access_token, user, expires_in } = await res.json()\n\u002F\u002F Сохраните access_token — он действует 24 часа\n```\n\n```json\n{\n  \"success\": true,\n  \"access_token\": \"vibe_session_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\",\n  \"user\": { \"id\": \"42\", \"name\": \"Иван Петров\", \"email\": \"user@example.com\" },\n  \"expires_in\": 86400\n}\n```\n\nКод одноразовый и действует 5 минут.\n\n## Шаг 4. Вызывайте API с токеном сессии\n\nКаждый запрос к API идёт с двумя заголовками — ключ авторизации в `X-Api-Key` и токен сессии в `Authorization: Bearer`:\n\n### cURL\n\n```bash\ncurl https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Fdeals \\\n  -H \"X-Api-Key: YOUR_APP_KEY\" \\\n  -H \"Authorization: Bearer USER_SESSION_TOKEN\"\n```\n\n### JavaScript\n\n```javascript\nconst res = await fetch('https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Fdeals', {\n  headers: {\n    'X-Api-Key': 'YOUR_APP_KEY',\n    'Authorization': 'Bearer USER_SESSION_TOKEN',\n  },\n})\nconst { data } = await res.json()\n```\n\nСессия наследует права приложения на портале. Без заголовка `Authorization: Bearer` эндпоинты, которым нужен пользовательский контекст, возвращают `401 TOKEN_MISSING`.\n\n## Что приходит на `redirect_uri`\n\nПлатформа возвращает пользователя на `redirect_uri` с результатом в параметрах запроса. Всегда приходит ваш `state` — сверяйте его первым.\n\n| Параметр | Когда приходит | Значение |\n|----------|----------------|----------|\n| `code` | Авторизация прошла | Одноразовый код для [обмена на токен](#шаг-3-обменяйте-код-на-токен-сессии). Действует 5 минут |\n| `state` | Всегда | Значение `state`, переданное на шаге 1 |\n| `error` | Авторизация не удалась | Причина отказа — одно из значений ниже |\n\nЗначения `error`:\n\n| `error` | Что произошло |\n|---------|---------------|\n| `token_exchange_failed` | Битрикс24 не выдал токены по коду авторизации |\n| `invalid_domain` | Домен портала не прошёл проверку |\n| `profile_fetch_failed` | Не удалось прочитать профиль пользователя на портале |\n\nЧасть отказов на приёме возврата приходит не в адресе, а JSON-ответом со статусом `400` или `500` — когда платформа ещё не знает `redirect_uri`, вернуть на него нельзя. Это `MISSING_PARAMS`, `INVALID_STATE` и `APP_CONFIG_ERROR` из таблицы [Ошибки](#ошибки).\n\n## Правило `redirect_uri`\n\n`redirect_uri` должен **точно** совпадать с одним из адресов, зарегистрированных у приложения — совпадают схема, хост, порт и путь. Добавить адрес возврата можно в карточке приложения в разделе [Ключи авторизации](\u002Fapps) — поле «Redirect URI (OAuth)».\n\nУ нового приложения по умолчанию зарегистрирован адрес `http:\u002F\u002Flocalhost` — без порта и с путём `\u002F`. Совпадение точное, поэтому `http:\u002F\u002Flocalhost:3000\u002Fcallback` под него не подходит. Чтобы возврат шёл на ваш адрес — `http:\u002F\u002Flocalhost:3000\u002Fcallback` или `https:\u002F\u002Fmyapp.example.com\u002Fcallback` — сначала добавьте его в карточке приложения. Иначе `GET \u002Fv1\u002Foauth\u002Fauthorize` вернёт `400 INVALID_REDIRECT_URI`.\n\nЕсли `redirect_uri` опущен, платформа использует встроенную страницу возврата — [Авторизация без своего redirect_uri](#авторизация-без-своего-redirect_uri).\n\n## Авторизация без своего `redirect_uri`\n\nКогда `redirect_uri` опущен, платформа возвращает пользователя на встроенную страницу `\u002Foauth\u002Fcomplete` и создаёт токен сессии на своей стороне. Приложение забирает результат опросом `GET \u002Fv1\u002Foauth\u002Fpoll` по тому же `state`.\n\n### cURL\n\n```bash\ncurl \"https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Foauth\u002Fpoll?app_key=YOUR_APP_KEY&state=YOUR_STATE\"\n```\n\n### JavaScript\n\n```javascript\nconst url = `https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Foauth\u002Fpoll?app_key=YOUR_APP_KEY&state=${state}`\nconst res = await fetch(url)\nconst result = await res.json()\nif (result.status === 'complete') {\n  \u002F\u002F result.access_token, result.user, result.expires_in\n}\n```\n\nПока пользователь не завершил вход, приходит статус `pending`:\n\n```json\n{ \"success\": true, \"status\": \"pending\" }\n```\n\nПосле входа тот же запрос отдаёт токен сессии. Результат одноразовый — следующий опрос по этому же `state` снова вернёт `pending`:\n\n```json\n{\n  \"success\": true,\n  \"status\": \"complete\",\n  \"access_token\": \"vibe_session_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\",\n  \"user\": { \"id\": \"42\", \"name\": \"Иван Петров\", \"email\": \"user@example.com\" },\n  \"expires_in\": 86400\n}\n```\n\nРезультат хранится 10 минут. Забирайте его сразу после возврата пользователя на страницу входа.\n\n## Токен сессии: срок и отзыв\n\nТокен сессии действует 24 часа и не обновляется — поле `expires_in` в ответе равно `86400`. Механизма продления нет. После истечения вызовы за пользователя возвращают `401 INVALID_SESSION` — это сигнал заново пройти авторизацию: `GET \u002Fv1\u002Foauth\u002Fauthorize` → `POST \u002Fv1\u002Foauth\u002Ftoken`.\n\nДосрочно отозвать токен — `POST \u002Fv1\u002Foauth\u002Frevoke` с токеном сессии в заголовке `Authorization: Bearer`. Отзыв удаляет сессию пользователя, дальнейшие вызовы с этим токеном отклоняются.\n\n### cURL\n\n```bash\ncurl -X POST https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Foauth\u002Frevoke \\\n  -H \"Authorization: Bearer USER_SESSION_TOKEN\"\n```\n\n### JavaScript\n\n```javascript\nconst res = await fetch('https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Foauth\u002Frevoke', {\n  method: 'POST',\n  headers: { 'Authorization': 'Bearer USER_SESSION_TOKEN' },\n})\nconst { revoked } = await res.json()\n```\n\n```json\n{ \"success\": true, \"revoked\": true }\n```\n\nПоле `revoked` равно `false`, если действующей сессии с таким токеном уже не было. Ответ приходит со статусом `200` в обоих случаях.\n\n## Приложение на своём сервере\n\nОтдельная вкладка для входа доступна не всегда — например, приложение открывается как размещение внутри Битрикс24, а страница согласия внутри `iframe` не открывается. Если приложение размещено на собственном сервере, а не за BlackHole, токен сессии текущего пользователя получают одним из двух способов — по тому, чей обработчик принимает размещение.\n\n**Приложение Вайбкод, `appUrl` — ваш сервер.** Размещение приходит на обработчик Вайбкод, и платформа перенаправляет браузер на `\u003CappUrl>\u002F?code=\u003Cодноразовый код>&placement=...&member_id=...`. Ваш сервер обменивает код на токен сессии тем же запросом [`POST \u002Fv1\u002Foauth\u002Ftoken`](#шаг-3-обменяйте-код-на-токен-сессии) с телом `{ app_key, code, redirect_uri }`, где `redirect_uri` точно равен настроенному `appUrl`. Токен сессии в браузер не попадает — в адресе только одноразовый код, бесполезный без `app_key`. Поле `appUrl` редактируется в карточке приложения в разделе [Ключи авторизации](\u002Fapps).\n\n**Собственное приложение Битрикс24 со своим обработчиком.** Размещение приходит напрямую на ваш сервер с токеном пользователя Битрикс24. Обменяйте его на токен сессии серверным запросом — `POST \u002Fv1\u002Foauth\u002Fplacement-session`.\n\n### cURL\n\n```bash\ncurl -X POST https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Foauth\u002Fplacement-session \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\n    \"app_key\": \"YOUR_APP_KEY\",\n    \"access_token\": \"BITRIX24_USER_TOKEN\",\n    \"member_id\": \"MEMBER_ID\",\n    \"domain\": \"mycompany.bitrix24.ru\"\n  }'\n```\n\n### JavaScript\n\n```javascript\nconst res = await fetch('https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Foauth\u002Fplacement-session', {\n  method: 'POST',\n  headers: { 'Content-Type': 'application\u002Fjson' },\n  body: JSON.stringify({\n    app_key: 'YOUR_APP_KEY',\n    access_token: 'BITRIX24_USER_TOKEN',\n    member_id: 'MEMBER_ID',\n    domain: 'mycompany.bitrix24.ru',\n  }),\n})\nconst { access_token, user, expires_in } = await res.json()\n```\n\n```json\n{\n  \"success\": true,\n  \"access_token\": \"vibe_session_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\",\n  \"user\": { \"id\": \"42\", \"name\": \"Иван Петров\", \"email\": \"user@example.com\" },\n  \"expires_in\": 86400\n}\n```\n\n`domain` должен совпадать с порталом приложения. Поля `refresh_token` и `expires_in` в теле необязательны и описывают токен пользователя Битрикс24: `expires_in` — сколько он действует, по умолчанию 3600 секунд. Без действующего `refresh_token` токен Битрикс24 автоматически не обновляется — после его истечения переоткройте размещение. Сам токен сессии, как и в основном потоке, действует 24 часа.\n\nПолный жизненный цикл встроенного приложения и примеры обработчика на Node, Python и Go — [Авторизация в приложении на BlackHole](\u002Fdocs\u002Finfra\u002Fapp-runtime).\n\n## Справочник эндпоинтов\n\n| Метод | Путь | Описание |\n|-------|------|----------|\n| GET | `\u002Fv1\u002Foauth\u002Fauthorize` | Начать авторизацию — редирект на страницу входа Битрикс24 |\n| GET | `\u002Fv1\u002Foauth\u002Fcallback` | Приём ответа Битрикс24. Вызывается Битрикс24, не приложением |\n| POST | `\u002Fv1\u002Foauth\u002Ftoken` | Обменять код на токен сессии |\n| GET | `\u002Fv1\u002Foauth\u002Fpoll` | Забрать результат авторизации без своего `redirect_uri` |\n| POST | `\u002Fv1\u002Foauth\u002Fplacement-session` | Токен сессии для приложения на своём сервере |\n| POST | `\u002Fv1\u002Foauth\u002Frevoke` | Отозвать токен сессии |\n\n## Ошибки\n\nКлюч авторизации проверяется на входе `GET \u002Fv1\u002Foauth\u002Fauthorize`, `POST \u002Fv1\u002Foauth\u002Ftoken` и `POST \u002Fv1\u002Foauth\u002Fplacement-session`:\n\n| HTTP | Код | Описание |\n|------|-----|----------|\n| 401 | `INVALID_APP_KEY` | `app_key` не найден или это не ключ авторизации |\n| 401 | `KEY_INACTIVE` | Ключ авторизации отозван |\n| 401 | `KEY_EXPIRED` | Срок действия ключа авторизации прошёл |\n| 403 | `OWNER_BLOCKED` | Владелец ключа заблокирован платформой |\n\n`GET \u002Fv1\u002Foauth\u002Fauthorize`:\n\n| HTTP | Код | Описание |\n|------|-----|----------|\n| 400 | `INVALID_REQUEST` | Нет обязательного `state` или он вне диапазона 16–512 символов |\n| 400 | `INVALID_REDIRECT_URI` | `redirect_uri` не зарегистрирован у приложения |\n| 500 | `NO_PORTAL` | Приложение не привязано к порталу |\n\n`GET \u002Fv1\u002Foauth\u002Fcallback` (вызывается Битрикс24):\n\n| HTTP | Код | Описание |\n|------|-----|----------|\n| 400 | `MISSING_PARAMS` | Битрикс24 вернулся без `code` или `state` |\n| 400 | `INVALID_STATE` | `state` не найден или истёк за 20 минут. В `error.details.reason` — `NOT_FOUND` или `EXPIRED` |\n| 500 | `APP_CONFIG_ERROR` | У приложения не заданы OAuth-учётные данные |\n\n`POST \u002Fv1\u002Foauth\u002Ftoken`:\n\n| HTTP | Код | Описание |\n|------|-----|----------|\n| 400 | `INVALID_REQUEST` | В теле нет `code` или `redirect_uri` |\n| 400 | `INVALID_CODE` | Код не найден или принадлежит другому приложению |\n| 400 | `CODE_EXPIRED` | Срок действия кода прошёл — 5 минут |\n| 400 | `CODE_ALREADY_USED` | Код уже обменян на токен |\n| 400 | `REDIRECT_URI_MISMATCH` | `redirect_uri` не совпадает с переданным в `GET \u002Fv1\u002Foauth\u002Fauthorize` |\n| 500 | `TOKEN_NOT_FOUND` | Токен пользователя не найден |\n\n`GET \u002Fv1\u002Foauth\u002Fpoll`:\n\n| HTTP | Код | Описание |\n|------|-----|----------|\n| 400 | `INVALID_REQUEST` | `state` короче 16 символов или нет `app_key` |\n| 401 | `INVALID_APP_KEY` | `app_key` не найден или это не ключ авторизации |\n\n`POST \u002Fv1\u002Foauth\u002Fplacement-session`:\n\n| HTTP | Код | Описание |\n|------|-----|----------|\n| 400 | `INVALID_REQUEST` | В теле нет `access_token`, `member_id` или `domain` |\n| 400 | `DOMAIN_MISMATCH` | `domain` не совпадает с порталом приложения |\n| 401 | `USER_AUTH_REQUIRED` | Токен пользователя Битрикс24 не подтвердил авторизацию на портале |\n| 500 | `NO_PORTAL` | Приложение не привязано к порталу |\n\n`POST \u002Fv1\u002Foauth\u002Frevoke`:\n\n| HTTP | Код | Описание |\n|------|-----|----------|\n| 400 | `MISSING_TOKEN` | Не передан `Authorization: Bearer` с токеном сессии |\n\nПолный список общих ошибок API — [Ошибки](\u002Fdocs\u002Ferrors).\n\n## Пример ответа при ошибке\n\n400 — не передан обязательный `state`:\n\n```json\n{\n  \"success\": false,\n  \"error\": {\n    \"code\": \"INVALID_REQUEST\",\n    \"message\": \"state: Required\"\n  }\n}\n```\n\n## Смотрите также\n\n- [Создание и использование ключа](\u002Fdocs\u002Fkeys-auth)\n- [Самоописание ключа](\u002Fdocs\u002Fkeys-auth\u002Fme)\n- [Авторизация в приложении на BlackHole](\u002Fdocs\u002Finfra\u002Fapp-runtime)\n- [Встраивание приложения в портал](\u002Fdocs\u002Fkeys-auth#встраивание-приложения-в-портал)\n- [Ошибки](\u002Fdocs\u002Ferrors)\n","2026-07-23",{}]