OAuth 2.0
OAuth 2.0
Открытый протокол, позволяющий одному приложению получить ограниченный доступ к ресурсам пользователя в другом приложении — без передачи логина и пароля. Вместо них передаётся выписанный для конкретного приложения токен.
История
OAuth родился из конкретной боли — соцсетей середины 2000-х. К 2006 году у людей появились десятки сервисов: Twitter, Flickr, Google Calendar, Delicious. Каждый раз, когда сторонняя программа хотела «постить за тебя» или «забрать твою адресную книгу», она просила логин и пароль. Это было ужасно: пользователь отдавал ключи от всего, а отозвать доступ можно было только сменой пароля — и тогда отваливались все приложения сразу.
Осенью 2006 года Blaine Cook (тогда — главный архитектор Twitter) и Chris Messina (тот самый, что придумал хештеги) встретились и поняли: им нужен общий стандарт делегирования доступа. К декабрю 2006-го собралась группа из нескольких компаний — Twitter, Magnolia, Pownce, Jaiku — и в апреле 2007-го они выкатили первый драфт OAuth 1.0. В декабре 2007-го протокол опубликовали официально.
В 2009-м нашли дыру — session fixation attack — и выпустили OAuth 1.0a. Параллельно стало понятно, что 1.0 слишком сложен: требовал криптографическую подпись каждого запроса HMAC-SHA1, что хорошо для безопасности, но плохо для разработчиков. Особенно мобильных разработчиков и тех, кто работал на стороне браузера.
В 2010-м IETF (это организация, которая выпускает RFC — основные документы интернет-стандартов) собрала рабочую группу для версии 2.0. Лидом редактора был Eran Hammer — программист, который писал OAuth 1.0 и был его главным апологетом. И вот тут случилась знаменитая драма.
В июле 2012-го, за несколько месяцев до публикации RFC, Hammer демонстративно ушёл с поста, опубликовав разгромный пост «OAuth 2.0 and the Road to Hell» («OAuth 2.0 и дорога в ад»). Он обвинял корпоративных участников (Microsoft, Salesforce и других) в том, что они превратили компактный протокол в швейцарский нож с десятком опций, где каждый делает по-своему и итоговая безопасность зависит от того, как именно ты собираешь все эти детали. Hammer сравнил это с проклятием WS-* — стандартами «энтерпрайз-сервисов» 2000-х, известными именно тем, что в них никто никогда до конца не разобрался.
Несмотря на скандал, в октябре 2012 года вышел RFC 6749 — The OAuth 2.0 Authorization Framework. Именно его сегодня все имеют в виду, когда говорят «OAuth». Это framework, а не протокол в строгом смысле: он описывает не один поток, а несколько, и оставляет много мест на усмотрение реализации.
С тех пор было много дополняющих RFC: RFC 6750 (Bearer Tokens), RFC 7636 (PKCE — обязательная защита для мобильных и SPA), RFC 8252 (для нативных приложений). Сейчас идёт работа над OAuth 2.1 — это не новая версия, а консолидация: убрать устаревшие потоки (Implicit Grant, Resource Owner Password Credentials), сделать PKCE обязательным везде, прибить лучшие практики гвоздями. Драфта 12 опубликован в 2024-м, финальный RFC — ещё в работе.
Параллельно с OAuth выросла надстройка OpenID Connect (2014) — она использует OAuth 2.0 как фундамент и добавляет сверху аутентификацию (то есть «кто этот пользователь», а не только «что ему разрешено»). Когда ты жмёшь «Войти через Google» — внутри почти всегда OpenID Connect поверх OAuth 2.0.
Что это такое
Главная мысль OAuth: разделить три вещи, которые раньше путали.
Аутентификация — кто ты. Это пароль и логин.
Авторизация — что тебе разрешено. Это право читать, писать, удалять.
Делегирование — ты разрешаешь кому-то третьему действовать от твоего имени, в ограниченных рамках.
Классическая ошибка — путать OAuth с «системой входа». Сам по себе OAuth этого не делает: он не говорит «вот этот пользователь — Паша». Он говорит «вот это приложение получило разрешение на чтение календаря пользователя такого-то». Для «опознать пользователя» нужен OpenID Connect, надстройка над OAuth.
В OAuth 2.0 четыре участника:
- Resource Owner (владелец ресурса) — обычно ты, человек, у которого есть данные на сервисе.
- Client (клиент) — приложение, которому ты хочешь дать доступ. Например, Trello, который хочет читать твой Google Calendar.
- Authorization Server (сервер авторизации) — тот, кто выдаёт токены. У Google это
accounts.google.com, у Яндекса —oauth.yandex.ru. - Resource Server (сервер ресурсов) — там лежат данные. У Google Calendar это
googleapis.com, у Яндекс.Метрики —api-metrika.yandex.net.
Authorization Server и Resource Server часто живут в одной компании, но это разные серверы и часто разные домены. Это важно: токен ты получаешь у одного, а используешь — у другого.
И главный артефакт всей системы — access token. Это короткая строка (обычно случайная либо JWT — об этом ниже), которую клиент прикладывает к каждому запросу: Authorization: Bearer <токен>. Сервер ресурсов проверяет токен и отвечает.
В чём отличие от старого «дай свой пароль приложению»:
- Токен выдан только этому конкретному клиенту (если украли — отозвал только у одного).
- Токен ограничен по правам (scope — об этом ниже).
- Токен ограничен по времени (живёт час-сутки-год, в зависимости от настройки).
- Токен отозвать проще, чем сменить пароль.
OAuth 2.0 vs OAuth 1.0a: 1.0a требовал подписывать каждый запрос. Безопаснее в каналах без HTTPS, но требовал криптографии в клиенте. 2.0 убрал подписи и опёрся на HTTPS — стало проще писать клиентов, но любой утёкший токен сразу даёт доступ.
OAuth vs SAML: SAML — это XML-протокол примерно того же возраста, родом из корпоративного мира (логины во внутренние системы крупных компаний). Делает похожее, но через громоздкие XML-документы и тяжелее в реализации. Сегодня в b2c-вебе SAML почти умер, в b2b ещё жив — крупные корпорации требуют SAML SSO для своих сотрудников.
OAuth vs API-ключ: API-ключ — простая строка, которую дают навсегда и обычно с правами на всё. OAuth-токен — выписан на конкретного пользователя, с конкретными правами, на ограниченный срок. API-ключ удобен для server-to-server (бэкенд ходит в чужой бэкенд), OAuth — для случаев, когда есть пользователь, и ты действуешь от его имени.
Аналогии из жизни
Гостиничная карта-ключ. Когда ты заселяешься, портье не отдаёт тебе мастер-ключ от всего отеля. Он выдаёт пластиковую карту, которая открывает только твой номер и работает до даты выезда. Если карту потеряешь — деактивируют только её, остальные гости спят спокойно. Если задержишься на день — нужно прийти и продлить. Точно так же OAuth-токен: ограниченный (только твой номер = только нужный scope), временный (живёт до выезда = срок жизни токена), легко отзываемый.
Где ломается: в отеле есть физический контроль на ресепшене — никто не подделает карту, потому что замки её распознают физически. В OAuth такого контроля нет: если ты случайно слил токен в чат или закоммитил в публичный гитхаб — кто угодно с ним зайдёт «в твой номер», пока его не отзовут. Карту-ключ из чужого кармана достать сложнее, чем строку из лога.
Доверенность у нотариуса. Ты выписываешь брату доверенность: «может получить мою посылку на почте, действует до 31 декабря». Брат идёт на почту, показывает доверенность, ему выдают посылку. Почта не звонит тебе и не проверяет лично — она доверяет печати нотариуса. Аналогично, ресурс-сервер не звонит пользователю, а доверяет токену, выданному сервером авторизации.
Где ломается: доверенность — на конкретное действие («получить посылку»). В OAuth scope бывает очень широким — например, scope «email» в Google означает «читай весь почтовый ящик». Если ты дал такой scope, ты «выписал доверенность на квартиру» там, где хотел только посылку забрать. Поэтому при логине через Google всегда читай, что именно разрешаешь.
Бейдж посетителя в офисе. Приходишь в офис, охранник сверяет паспорт (это аутентификация), выписывает временный пропуск с QR-кодом — «гость такой-то, этаж 5, до 18:00» (это OAuth-токен). Внутри уже никто не спрашивает паспорт — только сканируют пропуск. Если ты захотел в серверную на 8-м этаже, сканер пишет «не положено» (несоответствие scope). В конце дня пропуск перестаёт работать сам — это expiry токена.
Где ломается: бейдж в офисе обычно с фотографией, и охранник может сличить. В OAuth носителем токена может быть кто угодно — это так называемый bearer token (то есть «на предъявителя»). Прибил физически к одному устройству — это уже другие механизмы, DPoP или mTLS, и они применяются редко.
Как это работает
OAuth 2.0 описывает не один поток, а несколько — они называются grant types (типы получения токена). Самый распространённый и важный — Authorization Code Grant с PKCE. Разберём именно его, остальные — упомяну в конце.
Сценарий: ты сидишь на сайте AnalyticsTool (это клиент), он хочет читать твою Яндекс.Метрику.
Шаг 0 — заранее: разработчик AnalyticsTool пошёл к Яндексу, зарегистрировал приложение, получил пару client_id (публичный — что-то вроде «привет, я приложение №12345») и client_secret (секретный — пароль приложения, которым оно подтверждает, что это действительно оно). Указал redirect_uri — куда возвращать пользователя после согласия (https://analyticstool.example/oauth/callback).
Шаг 1 — отправка пользователя на согласие. Ты на AnalyticsTool жмёшь «Подключить Яндекс.Метрику». Клиент перенаправляет тебя в браузере на:
https://oauth.yandex.ru/authorize?
response_type=code&
client_id=ABC123&
redirect_uri=https://analyticstool.example/oauth/callback&
scope=metrika:read&
state=xyz789&
code_challenge=...&
code_challenge_method=S256
Тут важные параметры. response_type=code — «верни мне authorization code» (это «однократная купонная бумажка», а не сам токен). scope — какие права просит клиент. state — случайная строка от клиента, защита от CSRF (клиент потом проверит, что state в ответе тот же). code_challenge — кусок PKCE-защиты, расскажу через секунду.
Шаг 2 — Яндекс показывает экран согласия. Это та самая страница «AnalyticsTool хочет получить доступ: чтение данных Метрики». Если ты не залогинен в Яндекс — сначала логин. Если залогинен — сразу видишь список прав и кнопки «Разрешить»/«Отказать».
Шаг 3 — редирект обратно с authorization code. Жмёшь «Разрешить» — Яндекс делает 302-редирект в твоём браузере:
https://analyticstool.example/oauth/callback?code=TEMP_CODE_qwe123&state=xyz789
TEMP_CODE_qwe123 — это authorization code. Жив ~10 минут, использовать можно один раз.
Шаг 4 — клиент меняет код на токен. AnalyticsTool сервер (не браузер!) делает прямой POST на https://oauth.yandex.ru/token:
POST /token HTTP/1.1
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code
&code=TEMP_CODE_qwe123
&client_id=ABC123
&client_secret=SECRET_SAUCE
&redirect_uri=https://analyticstool.example/oauth/callback
&code_verifier=...
Это уже не в браузере, а сервер-к-серверу. Здесь клиент доказывает, что это действительно он (client_secret), и присылает code_verifier — вторую часть PKCE.
Шаг 5 — Яндекс возвращает токены.
{
"access_token": "y0_AgAAAAA...",
"token_type": "bearer",
"expires_in": 31536000,
"refresh_token": "1::..."
}
access_token — главный артефакт, его клиент будет прикладывать к запросам. expires_in — секунд до истечения (в этом примере — год; у Яндекса так и есть, у Google access_token обычно живёт час). refresh_token — выдаётся, чтобы потом получить новый access без участия пользователя.
Шаг 6 — клиент пользуется токеном.
GET https://api-metrika.yandex.net/management/v1/counters
Authorization: OAuth y0_AgAAAAA...
Технически правильно Authorization: Bearer ..., но Яндекс исторически принимает OAuth ... — это легаси с тех времён, когда они начинали с черновика стандарта.
Шаг 7 — токен умер, обновляемся. Через год (или через час, у разных сервисов по-разному) клиент получит:
{"errors":[{"error_type":"invalid_token","message":"Invalid oauth_token"}],"code":403}
Тогда клиент идёт обновлять — POST с grant_type=refresh_token&refresh_token=.... Если refresh жив (а он живёт ещё дольше) — выписывают новый access. Если и refresh умер — придётся вести пользователя через весь поток заново.
Что такое PKCE и зачем. PKCE (произносят «пикси», Proof Key for Code Exchange) — защита от перехвата authorization code. Клиент перед шагом 1 генерирует случайный code_verifier, хэширует его в code_challenge и отправляет challenge в запросе авторизации. Через несколько шагов, обменивая код на токен, присылает verifier. Сервер проверяет, что SHA256(verifier) == challenge. Если кто-то перехватил код посередине (например, через зловредную apk на телефоне) — без verifier'а ему ничего не светит. С 2024-го PKCE — обязательная практика для всех типов клиентов, не только мобильных.
Другие grant types (коротко):
- Client Credentials — машина-к-машине, без пользователя. Клиент сам себе токен выписывает по своим credentials. Используется, когда сервис ходит в сервис от своего имени.
- Refresh Token Grant — обновление, как описано выше.
- Resource Owner Password Credentials — клиент сам собирает у пользователя пароль и отдаёт на сервер. Считается антипаттерном, OAuth 2.1 его выкидывает.
- Implicit Grant — упрощённый поток для браузера, без code-step. Дырявый по умолчанию (access_token виден в URL), OAuth 2.1 тоже выкидывает. Заменён на Authorization Code + PKCE даже для SPA.
- Device Code — для устройств без браузера (телевизоры, консоли). Показывают код, ты заходишь с телефона на
device.example/codeи одобряешь.
Где встречается в обычной жизни
- «Войти через Google/ВКонтакте/Apple/Яндекс». Любая кнопка «войти через…» — это OAuth (точнее, OpenID Connect поверх OAuth). Сайт получает токен, идёт к Google за твоим email, открывает тебе сессию.
- Подключение Slack/Trello/Notion к Google Calendar. Подцепил календарь к мессенджеру — это значит, отдал ему OAuth-токен с правами на чтение событий.
- «Boosty получает доступ к вашему Telegram». Boosty хочет постить за тебя — даёт ссылку на oauth.telegram.org, ты подтверждаешь, ему прилетает токен.
- Камера смарт-телевизора. Когда ты вводишь короткий код на tv.example.com/code и подтверждаешь на телефоне — это Device Flow OAuth.
- Подключение банка к приложению учёта расходов. В Европе по PSD2 банки обязаны открывать данные клиентам — через OAuth. Tinkoff/Сбер делают похоже.
Где встречается в IT и бизнесе
- Любая «интеграция со сторонним сервисом», где есть пользовательские данные. Сюда попадает абсолютное большинство SaaS-интеграций.
- Маркетинговые API: Я.Метрика, Я.Директ, Google Analytics, Facebook Ads, AppsFlyer. Все они выдают пользовательские данные через OAuth — потому что у пользователя есть свой кабинет и нужно ходить от его имени.
- SSO для сотрудников. «Войти в Jira через корпоративный Google Workspace» — это OAuth/OIDC. Сэкономил часы IT-поддержки на сбросах паролей.
- Партнёрские интеграции в маркетплейсах. Wildberries, Ozon, Avito выдают партнёрам OAuth-токены, чтобы те загружали товары или скачивали отчёты от лица селлера.
- Платёжные системы. Когда сервис подписки умеет «привязать карту через Apple Pay/Google Pay» — внутри есть OAuth-like обмен токенами.
Кто пользуется
OAuth 2.0 — фактический стандарт интернета. По данным Authlete (одна из компаний, продающих OAuth-инфраструктуру), на 2023 год протокол поддерживают практически все крупные интернет-сервисы: Google, Microsoft, Apple, Facebook/Meta, Amazon, GitHub, GitLab, Atlassian, Slack, Notion, Figma, Adobe, Spotify, Twitter/X, Reddit, LinkedIn, Salesforce, Zoom — продолжать можно очень долго.
В России: Яндекс (oauth.yandex.ru), VK (oauth.vk.com), Сбер (sber id), Mail.ru. Mos.ru, Госуслуги выдают свои OAuth-токены — на них завязана половина государственных интеграций.
Масштабы — миллиарды токенов в день. Только Google отдаёт оценочно сотни миллионов access_token'ов в сутки своим OAuth-приложениям (точную цифру публично они не называют). На рынке есть отдельные продукты, которые ничего, кроме OAuth, не делают: Auth0 (куплен Okta в 2021 за 6,5 млрд $), Stytch, FusionAuth, отечественные Keycloak (Red Hat / опенсорс), Ory Hydra.
Альтернативы и конкуренты
SAML 2.0. Корпоративный стандарт делегированной аутентификации на XML. Плюсы: десятилетняя зрелость, поддержка enterprise SSO-решений (Okta, OneLogin, ADFS). Минусы: тяжёлый XML, нерасчитан на мобильные клиенты, сложно отлаживать.
API-ключи. Простая строка, обычно навсегда. Плюсы: дёшево и просто, отлично для server-to-server. Минусы: нет понятия «пользовательский контекст», нет короткого срока жизни, нет scope'ов.
JWT + кастомная авторизация. Многие сервисы выпускают свои JWT и обходятся без OAuth-фреймворка вообще. Плюсы: меньше зависимостей, полный контроль. Минусы: придётся самому изобретать всё, что в OAuth уже придумано (отзыв токена, обновление, scope, согласие).
Magic-links / Passkeys / WebAuthn. Это про вход, а не делегирование. Часто их кладут поверх OAuth-инфраструктуры как способ аутентификации внутри Authorization Code Flow.
Когда НЕ стоит использовать
- Когда нет пользователя. Если бэкенд А ходит в бэкенд Б, никакого «согласия пользователя» давать не от чьего лица. Тут проще API-ключ или Client Credentials Grant, а полноценный пользовательский OAuth-флоу избыточен.
- Когда тебе нужна только аутентификация, не делегирование. «Узнать, что это Паша» лучше делать через OpenID Connect (он надстройка над OAuth, специально под это). Чистый OAuth для аутентификации — это известный антипаттерн, описанный в спецификации OIDC. Можно по чужому токену не узнать пользователя, а узнать «кому-то была выдана какая-то бумажка».
- Когда вся система — внутри одной компании и под твоим контролем. OAuth оптимизирован под межсервисный мир, где Authorization Server и Client принадлежат разным организациям. Внутри одного контура часто избыточен — простой session cookie дешевле и понятнее.
Грабли с токенами в публичных репозиториях
OAuth-токен — это bearer, «на предъявителя». Если он попал в публичный гитхаб, gist, скриншот в чате — считай, его уже скачали боты. GitHub секрет-сканнер автоматически уведомляет Google/Slack/Stripe о найденных в коде токенах, и они часто отзывают токен сами. Но не все провайдеры это делают. Перед коммитом — проверь, что токен идёт через переменную окружения, не через хардкод.
Связанные понятия
- OpenID Connect (OIDC) — надстройка над OAuth 2.0, добавляющая аутентификацию через id_token (JWT с claims о пользователе).
- JWT (JSON Web Token) — формат токена: подписанный JSON с метаданными. Часто, но не всегда, используется как формат access_token в OAuth.
- PKCE — расширение OAuth, обязательное в OAuth 2.1, защита от перехвата authorization code на мобильных и SPA.
- Bearer Token — токен «на предъявителя»: кто его держит — тот и пользуется. Большинство OAuth access_token'ов именно такие.
- scope — строка-описание разрешения (например,
metrika:read,email,repo). Что именно разрешено сделать с токеном. - SSO (Single Sign-On) — общая практика «вошёл один раз — пользуешься многими сервисами», часто реализуется на OAuth/OIDC или SAML.
Литература и источники
- RFC 6749 «The OAuth 2.0 Authorization Framework» — основной документ. Англ., 2012. На сайте IETF:
datatracker.ietf.org/doc/html/rfc6749. Читается тяжело, но один раз нужно. - RFC 7636 «PKCE» — короткий и понятный, читается за полчаса.
datatracker.ietf.org/doc/html/rfc7636. - OAuth 2.0 Simplified (Aaron Parecki) — книга и сайт
oauth.net/2/. Англ., самое доступное введение, поддерживается одним из соавторов современных RFC. - «OAuth 2.0 and the Road to Hell» (Eran Hammer, 2012) — пост о причинах выхода из рабочей группы. Полезно прочесть, чтобы понимать критику. Искать в Google по названию.
- Документация OAuth у Яндекса —
yandex.ru/dev/id/doc/ru/. Конкретный пример реализации с разбором всех типов потоков. - Видео-лекция «OAuth 2.0 and OpenID Connect (in plain English)» — Nate Barbettini, YouTube, 2018. Английский, ~1 час. Многие отмечают как лучшее объяснение для новичков.
Где встретилось у меня
Вчера разбирались с Яндекс.Метрикой. Старый OAuth-токен для одного аккаунта оказался отозванным (invalid_token, 403), пришлось искать рабочий среди переменных окружения и параллельно соображать, есть ли вообще доступ к новому счётчику. Под разговор всплывали client_id, client_secret, scope'ы и сам URL oauth.yandex.ru/authorize — то есть всё семейство понятий OAuth 2.0, с которым работает любая интеграция.
Краткое резюме
- OAuth 2.0 — стандарт делегирования доступа: «дать приложению ограниченный ключ к моим данным в другом сервисе, не отдавая пароль».
- Главный артефакт — access_token, обычно bearer, с ограниченным сроком жизни и набором прав (scope).
- Самый правильный современный поток — Authorization Code + PKCE: ты в браузере одобряешь, клиент-сервер потом меняет одноразовый code на токен.
- Не путать с аутентификацией: «кто пользователь» — это уже надстройка OpenID Connect.
- Альтернативы: SAML (корпоративный, тяжёлый), API-ключи (для сервер-к-сервер без пользователя), JWT-самопис (полный контроль ценой переизобретения колеса).