Внешний контрагент часто описывает интеграцию так: OAuth2, в теле POST - client_id и client_secret, token URL вроде /security/oauth/token, дальше вызовы API с access_token. HTTP-сервис заказов на 1С:8.3 уже есть, но client credentials платформа не подменит сеансом пользователя. Нужны отдельный endpoint выдачи и приём Bearer через настройки публикации, а не проверка строки в каждом методе.
1. Задача партнёра и место 1С в цепочке
Контракт сверяем с OpenAPI (файлы вроде orders.json удобно смотреть в swagger-editor). Два класса запросов: POST на token URL, тело application/x-www-form-urlencoded, поля client_id и client_secret; и бизнес-методы с access token в заголовке Authorization. Партнёр не передаёт логин и пароль пользователя 1С и не шлёт Basic на endpoint выдачи.
Стандартный authorization server платформы с refresh token и полным набором grant types сюда не подставляется. Реализуем client credentials у себя: лёгкая публикация проверяет пару клиента и выдаёт подписанный access token объектом ТокенДоступа; рабочая публикация принимает его через accessTokenAuthentication в default.vrd. Grant type, scope и коды ошибок сверяем со swagger контрагента; полную сертифицируемую совместимость с OAuth 2.0 без оговорок не обещаем.
Архитектурно разделяем issuer и resource API. Эмитент, получатель и ключ подписи должны совпасть при выдаче и при проверке. Имя в массиве Получатели - то же, что имя HTTP-сервиса в vrd рабочей базы, а не произвольная строка из переписки.
Token endpoint и API часто разносят по двум информационным базам: микроконфигурация только для POST token и основная с сервисом заказов. Так проще ограничить права служебного пользователя в строке ib= на token URL и не смешивать журнал выдачи с бизнес-логикой.

Каталоги публикаций token и API на rphost
У token и у API свои каталоги на веб-сервере и свои файлы vrd, даже если rphost один.
2. Pубликация выдачи токена: POST и проверка client_id/client_secret
Контракт обработчика
HTTP-сервис с корневым URL по спецификации партнёра (часто сегмент /security/oauth/token; path уточняйте по действующему swagger). Метод POST читает тело, разбирает form-urlencoded, ищет клиента в справочнике или регистре с ограничением прав на чтение секрета.
Наивный парсер «режем строку по амперсанду и знаку равенства» даёт ложные ошибки аутентификации: в значениях процентное кодирование (например символ «@»), ключ без равенства, пустой client_id после декодирования. Значения декодируем, отсутствие равенства обрабатываем отдельно, о пропущенных полях отвечаем 400 с описанием, о неверной паре - после полной проверки тела.
Функция OAuthTokenPOST(Запрос)
Ошибки = Новый Массив;
Параметры = РазобратьFormUrlEncoded(Запрос.ПолучитьТелоКакСтроку());
client_id = Неопределено;
client_secret = Неопределено;
Параметры.Свойство("client_id", client_id);
Параметры.Свойство("client_secret", client_secret);
Если client_id = Неопределено Или ПустаяСтрока(client_id) Тогда
ДобавитьОшибкуJSON(Ошибки, "В теле application/x-www-form-urlencoded нужен client_id.");
КонецЕсли;
Если client_secret = Неопределено Или ПустаяСтрока(client_secret) Тогда
ДобавитьОшибкуJSON(Ошибки, "В теле application/x-www-form-urlencoded нужен client_secret.");
КонецЕсли;
Если Ошибки.Количество() = 0
И Не УчетныеДанныеКлиентаВерны(client_id, client_secret) Тогда
ДобавитьОшибкуJSON(Ошибки, "Ошибка аутентификации, проверьте client_id и client_secret.");
КонецЕсли;
Если Ошибки.Количество() > 0 Тогда
Возврат ОтветJSON(400, Новый Структура("errors", Ошибки));
КонецЕсли;
access_token = СформироватьAccessToken(client_id);
Возврат ОтветJSON(200, Новый Структура("access_token", access_token));
КонецФункции
Вспомогательные функции ОтветJSON, заголовки no-cache и единый формат массива ошибок с полем description выравнивают token endpoint с остальными JSON-методами публикации.
Если swagger требует в теле grant_type со значением client_credentials, проверку добавляем после разбора: отсутствие поля трактуем по контракту (400 или значение по умолчанию, если партнёр это допускает). Scope в payload токена платформа 8.3 в базовом сценарии ролями не подменяет: права задаёт сопоставленный пользователь ИБ и профиль доступа HTTP-сервиса.
default.vrd без Basic от партнёра
На token URL партнёр Basic не шлёт, поэтому в vrd публикации аутентификации прописываем служебного пользователя и пароль для входа rphost в ИБ, например фрагмент строки подключения:
ib="File="D:/1C/Base/HTTP_Auth";Usr="svc_auth";Pwd="***""
Это технический сеанс платформы, не доверие к партнёру. Доверие - только после проверки client_id и client_secret в коде. На продуктиве endpoint только по HTTPS; секреты клиентов не кладём в модуль и не возвращаем в теле ошибок.

Справочник клиентов и секрет для проверки POST
Модель данных клиента отделена от пользователя 1С, которого платформа подставит при успешном Bearer на API.
3. Сборка ТокенДоступа: HS256 и согласование с default.vrd
После проверки пары создаём ТокенДоступа. В заголовке - alg HS256. Заполняем эмитент, массив получателей с одним элементом (имя HTTP-сервиса из vrd API), КлючСопоставленияПользователя (пользователь с галочкой «Аутентификация токеном доступа»), время создания в формате объекта, время жизни в секундах, идентификатор. Вызываем Подписать тем же ключом, что в константе и в Base64 в keyInformation.
Время создания - разница между текущей универсальной датой и эпохой 1970-01-01, как ждёт объект при проверке TTL на API. Срок жизни согласуем с партнёром: длинный token расширяет окно компрометации, короткий нагружает token endpoint.
Ротация ключа: на время смены держим два значения keyInformation или две константы и на API принимаем подпись любым из них, пока живы старые токены. Client_secret партнёра меняем через справочник клиентов, без деплоя конфигурации.

Согласование полей токена и vrd
Любое расхождение между кодом выдачи и vrd - и rphost отрежет запрос до обработчика заказов.
4. Публикация API: пользователь, галочка, фрагмент default.vrd
В рабочей ИБ заводим пользователя для токенного входа (в примере tokenuser), права - только на нужный HTTP-сервис, в администрировании 8.3 включаем «Аутентификация токеном доступа». Публикуем сервис, в сгенерированном default.vrd добавляем блок проверки access token (имена элементов - по документации по публикации HTTP-сервисов для вашего релиза 8.3):
<accessTokenAuthentication>
<accessTokenRecepientName>PartnerOrders</accessTokenRecepientName>
<issuerName>ssl</issuerName>
<authenticationUserPropertyName>tokenuser</authenticationUserPropertyName>
<keyInformation>BASE64_КЛЮЧА_ПОДПИСИ</keyInformation>
</accessTokenAuthentication>
Платформа проверяет подпись, срок, эмитента и получателя и открывает сеанс от имени сопоставленного пользователя. В модуле HTTP-сервиса заказов разбор JWT не дублируем: настройки vrd и ручная проверка разойдутся при смене ключа.
Опираемся на штатные механизмы: публикация HTTP-сервисов, формат default.vrd, настройка пользователя ИБ. Объекта метаданных «OAuthСервер» в типовой конфигурации нет.
5. Сквозная проверка и типовые сбои
Приёмка: curl или Postman - POST на token с корректной парой, ответ 200 и непустой access_token; read-only метод API с Bearer; повтор с неверным secret (400 на token); с испорченным payload при верном token (401 на API); вызов после истечения TTL.
401 до входа в метод HTTP-сервиса чаще всего - неверный keyInformation, другой issuerName или accessTokenRecepientName, не совпадающий с Получатели. 400 на token при «верных» секретах - парсер тела или лишние пробелы после декодирования. На ИБ выдачи пишем в журнал регистрации отказ без значения client_secret; на API смотрим технологический журнал rphost и HTTP-сервиса.

Цепочка запросов при приёмке интеграции
Сначала успешный token, один метод API, затем негативные кейсы - до подключения партнёра.
6. Эксплуатация: HTTPS, секреты, одна база или две
Две ИБ (token и API) имеет смысл, когда политика безопасности требует разного состава прав и разных админов на контурах. Одну публикацию с двумя HTTP-сервисами допускаем, если URL разведены, пользователи сеансов разные, а общий каталог vrd приемлем по рискам. В обоих вариантах синхронизация трёх мест - поля токена, vrd API, хранилище ключа - обязательна.
Path в swagger и поля личного кабинета партнёра меняются: перед сдачей сверяем grant_type в теле и формат ошибок, даже если token endpoint отвечает упрощённо.
Для сопровождения: client_id и client_secret дают право получить токен, access token - право вызвать HTTP-сервис. Связка endpoint выдачи с ТокенДоступа (HS256) и accessTokenAuthentication в default.vrd держится на согласованных получателе, эмитенте и ключе подписи. Переименование сервиса в метаданных без правки vrd и констант снова даст 401.
Ограничения подхода
Refresh token и authorization code flow этим рецептом не закрываются. Тела ошибок OAuth RFC партнёр может не принять без маппинга. Парсер form-urlencoded здесь учебный: вложенные структуры и нестандартные кодировки нужно покрыть отдельно. Несколько resource API с разными получателями потребуют отдельной выдачи или разных значений в массиве получателей - по правилам платформы для вашего релиза.
| Ситуация | Решение | Риск |
|---|---|---|
| Партнёр шлёт client_id/secret в теле, без Basic на token | Отдельная публикация token, Usr/Pwd в ib vrd, проверка пары в коде | Секреты в логах при отладке тела запроса |
| API должен знать сеанс без логина партнёра | ТокенДоступа + accessTokenAuthentication, пользователь с аутентификацией токеном | 401 при рассинхроне issuer, recipient или ключа |
| Нужна смена ключа подписи | Окно двух keyInformation на token и API | Клиенты со старым токеном до истечения TTL |
| Один rphost, два контура | Два HTTP-сервиса в одной ИБ или две ИБ | tokenuser шире необходимых ролей API |
| 400 «аутентификация» при верных секретах | URL-декодирование и проверка пустых полей в парсере | Ложные тикеты к партнёру |
Вступайте в нашу телеграмм-группу Инфостарт