OAuth2 без путаницы: роли, потоки и выбор сценария
OAuth2 позволяет приложению получить ограниченный доступ к API от имени пользователя или другой системы. Разбираем, кто участвует в обмене, зачем нужен PKCE и какой поток выбрать для сайта, мобильного приложения или сервиса.

OAuth2 не передаёт вашему приложению пароль пользователя: он выдаёт ограниченный токен, с которым можно обращаться к API. Путаница начинается, когда один и тот же термин используют для разных участников и сценариев. Ниже — схема OAuth 2.0 по RFC 6749 и практические рекомендации по безопасности из RFC 9700: как проходит обмен, где нужен PKCE и почему токен доступа не доказывает личность пользователя.
Четыре участника, а не один «сервер авторизации»
Сначала разведите роли. В реальном продукте несколько из них могут находиться на одной инфраструктуре, но в протоколе это разные обязанности:
- Владелец ресурса — обычно пользователь, чьи данные доступны через API.
- Клиент — приложение, которое хочет получить доступ: например, ваш сайт или мобильное приложение.
- Сервер авторизации — проверяет пользователя, получает его согласие и выпускает токены.
- Сервер ресурсов — API, который принимает токен и решает, можно ли выполнить запрос.
Например, кнопка «Подключить календарь» запускает OAuth-сценарий: ваш сервис просит разрешение читать календарь, пользователь подтверждает его на стороне поставщика, а ваш сервис получает токен с ограниченным доступом. Пароль от учётной записи поставщика приложению не передают.
Термин. Публичный клиент — приложение, которое не может надёжно хранить секрет: например, код в браузере или приложение на телефоне. Секрет, встроенный в такое приложение, можно извлечь, поэтому он не доказывает серверу, что запрос пришёл от доверенного клиента.
OAuth отвечает на вопрос «какие действия этому приложению разрешены?», а не «кто именно вошёл?».
Как работает Authorization Code с PKCE
Для входа пользователя через сторонний сервис чаще всего используют поток Authorization Code. В браузерном и мобильном приложении к нему добавляют PKCE — механизм, который связывает запрос авторизации с последующим обменом кода на токен. Детали интерфейса у провайдеров отличаются, но последовательность обычно такая:
- Клиент создаёт параметры защиты. Генерирует случайный
state, а для PKCE — случайныйcode_verifierи вычисленный из негоcode_challenge. Проверка: значения созданы для этой попытки авторизации и не переиспользуются из другого входа. - Клиент перенаправляет пользователя на сервер авторизации. В запросе указываются клиент, адрес возврата, нужные права доступа (
scope),stateи параметры PKCE. Проверка: пользователь видит страницу ожидаемого провайдера, а не форму пароля вашего приложения. - Пользователь входит и подтверждает доступ. Сервер авторизации проверяет учётную запись и, если требуется, показывает согласие на запрошенные права. Проверка: приложение не получает пароль, а пользователь может понять, какие данные запрашивают.
- Сервер возвращает браузер в приложение. В адрес возврата приходят короткоживущий код авторизации и исходный
state. Клиент сравнивает полученныйstateс сохранённым. Проверка: значения совпали; если нет — процесс прекращают, а не продолжают «на удачу». - Клиент обменивает код на токен. Запрос уходит на сервер авторизации, а клиент передаёт код и исходный
code_verifier. Сервер проверяет связь с ранее переданным challenge и выдаёт токен, если проверка успешна. Проверка: ответ содержит токен и срок его действия либо возвращает понятную ошибку. - Клиент обращается к API. Токен передаётся серверу ресурсов в заголовке авторизации. API проверяет токен, его срок и права доступа. Проверка: разрешённый запрос проходит, а запрос за пределами выданных прав отклоняется.
PKCE важен потому, что перехваченного кода недостаточно для получения токена: нужен ещё code_verifier. state решает другую задачу — помогает связать ответ с начатым входом и не принять неожиданный переход за свой. Не смешивайте эти параметры и не считайте один заменой другого.
Какой сценарий выбрать
У OAuth2 несколько вариантов выдачи токенов, или потоков. Выбор зависит прежде всего от того, действует ли пользователь и где выполняется клиент. Это не три взаимозаменяемых способа «залогиниться».
| Сценарий | Когда подходит | Что важно учесть |
|---|---|---|
| Authorization Code + PKCE | Вход пользователя в веб-приложении или мобильном приложении | Пользователь проходит авторизацию на стороне провайдера. Для публичных клиентов нужен PKCE; он полезен и в других сценариях с кодом. |
| Authorization Code для серверного приложения | Веб-сайт, у которого есть сервер и возможность безопасно хранить учётные данные клиента | Секрет хранится только на сервере. Для обмена кодом сервер также может использовать PKCE; секрет клиента не заменяет проверку state. |
| Client Credentials | Обмен между сервисами, когда пользователь не участвует | Токен выдают самому клиенту, а не от имени пользователя. Секреты и права доступа нужно ограничивать и защищать на сервере. |
Когда что выбирать
- Пользователь подключает внешний аккаунт — Authorization Code с PKCE.
- Ваш сервер обрабатывает возврат от провайдера и хранит секрет вне браузера — Authorization Code; PKCE остаётся дополнительной защитой.
- Один сервер вызывает API другого от имени своей системы — Client Credentials, если провайдер поддерживает этот сценарий.
Не начинайте новую интеграцию с передачи логина и пароля пользователя приложению или с попытки выдать токен напрямую из браузерного перенаправления. В рекомендациях RFC 9700 потоки Implicit и Resource Owner Password Credentials не подходят для новых систем: выбирайте сценарий с кодом авторизации или другой поток, который официально поддерживает ваш провайдер.
Токен — не обязательно профиль пользователя
Access token даёт доступ к API в рамках выданных прав. Он может быть JWT с данными, которые API проверяет, или непрозрачной строкой, смысл которой известен только серверу авторизации. Клиенту не следует самостоятельно угадывать формат токена и считать любую строку JWT.
Если задача — подтвердить, что пользователь вошёл именно под определённой учётной записью, одной базовой спецификации OAuth2 недостаточно. Для этого часто используют OpenID Connect (OIDC) — слой идентификации поверх OAuth2. В OIDC появляется ID token с данными об аутентификации; его проверяют по правилам OIDC, включая ожидаемого получателя и издателя. Не используйте access token вместо ID token и наоборот.
Что ломается в реальной интеграции
- Несовпадает
redirect_uri. Сервер авторизации может отклонить запрос, если адрес возврата не совпадает с зарегистрированным. Сверьте схему, домен, путь и настройки окружения; не расширяйте адрес возврата до произвольного. - Приходит ошибка
invalid_grant. Код мог истечь, быть использован повторно или не совпасть с параметрами запроса. Получайте новый код для каждой попытки и проверьте, что обмениваете его на том же сервере и с тем же клиентом. - Возвращается
invalid_client. Проверьте идентификатор клиента и способ его аутентификации. В публичном приложении не пытайтесь исправить ошибку добавлением встроенного секрета: он не станет секретным. - API отвечает 401. Токен может истечь, быть предназначен для другого API или не пройти проверку. Проверьте срок действия и целевую аудиторию по правилам провайдера; не отправляйте токен в URL.
- Ответ возвращается не в ту вкладку или с ошибкой проверки. Сверьте сохранённый
stateс вернувшимся значением и привяжите его к конкретной попытке входа. Не отключайте эту проверку, чтобы «починить» редирект.
В проде отдельно продумайте хранение токенов, завершение сессии и обновление доступа. Refresh token может давать возможность получить новые access token, поэтому его утечка опаснее обычной ошибки входа. Храните его только там, где это оправдано архитектурой, ограничивайте доступ и следуйте рекомендациям провайдера по ротации и отзыву. Не записывайте токены в логи, аналитику и сообщения об ошибках.
Что проверить перед запуском
Протокол: OAuth 2.0 по RFC 6749; рекомендации по защите — RFC 9700. Названия полей и требования к регистрации приложения могут различаться у провайдеров, поэтому сверяйте параметры с документацией конкретного API.
- Указан подходящий поток: пользовательский или межсервисный.
- Адрес возврата зарегистрирован точно, а
stateсоздаётся и проверяется для каждой попытки. - Для потока с кодом настроен PKCE, а
code_verifierне попадает в логи и не переиспользуется. - Права доступа ограничены необходимыми
scope, а сервер проверяет токен по правилам API. - В логах и мониторинге нет токенов, кодов авторизации и клиентских секретов.
Следующий шаг — пройти сценарий целиком на тестовом приложении у вашего провайдера и проверить не только успешный вход, но и отказ пользователя, просроченный код и ответ API с недостаточными правами. Именно на этих ветках обычно обнаруживаются ошибки, которые не видны на кнопке «Войти».
Сценарист праздников: Тосты, квесты, сценарии корпоративов и дней рождения.
Спросить за 8 ₽Источники: RFC 6749: The OAuth 2.0 Authorization Framework, RFC 9700: Best Current Practice for OAuth 2.0 Security
Частые вопросы
OAuth2 — это способ входа через Google или другой аккаунт?
Можно ли использовать Authorization Code без PKCE?
Нужно ли хранить access token в браузере?
Что делать, если вместо токена приходит invalid_grant?
Можно ли одним OAuth-токеном вызывать любой API?
Какой поток выбрать, если у меня другая версия OAuth или библиотеки?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.