Справочник системных ошибок и решений

Windows Server, Active Directory, 1С:Предприятие, СУБД, Linux, Cisco, MikroTik, Asterisk.

⚠️ Важная информация Все материалы, инструкции, команды и скрипты на сайте предоставлены исключительно в ознакомительных целях. Их применение может повлиять на работу операционной системы, программного обеспечения, баз данных, сетевого оборудования и других компонентов инфраструктуры. Перед выполнением действий создайте резервную копию и по возможности протестируйте изменения в безопасной среде. Пользователь самостоятельно оценивает риски и несет ответственность за результат. При отсутствии необходимых знаний обратитесь к квалифицированному ИТ-специалисту.

1C_HTTP_401_UNAUTHORIZED 1С:Предприятие и СУБД

Реализация авторизации OAuth 2.0 и JWT в исходящих HTTP-запросах 1С:Предприятие

Обновлено: 26.08.2026 · Официальная документация ↗

При интеграции 1С с современными внешними сервисами возникают следующие сложности:

  • Внешний API возвращает HTTP-статус 401 Unauthorized или 403 Forbidden при отправке стандартных Basic Auth заголовков.
  • Истечение срока жизни Access Token (Token expired) во время длительных регламентных заданий.
  • Необходимость подписи payload для формирования JSON Web Token (JWT) по алгоритму RS256/HS256.
  • Ошибки десериализации ответа авторизационного сервера при получении refresh_token.

1. Архитектура взаимодействия OAuth 2.0 (Client Credentials Flow)

Схема включает два этапа: получение временного access_token через сервисный эндпоинт авторизации и последующее выполнение целевых вызовов с заголовком Authorization: Bearer <токен>. Для минимизации сетевых задержек токен необходимо кэшировать в оперативной памяти или базе данных до момента его экспирации.

2. Программный модуль получения и кэширования Bearer токена

&НаСервере
Функция ПолучитьOAuth2Токен(НастройкиАвторизации, ПринудительноОбновить = Ложь) Экспорт
    
    КлючКэша = "КэшOAuthТокена_" + НастройкиАвторизации.ИмяСервиса;
    
    Если НЕ ПринудительноОбновить Тогда
        ДанныеТокена = ПараметрыСеанса.КэшТокеновOAuth.Получить(КлючКэша);
        Если ДанныеТокена <> Неопределено И ДанныеТокена.СрокДействия > ТекущаяДатаСеанса() + 60 Тогда
            Возврат ДанныеТокена.AccessToken;
        КонецЕсли;
    КонецЕсли;
    
    // Инициализация SSL соединения
    ПараметрыTLS = Новый ПараметрыЗащищенногоСоединенияOpenSSL();
    ЗащищенноеСоединение = Новый ЗащищенноеСоединениеOpenSSL(ПараметрыTLS);
    
    HTTPСоединение = Новый HTTPСоединение(
        НастройкиАвторизации.СерверАвторизации,
        443,
        ,,,
        30,
        ЗащищенноеСоединение
    );
    
    HTTPЗапрос = Новый HTTPЗапрос(НастройкиАвторизации.ПутьАвторизации);
    HTTPЗапрос.Заголовки.Вставить("Content-Type", "application/x-www-form-urlencoded");
    
    ТелоЗапроса = СтрШаблон(
        "grant_type=client_credentials&client_id=%1&client_secret=%2&scope=%3",
        КодироватьСтроку(НастройкиАвторизации.ClientID, СпособКодированияСтроки.КодировкаURL),
        КодироватьСтроку(НастройкиАвторизации.ClientSecret, СпособКодированияСтроки.КодировкаURL),
        КодироватьСтроку(НастройкиАвторизации.Scope, СпособКодированияСтроки.КодировкаURL)
    );
    
    HTTPЗапрос.УстановитьТелоИзСтроки(ТелоЗапроса, КодировкаТекста.UTF8, ИспользованиеByteOrderMark.НеИспользовать);
    
    HTTPОтвет = HTTPСоединение.ОтправитьДляОбработки(HTTPЗапрос);
    
    Если HTTPОтвет.КодСостояния <> 200 Тогда
        ВызватьИсключение СтрШаблон("Ошибка OAuth (%1): %2", HTTPОтвет.КодСостояния, HTTPОтвет.ПолучитьТелоКакСтроку());
    КонецЕсли;
    
    ЧтениеJSON = Новый ЧтениеJSON;
    ЧтениеJSON.УстановитьСтроку(HTTPОтвет.ПолучитьТелоКакСтроку());
    ОтветJSON = ПрочитатьJSON(ЧтениеJSON);
    
    AccessToken = ОтветJSON.access_token;
    ExpiresIn = ?(ОтветJSON.Свойство("expires_in"), ОтветJSON.expires_in, 3600);
    
    // Сохранение в кэш
    СтруктураКэша = Новый Структура("AccessToken, СрокДействия", AccessToken, ТекущаяДатаСеанса() + ExpiresIn);
    ПараметрыСеанса.КэшТокеновOAuth.Вставить(КлючКэша, СтруктураКэша);
    
    Возврат AccessToken;
КонецФункции

3. Выполнение целевого запроса с передачей Bearer токена

&НаСервере
Функция ВыполнитьЗапросКРесурсу(Сервер, Путь, ДанныеJSON, НастройкиАвторизации)
    
    Попытка
        Токен = ПолучитьOAuth2Токен(НастройкиАвторизации);
    Исключение
        ЗаписьЖурналаРегистрации("OAuth2", УровеньЖурналаРегистрации.Ошибка,,, ОписаниеОшибки());
        ВызватьИсключение;
    КонецПопытки;
    
    HTTPСоединение = Новый HTTPСоединение(Сервер, 443,,,, 60, Новый ЗащищенноеСоединениеOpenSSL());
    HTTPЗапрос = Новый HTTPЗапрос(Путь);
    HTTPЗапрос.Заголовки.Вставить("Authorization", "Bearer " + Токен);
    HTTPЗапрос.Заголовки.Вставить("Content-Type", "application/json; charset=utf-8");
    HTTPЗапрос.УстановитьТелоИзСтроки(ДанныеJSON, КодировкаТекста.UTF8, ИспользованиеByteOrderMark.НеИспользовать);
    
    HTTPОтвет = HTTPСоединение.ВызватьHTTPМетод("POST", HTTPЗапрос);
    
    // Обработка возможной инвалидации токена до истечения локального TTL
    Если HTTPОтвет.КодСостояния = 401 Тогда
        Токен = ПолучитьOAuth2Токен(НастройкиАвторизации, Истина); // Принудительный refresh
        HTTPЗапрос.Заголовки.Вставить("Authorization", "Bearer " + Токен);
        HTTPОтвет = HTTPСоединение.ВызватьHTTPМетод("POST", HTTPЗапрос);
    КонецЕсли;
    
    Возврат HTTPОтвет;
КонецФункции

4. Декодирование полезной нагрузки JWT (Payload) без внешних библиотек

Для чтения claims из JWT-токена выполните Base64-декодирование центральной секции токена (header.payload.signature):

&НаСервере
Функция ПолучитьPayloadJWT(СтрокаJWT)
    МассивЧастей = СтрРазделить(СтрокаJWT, ".");
    Если МассивЧастей.Количество() < 2 Тогда
        Возврат Неопределено;
    КонецЕсли;
    
    Base64Payload = МассивЧастей[1];
    // Нормализация Base64URL в стандартный Base64
    Base64Payload = СтрЗаменить(Base64Payload, "-", "+");
    Base64Payload = СтрЗаменить(Base64Payload, "_", "/");
    Остаток = СтрДлина(Base64Payload) % 4;
    Если Остаток = 2 Тогда
        Base64Payload = Base64Payload + "==";
    ИначеЕсли Остаток = 3 Тогда
        Base64Payload = Base64Payload + "=";
    КонецЕсли;
    
    ДвоичныеДанные = Base64Значение(Base64Payload);
    СтрокаJSON = ПолучитьСтрокуИзДвоичныхДанных(ДвоичныеДанные, КодировкаТекста.UTF8);
    
    Чтение = Новый ЧтениеJSON;
    Чтение.УстановитьСтроку(СтрокаJSON);
    Возврат ПрочитатьJSON(Чтение);
КонецФункции
💡 Практика специалистов: Всегда реализуйте механизм Retry со сбросом кэша токена при получении 401 HTTP-ответа. Сервер авторизации может отозвать сессию раньше времени, указанного в expires_in, что вызовет лавинообразные ошибки интеграции в фоновых заданиях.

Частые вопросы (FAQ)

Как безопасно хранить Client Secret для OAuth в 1С?

Client Secret нельзя жестко зашивать в код конфигурации. Его следует хранить в защищенном регистре сведений с разделением прав или использовать встроенные механизмы БСП 'ХранилищеДополнительнойИнформации' с шифрованием данных.

Что делать, если внешний сервер возвращает JWT в формате Base64Url?

Встроенная функция 1С Base64Значение() работает со стандартным Base64. Символы '-' и '_' необходимо заменить на '+' и '/', а также дополнить строку символами '=' до кратности 4.

Как реализовать подпись JWT алгоритмом RS256 средствами 1С?

Платформа 1С:Предприятие поддерживает объект МенеджерКриптографии. Для RS256 генерируется хеш SHA-256 от Header.Payload и подписывается закрытым RSA-ключом через метод Зашифровать() или внешнюю утилиту OpenSSL.

Почему при получении токена возникает ошибка 'Invalid grant_type'?

Ошибка возникает, если тело POST-запроса не передано в формате Content-Type: application/x-www-form-urlencoded или параметры client_id/client_secret не прошли экранирование через КодироватьСтроку(..., СпособКодированияСтроки.КодировкаURL).

Полезные материалы
Рекомендуем