В процессе работы программистом 1С у меня иногда возникали задачи интеграции с системами использующими OAuth2 (Zoho Books, Google, Yandex и прочие). Причем часто нужно делать автоматические обмены с этими системами, не подразумевающих участия пользователя.
OAuth2 несколько более сложная система доступа, чем пара логин-пароль. К сожалению, некоторые системы полностью отказались от доступа по паролям приложений и приходится использовать модные новые способы доступа с прокладкой в виде пользователя посредине. Попробую объяснить ее суть и простейший способ реализации для интеграции. Цель статьи объяснить как получить постоянный доступ для роботов к системам, у которых нет паролей приложения, а есть только OAuth2.
Участники процесса авторизации:
Интегрируемая система (ZB, Google и т.п.) - далее Система.
Приложение - приложение, которое пытается получить доступ к интегрируемой системе. Это может быть сайт, а может быть оффлайн-приложение.
Пользователь - к сожалению, в отличии от авторизации по логину-паролю, пользователь должен эпизодически присутствовать в схеме авторизации.
Создание приложения в Системе
Сначала в личном кабинете Системы нажатием одной кнопки создается веб-приложение. В приложении нужно указать RedirectURI, смысл которого объясню далее:
![](https://habrastorage.org/getpro/habr/upload_files/aad/fcb/b2d/aadfcbb2dfd9e159dce49ced65c0a867.png)
Для приложения система генерирует ClientID и ClientSecret:
![](https://habrastorage.org/getpro/habr/upload_files/ea2/54c/84d/ea254c84d970e90b3757fc1522f0ec31.png)
Получение Grant токена
Затем пользователю генерируется ссылка, ведущая на страницу Системы. Ссылка содержит ClientID в открытом виде. Пользователь должен пройти по ссылке. При этом пользователь должен быть авторизован под собой Системе при переходе по ссылке. Если он не авторизован, ему будет предложено авторизоваться.
Пользователю будет предложено разрешить приложению доступ к его данным - нажать зеленую кнопку:
![](https://habrastorage.org/getpro/habr/upload_files/d9c/73a/64c/d9c73a64c1888abc18b92155a8d383a1.png)
На этом этапе мы видим, что ClientID - публичный идентификатор. Также видим, что нельзя воспользоваться в OAuth2 в браузере, где пользователь не авторизовался и автоматом кликнуть на кнопке "Согласен". Можно, конечно, заманить пользователя на свой сайт и попросить там ввести логин и пароль в систему, но вряд ли пользователь на это "купится". Так что тут всё довольно безопасно.
Когда пользователь подтверждает доступ, браузер переходит по адресу RedirectURI, передавая в параметре значение Grant токен. Скрипт, расположенный по этому адресу, сохраняет этот токен в Приложении.
Тут есть один подводный камень - теоретически, можно вызвать адрес RedirectURI и сбить сохраненный в Приложении Grant токен. Проблему можно решить тем, чтобы ограничить доступ к RedirectURI только администраторам.
Grant токен довольно долгоиграющий и может работать месяцами и годами, пока не будет отозван доступ. Пользователь может в личном кабинете зайти, посмотреть и отозвать выданные доступы.
Где хранить Grant токен
Рассмотрим ситуацию, когда у вас несколько пользователей гоняют данные туда-обратно в одну и ту же Систему. Тогда имеет смысл хранить Grant токен в константе. В первый раз пользователь, имеющий доступ в систему, авторизуется под собой в Систему и получит этот токен, а дальше возможностями интеграции с системой будут пользоваться все пользователи Приложения в рамках, ограниченных Приложением.
Но можно, конечно, хранить Grant токен и для каждого пользователя отдельно. Только не в сессиях, потому что срок жизни Grant токена намного дольше жизни сессии на сайте. Поэтому лучше хранить этот токен в настройках пользователя Приложения.
Особенности работы в локальном приложении
Однако как быть, если приложение - локальное (например 1С) и у нас нет веб-страницы для RedirectURI?
Тогда нужно встроить браузер в приложение и указать в качестве RedirectURI любую несуществующую страницу или любую страницу внутри корпоративного сайта. Тогда пользователь авторизуется во встроенном браузере, ведь он доверяет локальному приложению и когда перейдет по ссылке, браузер попытается перейти по ссылке, которая содержит Grant-токен. Можно перехватить этот адрес из встроенного браузера и получить из него токен.
Получение Refresh и Access токенов
Если известен Grant токен, можно выполнить запрос, содержащий ClientSecret и Grant токен. Система выдаст Refresh или Refresh и Access токены одновременно.
Refresh токен долгоживущий - в зависимости от настроек и параметро запроса может жить несколько суток или недель.
Access токен живет более короткий срок, обычно несколько часов.
OAuth2 также подерживает получение Access токена из Refresh.
На практике обычно используется такой алгоритм:
Если есть Access токен, то очередная операция осуществляется с его помощью. Нужно понимать, что доступ по этому токену может прерваться в любой момент, поэтому в случае отказа при обработке данных в цикле, проверять, а не по причине ли истечения срока Access токена произошел отказ.
Если Access токена нет или он прекратил свое действие, то генерируется новый Access токен из Refresh токена.
Если Refresh токена нет, то он генерируется из Grant токена.
Если Grant токена нет, то обратока данных обычно прерывается с ошибкой, т.к. необходимо вмешательство пользователя, который должен заново авторизовать Приложение в Систему. А пользователь может быть не доступен в этот момент.
Выводы
Многоступенчатая система токенов призвана для устранения уязвимостей. Например, если перехватить Access токен, то воспользоваться доступом можно всего несколько часов. Refresh токен перехватить уже сложнее.
Жаль, что такое элегантное решение как пароли приложений, которые точно так же легко отозвать, игнорируется некоторыми системами и в задачах автоматизированного обмена приходится иногда вмешиваться в ход давно настроенных обработок. Это оборотная сторона безопасности.
![Схема OAuth2 Схема OAuth2](https://habrastorage.org/getpro/habr/upload_files/a11/c50/f92/a11c50f9266ae564744160aad4f3d3b8.png)