Bitrix24
Цикл OAuth
Authorize, обмен кода на токены, обновление по refresh_token и поля, которые портал передаёт фрейму приложения.
На этой странице · 8
Сервер авторизации APIStend отвечает тем же конвертом, что боевой oauth.bitrix.info:
те же имена полей, те же коды ошибок, те же сроки жизни. Полный цикл проверяется
одним curl, не поднимая приложение.
Два способа получить токены
Приложению с интерфейсом токены приходят сами: портал кладёт их в тело POST-запроса
при открытии фрейма — это «упрощённая авторизация», и большинству приложений
её достаточно. Полный цикл authorize → token нужен там, где приложение
авторизуется само: серверная часть без фрейма, CRest, свой обмен кода.
Authorize
curl -si "http://localhost:8080/oauth/authorize/?client_id=local.aabbccddeeff11.12345678&state=xyz"
HTTP/1.1 302 Found
location: http://localhost:3210/handler?code=77im8soiuda2ru9des1y3pf3yko96ivr&state=xyz
&domain=localhost%3A8080&member_id=16ae2b1b95d1092ee78bc6d344af2224
&scope=crm%2Cplacement%2Cuser&server_domain=localhost%3A8080
(в реальном ответе location — одна строка).
Параметры authorize
Боевой портал redirect_uri в запросе не принимает и берёт адрес из карточки
приложения. Здесь он принимается как послабление: у локального приложения такого
поля в форме нет, и проверить полный цикл иначе было бы негде.
Экрана входа и согласия нет: код выдаётся сразу. Кем открыто приложение, выбирается в шапке демонстрационного портала, а не в OAuth.
Обмен кода на токены
curl -s -X POST http://localhost:8080/oauth/token/ \
-d "grant_type=authorization_code" \
-d "client_id=local.aabbccddeeff11.12345678" \
-d "client_secret=$CLIENT_SECRET" \
-d "code=$CODE"
{
"access_token": "sawe6p7tj4yavjd6ws65ia098gpjpc8b",
"refresh_token": "nfr1a7wvqzcp6c7z9khovj8yvdkweipb",
"expires_in": 3600,
"expires": 1788952526,
"scope": "crm,placement,user",
"domain": "localhost:8080",
"server_endpoint": "http://localhost:8080/oauth/rest/",
"client_endpoint": "http://localhost:8080/rest/",
"member_id": "16ae2b1b95d1092ee78bc6d344af2224",
"status": "L",
"user_id": 1
}
Имена полей не переименованы ни в одном месте: их разбирает клиентский код
разработчика. Метод принимается и как GET, и как POST; ответ отдаётся
с Access-Control-Allow-Origin: *.
domain— хост портала, без схемы: приложение склеивает адрес само, подставляя схему изPROTOCOL.client_endpoint— база REST, куда идут вызовы методов.server_endpoint— база сервера авторизации.member_id— постоянный идентификатор портала. Считается от песочницы и не меняется от смены домена, как и в бою.status— вид приложения; у локального всегдаL.
Обновление
curl -s -X POST http://localhost:8080/oauth/token/ \
-d "grant_type=refresh_token" \
-d "client_id=$CLIENT_ID" -d "client_secret=$CLIENT_SECRET" \
-d "refresh_token=$REFRESH_TOKEN"
Ответ — тот же конверт с новой парой. Прежняя пара гасится: старый refresh_token
на второй обмен отвечает invalid_grant, а старый access_token — expired_token.
Именно expired_token, а не NO_AUTH_FOUND: у приложения могла остаться копия
прежнего токена (например, во фрейме, пока серверная часть уже обновилась), и она
обязана узнать «пора обновиться», а не «такого токена не существует».
Обновлять по расписанию нельзя
Документация Bitrix24 предписывает дождаться ошибки expired_token и только после неё
идти за новой парой. Обновление раз в час или перед каждым вызовом там прямо запрещено.
Сроки жизни
Тридцати секунд достаточно, чтобы обменять код сразу, и недостаточно, чтобы «пока
сохраню, потом обменяю». Код одноразовый: повторный обмен — invalid_grant.
Срок токенов настраивается в карточке приложения — это единственное место, где APIStend
сознательно расходится с боевым порталом. Причина в том, что проверять надо поведение
приложения после отказа, а в бою срок всегда час и ускорить его нечем. Настроенный срок
уходит приложению честно: в expires_in ответа сервера авторизации и в AUTH_EXPIRES
при открытии фрейма.
Кнопка «Состарить сейчас» в карточке состаривает все действующие пары немедленно.
Токены именно состариваются, а не отзываются: приложение обязано получить
expired_token и пойти обновляться.
Перед переносом верните 3600
Короткий срок легко принять за рабочее поведение: в бою то же самое случится только через час — обычно уже у клиента.
Что приходит во фрейм
Приложение с интерфейсом открывается POST-запросом, и данные разделены между адресом и телом так же, как в бою: в query-строке токенов нет.
Каждое открытие фрейма выпускает новую пару токенов, а прежняя продолжает действовать до своего срока — как и в бою: копия приложения в соседней вкладке не должна внезапно терять доступ.
PLACEMENT_OPTIONS разбирается на стороне приложения. Кроме ключей самой точки
встраивания портал кладёт туда URI — путь страницы, с которой открыт виджет:
для вкладки в карточке сделки это /crm/deal/details/<ID>/.
Токены в событиях
Событие, адресованное приложению, несёт в auth[] действующий access_token —
обработчику есть чем ответить, не поднимая своё хранилище. Тело —
application/x-www-form-urlencoded с PHP-скобками: event, event_handler_id,
data[...], ts, auth[domain], auth[client_endpoint], auth[server_endpoint],
auth[member_id], auth[application_token], auth[status], auth[access_token],
auth[expires_in], auth[scope].
Два исключения:
- в
ONAPPINSTALLдополнительно приходитauth[refresh_token]— это единственный момент, когда приложению негде взять долгоживущую авторизацию иначе; - в
ONAPPUNINSTALLнет ниaccess_token, ниexpires_in, ниscope: права уже сняты.
Ошибки
Сервер авторизации отвечает на ошибку вместо пары токенов, всегда со статусом 400:
Ответы /oauth/token
Ошибки контекста приложения приходят в конверте REST:
Ответы /rest/…