MORLIX JOURNAL
OAuth 2.0 для интеграций: scopes, redirect URI и токены
Как устроен OAuth 2.0 для интеграций: scopes, redirect URI, PKCE и безопасная работа с токенами.
OAuth 2.0 позволяет приложению получить ограниченный доступ к ресурсу через сервер авторизации. Пользователь может разрешить интеграции определённые действия, не передавая ей пароль от основного сервиса. При этом OAuth сам по себе не является универсальным протоколом входа: для подтверждения личности часто используют отдельный слой OpenID Connect.
Для интеграции важно разобраться в трёх вещах: какие права запрашиваются через scopes, куда возвращается ответ через redirect URI и как защищаются токены. Рассмотрим распространённый поток Authorization Code с PKCE, жизненный цикл доступа и проверки перед запуском. Примеры условные: реальные адреса и поддерживаемые возможности нужно брать из документации вашего поставщика.
Кто участвует в OAuth 2.0
В процессе участвуют владелец ресурса, клиентское приложение, сервер авторизации и сервер ресурсов. Владелец разрешает доступ; клиент просит его для конкретной задачи; сервер авторизации выдаёт необходимые данные; сервер ресурсов принимает запросы к защищённому API и проверяет полномочия.
Например, приложение для отчётов хочет читать список заказов магазина. Оно перенаправляет владельца к поставщику, запрашивает только необходимое разрешение и затем обращается к API с токеном. API по-прежнему самостоятельно проверяет, допустимо ли действие для этого ресурса. Сам факт получения токена не заменяет проверки прав на стороне сервера.
Различайте публичные клиенты, которые не могут надёжно сохранить общий секрет в приложении или браузере, и конфиденциальные клиенты, которые способны хранить учётные данные на защищённом сервере. Нельзя считать секрет в мобильном приложении или JavaScript надёжно скрытым от пользователя устройства.
Как проходит Authorization Code с PKCE
Поток обычно начинается с перехода пользователя на сервер авторизации. Клиент формирует запрос с зарегистрированным идентификатором приложения, redirect URI, запрашиваемыми правами и параметрами защиты. Пользователь входит непосредственно у поставщика и при необходимости подтверждает доступ.
После согласия сервер возвращает краткоживущий код авторизации на зарегистрированный redirect URI. Клиент отправляет код на token endpoint вместе с необходимыми параметрами и получает ответ с токеном доступа и, если поставщик его выдаёт, токеном обновления. Сам код — не access token, и его нельзя использовать как долгосрочное разрешение.
PKCE связывает запрос авторизации с последующим обменом кода. Клиент заранее создаёт случайный code_verifier, вычисляет для него code_challenge и передаёт challenge в запросе. При обмене он предъявляет исходный verifier; сервер сравнивает его с ранее полученным значением. Используйте метод S256, если он поддерживается, и надёжный генератор случайных значений.
PKCE нужен публичным клиентам и полезен также конфиденциальным. Он не отменяет защиту redirect URI, проверку состояния запроса и другие меры. Точный набор параметров, поддержку PKCE и способ аутентификации клиента проверяйте в документации сервиса. Основы проектирования защищённого API отдельно рассмотрены в статье о REST API и авторизации.

Scopes: просите только необходимые права
Scope — обозначение запрашиваемого уровня доступа, смысл которого определяет сервер авторизации. Названия и гранулярность у разных поставщиков различаются: нельзя предполагать, что одинаковое слово в двух API даёт одинаковые полномочия. Запрашивайте минимум, необходимый для конкретной функции, и объясняйте пользователю зачем он нужен.
Если отчётам достаточно чтения заказов, не запрашивайте изменение товаров и доступ к платежам «на будущее». Если позднее появляется новая функция, согласуйте дополнительные разрешения отдельно, когда это поддерживается поставщиком. Проверяйте реально выданные права: пользователь или сервер может предоставить не весь запрошенный набор.
На стороне API дополнительно проверяйте принадлежность ресурса и права субъекта. Широкий scope не означает, что клиент вправе читать данные любого пользователя. Отказ в доступе обрабатывайте как штатный сценарий: покажите понятное состояние и путь повторного согласования, не выполняя бесконечные запросы.

Redirect URI и защита обратного перехода
Redirect URI — адрес клиента, на который сервер авторизации возвращает результат. Зарегистрируйте конкретный адрес и используйте безопасное сравнение согласно требованиям поставщика. Не принимайте произвольный адрес возврата из параметра запроса: открытая переадресация может направить код злоумышленнику.
Используйте HTTPS для сетевых адресов, кроме специально оговорённых безопасных сценариев локального перенаправления для нативных приложений. Не используйте шаблонные wildcard-адреса и общие callback-маршруты, если это создаёт возможность подмены получателя. Особенности локальных адресов, схем приложений и регистрацию проверяйте по стандартам и документации платформы.
Перед началом потока создайте непредсказуемое значение state, свяжите его с пользовательской сессией и проверьте после возврата. Это помогает обнаружить несоответствие ответа инициированному запросу. Сравнение должно происходить до использования кода; отклоняйте отсутствующее, повторно использованное или неверное значение. В сценариях с несколькими серверами авторизации также защищайтесь от перепутывания поставщика и проверяйте ожидаемого издателя по поддерживаемому механизму.
На callback-странице не оставляйте код в URL дольше необходимого: обработайте ответ и перенаправьте пользователя на чистый адрес. Не передавайте его сторонним скриптам и не записывайте в журналы. Подробности о защите пользовательских запросов и сессий есть в материале о XSS и CSRF.
Access token и refresh token
Access token предъявляется серверу ресурсов для выполнения разрешённых запросов. Его формат и срок действия зависят от поставщика; не предполагайте, что любой токен является JWT или что клиенту нужно разбирать его содержимое. Bearer-токен следует защищать как секрет: тот, кто им владеет, может использовать его в пределах предоставленных прав, если дополнительные меры привязки не применяются.
Обычно токен передают в заголовке Authorization: Bearer по защищённому соединению. Не помещайте токены в URL: адреса попадают в историю, журналы и другие системы. Не выводите их в диагностику, аналитические события, сообщения об ошибках и клиентские снимки экрана. Ограничивайте доступ к журналам и маскируйте чувствительные данные.
Refresh token используется для получения нового access token, если поставщик выдал его и сценарий допускает обновление. Он часто живёт дольше и потому требует особенно аккуратного хранения. Храните его в защищённом хранилище, ограничивайте доступ сервиса и используйте предусмотренные поставщиком ротацию и отзыв. Для публичных клиентов рекомендации безопасности предусматривают защиту refresh token, например ротацию или привязку к отправителю в поддерживаемом варианте.
При обновлении учитывайте конкурентные запросы: если несколько процессов одновременно используют один refresh token, ротация может привести к конфликту. Сериализуйте обновление для конкретного подключения и сохраняйте новый токен атомарно. Если обновление отклонено или разрешение отозвано, остановите фоновые запросы и предложите пользователю безопасно подключить интеграцию заново.
Пример настройки интеграции по шагам
- Определите данные и действия, необходимые функции, затем сопоставьте их с минимальными scopes поставщика.
- Зарегистрируйте клиент и точный redirect URI. Уточните тип клиента, поддержку PKCE S256 и требуемый способ аутентификации на token endpoint.
- Создайте отдельные параметры state и PKCE для каждой попытки, привяжите их к сессии и задайте ограниченный срок действия.
- Направьте пользователя на сервер авторизации. После возврата проверьте state, ожидаемого поставщика и результат, затем обменяйте код с verifier.
- Сохраните токены в соответствующем защищённом хранилище, зафиксируйте срок действия и фактически выданные права без сохранения секретов в логах.
- Проверьте успешный запрос, отказ в разрешении, истечение и отзыв доступа. Убедитесь, что повторный callback не создаёт второе подключение.
Для условного сервиса отчётов тест начинается с чтения одного доступного заказа в тестовой учётной записи. Затем проверьте, что попытка изменить заказ без нужного разрешения отклоняется, а данные другого владельца недоступны. Это пример тестового сценария, а не обещание конкретного поведения любого API.
Частые ошибки и проверка перед запуском
Секреты в публичном клиенте
Не встраивайте client secret в распространяемый браузерный или мобильный код как единственную защиту. Используйте подходящий поток публичного клиента с PKCE либо серверную архитектуру, если она нужна и поддерживается. Секреты сервера храните в управляемом хранилище, а не в репозитории.
Смешение авторизации и идентификации
OAuth решает задачу делегированного доступа. Если приложению нужно удостовериться, кто вошёл, используйте подходящий протокол идентификации и проверяйте его требования; не считайте наличие access token доказательством личности само по себе. При применении OpenID Connect проверяйте ID token в соответствии со спецификацией и настройками поставщика.
Отсутствие отзыва и обработки ошибок
Предусмотрите отключение интеграции, удаление сохранённых секретов и отзыв токенов, если поставщик предоставляет соответствующий механизм. Не повторяйте неуспешные запросы бесконечно. Для фоновых обменов предусмотрите ограниченные повторы и защиту от дублирования операций; связанные практики описаны в статье о приёме вебхуков.
- Scopes минимальны, их смысл и фактически выданные права проверены.
- Redirect URI зарегистрирован точно, callback не является открытой переадресацией.
- State и PKCE уникальны для попытки, связаны с сессией и проверяются до обмена кода.
- Токены передаются по защищённому каналу, не попадают в URL и журналы и хранятся с ограниченным доступом.
- Обработаны отказ, истечение, отзыв, ротация и одновременное обновление токенов.
- API проверяет полномочия и принадлежность ресурса на каждом защищённом действии.
Перед реализацией сверяйте требования с RFC 6749, RFC 7636 о PKCE и рекомендациями безопасности OAuth 2.0, а затем с документацией конкретного поставщика. Начните с минимальных прав и тестовой интеграции, проверив весь жизненный цикл доступа.