OAuth 2

Роли / Roles

Стороннее приложение: Клиент

Клиент это приложение которое пытается получить доступ к учетной записи пользователя. Для этого клиенту нужны разрешения от пользователя.

API: Сервер ресурсов

Сервер ресурсов это API сервер используемый для получения доступа к информации пользователя.

Сервер авторизации

Это сервер предоставляющий интерфейс где пользователь разрешает или запрещает запрос разрешений. В большинстве реализаций, это может быть один и тот сервер что и API. В крупных проектах это скорее всего будет отдельный сервер.

Пользователь, владелец ресурса

Владелец ресурса это реальный пользователь, который выдает доступ к части своей информации.

Создание приложения

В начале использования OAuth процесса, вы должны зарегистрировать новое приложение в сервисе. При регистрации обычно определяется общая информация, такая как название, сайт, логотип и т.д. Дополнительно необходимо указать  URI перенаправления, который будет использован для перенаправления пользователей на веб-сервер, браузер или мобильное приложение.

Redirect URIs

Сервис только перенаправляет пользователей на зарегистрированный URI, чтобы уменьшить риск некоторых атак. Любое HTTP перенаправление должно выполняться через HTTPS. Это защищает токены от перехвата во время процесса авторизации. Нативные приложения могут регистрировать URI перенаправления используя собственную URL схему для приложения, которая может выглядеть так demoapp://redirect.

Client ID, Secret

После регистрации приложения, будут получены идентификатор клиента Client ID (UID) и секрет (secret). Client ID это публичный информация, и используется открыто для формирования URL, или включения в JavaScript-код приложения на странице. Secret должен сохраняться в тайне и не передаваться в публичный доступ. Если приложение не имеет возможности хранить Secret в безопасности, например это SPA-страница, или нативные приложения, то Secret не используется, и в идеале секрет не должен выдаваться для таких приложений.

Авторизация

Первый шаг это запрос авторизации от пользователя. Для браузерных и мобильных приложений это обычно интерфейс предоставляемый сервисом.

OAuth 2  предоставляет несколько типов разрешений для разных случаев применения

  • Authorization Code для приложений выполняемых в браузере, основанных на браузерных технологиях  и мобильных приложений
  • Password для входа с именем пользователя и паролем ((only for first-party apps)
  • Client credentials для приложений без ассоциации с пользователем
  • Implicit - ранее этот тип был рекомендован для клиентов без Secret, но был заменен на способ предоставления кода авторизации PKCE.

Web Server Apps

Серверные веб-приложения основной тип приложений для работы с OAuth. Приложения написаны на серверных языках и выполняются на сервере, где исходный код не доступен публично. Что значит приложение может использовать Client Secret для коммуникации с сервером авторизации.

Авторизация

Ссылка "Войти"

https://auth.server/oauth/authorize?response_type=code&client_id=CLIENT_ID&redirect_uri=REDIRECT_URI&scope=user&state=1234x
  • response_code=code - указывает, что сервер должен вернуть код авторизации
  • client_id - идентификатор приложения, которое мы создали в сервисе
  • redirect_uri - URL куда направить пользователя после завершения авторизации
  • scope - область доступа
  • state - случайная строка

Сервис должен отобразить диалог, с возможностью выбора предоставить доступ или отказать. Если пользователь предоставляет доступ, сервис перенаправляет пользователя обратно на сайт с кодом авторизации

https://my.app/callback?code=AUTH_CODE&state=1234x
  • code - код авторизации
  • state - строка из запроса авторизации

Мы должны проверить state чтобы убедиться что это "наш" запрос, мы его инициировали. Обычно значение state сохраняется в cookie или сессии, и сравнивается после получения ответа. Это создает гарантию, что точку перенаправления нельзя обмануть отправляя произвольными кодами авторизации.

Получение токена доступа

Для получения токена отправляем POST запрос, указывая полученный код авторизации

POST https://auth.server/oauth/token
grant_type=authorization_code&
code=AUTH_CODE&
redirect_uri=REDIRECT_URI&
client_id=CLIENT_ID&
client_secret=CLIENT_SECRET
  • grant_type=authorization_code - тип
  • code=AUTH_CODE - код, полученный от сервера авторизации
  • redirect_uri=REDIRECT_URI - должен соответствовать URI указанному в настройка приложения в сервисе
  • client_id=CLIENT_ID - идентификатор приложения в сервисе
  • client_secret=CLIENT_SECRET - так как запрос отправляется на стороне сервере, можем включить секрет

Сервер ответит

{
  "access_token": "Jjhg65HKL8097ghgfYU",
  "expires_in": 7200
}

Или ошибкой

{
  "error":"invalid_request"
}

Single-Page Apps (SPA)

SPA приложения работаю полностью в контексте браузера, после того как код приложения будет загружен с сервера. Код полностью доступен на стороне браузера, что означает отсутствие возможности сохранить конфиденциальные данные, пароли, коды и т.д. Использование Secret невозможно. Поток авторизации основан на потоке с кодом авторизации, но с добавлением динамически генерируемых секретов для каждого запроса. Также известно как PKCE расширение.

Ранее. для подобных случаев рекомендовалось использовать implicit поток, который возвращал токен доступа сразу в перенаправлении и не имел шага получения токена. Сейчас рекомендуется использовать поток с кодом авторизации без использования секрета.

Авторизация

Создать случайную строку длиной 43-128 символов, затем сгенерировать url-безопасный base64 SHA256 хеш на основе этой строки. Оригинальная строка будет называться code_verifier, в хеш версия code_challenge

Например, строка, code_verifier

5d2309e5bb73b864f989753887fe52f79ce5270395e25862da6940d5

Hash, SHA256, base64-encoded, code_challenge

MChCW5vD-3h03HMGFZYskOSTir7II_MMTb8a9rJNhnI

Строка входа будет такой

https://auth.server/oauth/authorize?response_type=code&client_id=CLIENT_ID&redirect_uri=REDIRECT_URI&scope=user&state=123x&code_challenge=CODE_CHALLENGE&code_challenge_method=S256
  • response_type=code - сервер должен возвратить код авторизации
  • client_id - ID приложения
  • redirect_uri - адрес перенаправления
  • scope - область доступа
  • state - случайная строка для проверки запроса
  • code_challenge - хеш, основанный на случайной строке, временный секрет
  • code_challenge_method - метод хеширования

При выдаче пользователем разрешения на доступ, редирект будет таким

https://my.app/callback?code=AUTH_CODE&state=123x

После проверки идентичности state, можно запросить токен.

Получение токена доступа

Теперь отправляем POST запрос с  кодом авторизации, но добавляем в  параметры вместо секрета приложения, PKCE секрет, созданный ранее

POST https://auth.server/oauth/token
grant_type=authorization_code&
code=AUTH_CODE&
redirect_uri=REDIRECT_URI&
client_id=CLIENT_ID&
code_verifier=CODE_VERIFIER

Здесь CODE_VERIFIER - это секрет созданные нами в самом начале. Сервер преобразует CODE_VERIFIER в hash и сравнит с кодом отправленным ранее.

Мобильные приложения

Так же как и приложения в браузере, мобильные приложения не могут обеспечить конфиденциальность при сохранение секрета приложения. Поэтому безопасное использование секрета невозможно.

Авторизация

Следует направить пользователя либо в нативное приложение сервиса на телефоне, либо на мобильную страницу сервиса. Приложение может регистрировать нестандартную схему например my-app://, чтобы запускалось нативное приложение.

Например если установлено приложение Facebook, адрес авторизации может быть таким

fbauth2://autorize?response_type=code&client_id=ID&redirect_uri=URI&scope=email&state=123x

Другие типы

Password

OAuth предлагает использовать имя пользователя и пароль напрямую для получения токена доступа. В данном случае приложение напрямую получает учетные данные пользователя, а значит такой подход должен использоваться только приложениями создаваемыми сервисом, являющимися часть сервиса. Для примера, нативное приложение для Twitter может использовать тип password для  входа пользователей на мобильных и десктоп приложениях.

Для получения токена достаточно отправить простой POST запрос

POST https://aut.server/oauth/token
grant_type=password&
username=USERNAME&
password=PASSWORD&
client_id=CLIENT_ID
  • grant_type=password - тип
  • username=USERNAME - реальное имя пользователя
  • password=PASSWORD - реальный пароль пользователя
  • client_id=CLIENT_ID - идентификатор приложения в сервисе

Сервер пришлет в ответе токен доступа.

{
  "access_token": "Jjhg65HKL8097ghgfYU",
  "expires_in": 7200
}

Здесь также Client Secret не включен в запрос, предполагая что основные области использования потока password это мобильные и веб-приложения, где безопасно хранить Secret возможности нет.

Доступ приложений

В некоторых случаях, приложениям нужен  токен доступа для работы от своего имени, а не от имени пользователя. Например для сбора статистики или обновления своих настроек. Для подобных случаев используется поток client_credentials

POST https://auth.server/oauth/token
grant_type=client_credentials&
client_id=CLIENT_ID&
client_secret=CLIENT_SECRET

В данном случае подразумевается, что запросы выполняются на стороне сервера.

Запросы

После получения токена можно выполнять запросы к защищенным данным

curl -H 'Authorization: Bearer <TOKEN>' \
https://api.server/api/v1/me

Все запросы должны выполняться посредством https, чтобы исключить перехват токена и подмену.