В этой статье рассмотрим историю возникновения и схему работы. Разберемся в чем отличие OAuth 2.0 от OpenID Connect и что такое SSO.
История возникновения OAuth
Авторизацией через социальные сети никого уже не удивишь. Нажимаешь кнопку соц сети, вжух и ты авторизовался на новом сайте. Сайт получил твоё ФИО, фотку и прочие данные. Но так было не всегда.
В «каменном веке» интернета все было проще. Вы просто давали свой логин и пароль от одного сервиса другому, чтобы тот вошел в вашу учетную запись и получил любую необходимую ему информацию.
На заре становления Facebook просил у пользователей логин и пароль от Gmail аккаунта, чтобы отправить контактам приглашение. Такой подход имеет большую проблему: логин и пароль дают полный доступ к сервису. Поэтому был разработан стандарт OAuth.
С помощью этого стандарта вы позволяете приложению считать данные или использовать функции другого приложения от вашего имени, не сообщая ему свой пароль. Класс!
Главным недостатком OAuth 1.0 была слишком большая сложность данной версии.
Начнем разбор OAuth 2.0 с ролей. Всего есть 4 роли:
- Владелец ресурса.
- Клиент.
- Сервер ресурсов.
- Авторизационный сервер.
Далее мы рассмотрим каждую из ролей.
Владелец ресурса
Ресурсом являются данные, например ФИО, фотография, ваши сообщения в соц сетях, и прочее. Владелец ресурса это пользователь. При межсерверном общении владельцем ресурса может быть один из серверов.
Сервер ресурсов
На сервере ресурсов лежат ваши данные. В случае с примером выше ваши контакты Gmail это ресурс, а лежат они на серверах Gmail.
Клиент
Клиент это сервис, которому требуется доступ к вашим ресурсам. Например, Facebook требуется доступ к контактам Gmail.
Авторизационный сервер
В данном примере он принадлежит Google, так как он хранит ваши данные.
Базовая схема протокола
OAuth 2.0 основан на использовании базовых веб-технологий: HTTP-запросах, редиректах и т. п. Поэтому использование OAuth возможно на любой платформе с доступом к интернету и браузеру: на сайтах, в мобильных и desktop-приложениях, плагинах для браузеров.
Вернемся к нашему примеру про Facebook и Gmail. На анимации ниже, я постарался схематично изобразить, как реализовать этот пример правильно с помощью Oauth2. Стоит учитывать, что у Google есть свой сервер авторизации, который отвечает за авторизацию на любом сервисе Google. Поэтому Gmail только хранит ресурсы, но не отвечает за авторизацию.
Весь смысл в том, что Клиент должен получить каким-то образом от авторизационного сервера access_token
. Способов этих четыре, о них мы поговорим дальше. Используя этот access_token
Клиент может использовать его в запросах к Серверу ресурсов, чтобы получать какие-то данные.
Это строка, которая является альтернативой логину и паролю.
Особенности Access Token:
- Ограниченное время жизни.
- Его можно отозвать. Если есть подозрение, что токен украли, то мы просто запрещаем получать данные с помощью этого токена.
- Компрометация токена не значит компрометирование логина и пароля. Из токена никак не получить логин и пароль.
- По токену может быть доступна только часть данных (scope). Клиент запрашивает список разрешений, которые необходимы ему для работы, а Владелец ресурсов решает выдать такие права или нет. Например, можно выдать права только на просмотр списка контактов, тогда читать письма или редактировать контакты будет нельзя.

Помимо access_token
Авторизационный сервер может выдавать также refresh_token
. Это токен, который позволяет запросить новый access_token
без участия Владельца ресурсов. Время жизни у такого токена намного больше access_token
и его потеря гораздо серьезнее.
Вернемся к базовой схеме. Авторизационный сервер должен знать про каждого клиента, который делает к нему запрос. То есть, каждый клиент должен быть зарегистрирован. Зарегистрировав клиента мы получаем client_id
и client_secret
и обязаны передавать, как минимум client_id
в каждом запросе.
Не все клиенты могут гарантировать сохранность client_secret
, поэтому он есть не у всех. Например, SPA без бэкенда, теоретически достать оттуда можно что угодно.
Существует возможность регистрировать клиентов динамически: RFC 7591 и RFC 7592.
Способы получения Access Token
Всего есть 4 способа:
- По авторизационному коду (Authorization Code Grant). Самый сложный и самый надежный способ.
- Неявно (Implicit)
- По логину и паролю пользователя (Resource Owner Password Credential). Только для безопасных клиентов, заслуживающих полного доверия.
- По данным клиента (Client Credentials). Получаем токен по
client_id
иclient_secret
.
Client Credentials
Начнем разбор с самой простой схемы. Этот способ придуман для межсерверного взаимодействия. У нас есть два сервера API1 и API2, и им надо как-то общаться.

- API 1 идет в авторизационный сервер передает туда
client_id
иclient_secret
.
curl --request POST \
--url 'https://YOUR_DOMAIN/oauth/token' \
--header 'content-type: application/x-www-form-urlencoded' \
--data grant_type=client_credentials \
--data client_id=YOUR_CLIENT_ID \
--data client_secret=YOUR_CLIENT_SECRET \
--data audience=YOUR_API_IDENTIFIER
2. Взамен API 1 получает access_token
, с помощью которого может обратиться к API 2.
{
"access_token": "eyJz93a...k4laUWw",
"token_type": "Bearer",
"expires_in": 86400
}
3. API 1 обращается к API 2.
curl --request GET \
--url https://api2.com/api \
--header 'authorization: Bearer ACCESS_TOKEN' \
--header 'content-type: application/json'
4. API 2 получает запрос с access_token
и обращается к авторизационному серверу для проверки действительности переданного токена (RFC 7662).
Resource Owner Password Credential
- Владелец ресурсов передает свой логин и пароль Клиенту.
- Клиент отправляет Авторизационному серверу логин и пароль клиента, а так же свой
client_id
иclient_secret
.
curl -d "grant_type=password" \
-d "client_id=3MVG9QDx8IKCsXTFM0o9aE3KfEwsZLvRt" \
-d "client_secret=4826278391389087694" \
-d "username=ryan%40ryguy.com" \
-d "password=_userspassword__userssecuritytoken_" \
https://as.com/oauth2/token
3. Если предоставленные пользователем учетные данные успешно аутентифицированы, сервер авторизации вернет ответ application/json
, содержащий access_token
:
{
"id":"https://as.com/id/00DU0000000Io8rMAC/005U0000000hMDCIA2",
"issued_at":"1316990706988",
"instance_url":"https://na12.salesforce.com",
"signature":"Q2KTt8Ez5dwJ4Adu6QttAhCxbEP3HyfaTUXoNI=",
"access_token":"00DU0000000Io8r!AQcKbNiJPt0OCSAvxU2SBjVGP6hW0mfmKH07QiPEGIX"
}
Authorization Code Grant
Является одним из наиболее распространённых типов разрешения, поскольку он хорошо подходит для серверных приложений, где исходный код приложения и секрет клиента не доступны посторонним.
- Пользователь на сайте нажимает кнопку авторизации, например через Facebook.
- Происходит редирект на авторизационный сервер.
- Если активной сессии нет, то Пользователь должен залогиниться. Если активная сессия есть, то просто подтвердить авторизацию.
Пример авторизационного запроса
https://YOUR_DOMAIN/authorize
?response_type=code
&client_id=YOUR_CLIENT_ID
&redirect_uri=https://YOUR_APP/callback
&scope=SCOPE
&audience=API_AUDIENCE
&state=STATE
response_type
- Обозначает тип учетных данных, которые возвращает авторизационный сервер. Для этого способа значение должно бытьcode
.redirect_uri
- URL-адрес, на который авторизационный сервер будет перенаправлять браузер после авторизации пользователя. Код авторизации будет доступен в параметреcode
.
В настройках Авторизационного сервера можно настроить url адреса, на которые разрешен редирект.
4. Если все пойдет хорошо, вы получите ответ HTTP 302. Код авторизации включен в конце URL-адреса: в параметре ?code=SplewFEFofer
HTTP/1.1 302
Found Location: https://YOUR_APP/callback?code=AUTHORIZATION_CODE&state=xyzABC123
Так как code
попадает в браузер и ничем не защищен, то это точка уязвимости. Поэтому на авторизационный код накладываются следующие ограничения:
- Код одноразовый
- Время жизни кода очень мало
5. Теперь, когда у вас есть код авторизации, вы должны обменять его на токены. Используя извлеченный код авторизации из предыдущего шага, вам нужно будет выполнить POST на URL-адрес токена.
curl --request POST \
--url 'https://YOUR_DOMAIN/oauth/token' \
--header 'content-type: application/x-www-form-urlencoded' \
--data 'grant_type=authorization_code' \
--data 'client_id=YOUR_CLIENT_ID' \
--data 'client_secret=YOUR_CLIENT_SECRET' \
--data 'code=YOUR_AUTHORIZATION_CODE' \
--data 'redirect_uri=https://YOUR_APP/callback'
6. Если все пойдет хорошо, вы получите ответ HTTP 200 с полезной нагрузкой, содержащей значения access_token
, refresh_token
, id_token
и token_type
:
{
"access_token": "eyJz93a...k4laUWw",
"refresh_token": "GEbRxBN...edjnXbL",
"id_token": "eyJ0XAi...4faeEoQ",
"token_type": "Bearer"
}
7. Чтобы вызвать ваш API из обычного веб-приложения, приложение должно передать полученный токен доступа в заголовке авторизации вашего HTTP-запроса.
curl --request GET \
--url https://myapi.com/api \
--header 'authorization: Bearer ACCESS_TOKEN' \
--header 'content-type: application/json'
Implicit Grant
Теперь у нас сайт без бэкенда - SPA.
- Пользователь на сайте жмет на кнопку, происходит редирект на сервер авторизации.
- Пользователь вводит логин пароль, если он не авторизован.
- Происходит редирект обратно, но
access_token
возвращается в URL сразу:https://domain.com/back_path#access_token=8ijfwWEFFf0wefOofreW6rglk
.
Адресная строка никак не шифруется, а так как access_token
попадает в адресную строку, то существует множество способов его перехватить. Например, провайдер видит все адреса, по которым вы переходите.
При использовании схемы Code Grant вы передаете токен в куке. Куки передаются в заголовке запроса. При использовании https соединения, заголовки шифруются. Поэтому достать токен из куки при передаче невозможно.
OpenID Connect
OAuth 2.0 разработан только для авторизации — для предоставления доступа к данным и функциям от одного приложения другому. OpenID Connect (OIDC) — это тонкий слой поверх OAuth 2.0, добавляющий сведения о логине и профиле пользователя, который вошел в учетную запись.
OpenID Connect позволяет реализовывать сценарии, когда единственный логин можно использовать во множестве приложений, — этот подход также известен как single sign-on (SSO)
Поток (flow) OpenID Connect выглядит так же, как и в случае OAuth 2.0. Единственная разница в том, что в первичном запросе используемый конкретный scope
— openid, — а Клиент в итоге получает как access_token
, так и id_token
.
ID Token — это особым образом отформатированная строка символов - JSON Web Token или JWT. Сторонним наблюдателям JWT может показаться непонятной абракадаброй, однако Клиент может извлечь из JWT различную информацию, такую как ID, имя пользователя, время входа в учетную запись, срок окончания действия ID Token’а, наличие попыток вмешательства в JWT.

В случае OIDC также имеется стандартный способ, с помощью которого Клиент может запросить дополнительную информацию о пользователе от Сервера авторизации, например, адрес электронной почты, используя access_token
.
Заключение
Подведем итог. OAuth 2.0 это простой протокол авторизации, основанный на HTTP, что дает возможность применять его практически на любой платформе. Он имеет хорошую документацию, и большинство крупных площадок его поддерживают. Так что если вы решили использовать этот протокол в своем проекте — это хороший выбор.