Token id что это
Перейти к содержимому

Token id что это

  • автор:

Как работает OAuth 2.0 и OpenID Connect

OAuth 2.0 — протокол авторизации, позволяющий выдать одному сервису (приложению) права на доступ к ресурсам пользователя на другом сервисе. Протокол избавляет от необходимости доверять приложению логин и пароль, а также позволяет выдавать ограниченный набор прав, а не все сразу.

Как работает OAuth 2.0 и OpenID Connect

В этой статье рассмотрим историю возникновения и схему работы. Разберемся в чем отличие OAuth 2.0 от OpenID Connect и что такое SSO.

История возникновения OAuth

Авторизацией через социальные сети никого уже не удивишь. Нажимаешь кнопку соц сети, вжух и ты авторизовался на новом сайте. Сайт получил твоё ФИО, фотку и прочие данные. Но так было не всегда.

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

На заре становления Facebook просил у пользователей логин и пароль от Gmail аккаунта, чтобы отправить контактам приглашение. Такой подход имеет большую проблему: логин и пароль дают полный доступ к сервису. Поэтому был разработан стандарт OAuth.

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

OAuth 1.0 не используется. Забудьте о нем. Используйте OAuth 2.0

Главным недостатком 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, и им надо как-то общаться.

  1. API 1 идет в авторизационный сервер передает туда client_id и client_secret .

2. Взамен API 1 получает access_token , с помощью которого может обратиться к API 2.

3. API 1 обращается к API 2.

4. API 2 получает запрос с access_token и обращается к авторизационному серверу для проверки действительности переданного токена (RFC 7662).

Resource Owner Password Credential

  1. Владелец ресурсов передает свой логин и пароль Клиенту.
  2. Клиент отправляет Авторизационному серверу логин и пароль клиента, а так же свой client_id и client_secret .

3. Если предоставленные пользователем учетные данные успешно аутентифицированы, сервер авторизации вернет ответ application/json , содержащий access_token :

Authorization Code Grant

Является одним из наиболее распространённых типов разрешения, поскольку он хорошо подходит для серверных приложений, где исходный код приложения и секрет клиента не доступны посторонним.

  1. Пользователь на сайте нажимает кнопку авторизации, например через Facebook.
  2. Происходит редирект на авторизационный сервер.
  3. Если активной сессии нет, то Пользователь должен залогиниться. Если активная сессия есть, то просто подтвердить авторизацию.

Пример авторизационного запроса

  • response_type — Обозначает тип учетных данных, которые возвращает авторизационный сервер. Для этого способа значение должно быть code .
  • redirect_uri — URL-адрес, на который авторизационный сервер будет перенаправлять браузер после авторизации пользователя. Код авторизации будет доступен в параметре code .

4. Если все пойдет хорошо, вы получите ответ HTTP 302. Код авторизации включен в конце URL-адреса: в параметре ?code=SplewFEFofer

Так как code попадает в браузер и ничем не защищен, то это точка уязвимости. Поэтому на авторизационный код накладываются следующие ограничения:

  • Код одноразовый
  • Время жизни кода очень мало

5. Теперь, когда у вас есть код авторизации, вы должны обменять его на токены. Используя извлеченный код авторизации из предыдущего шага, вам нужно будет выполнить POST на URL-адрес токена.

6. Если все пойдет хорошо, вы получите ответ HTTP 200 с полезной нагрузкой, содержащей значения access_token , refresh_token , id_token и token_type :

7. Чтобы вызвать ваш API из обычного веб-приложения, приложение должно передать полученный токен доступа в заголовке авторизации вашего HTTP-запроса.

Implicit Grant

Теперь у нас сайт без бэкенда — SPA.

  1. Пользователь на сайте жмет на кнопку, происходит редирект на сервер авторизации.
  2. Пользователь вводит логин пароль, если он не авторизован.
  3. Происходит редирект обратно, но 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, что дает возможность применять его практически на любой платформе. Он имеет хорошую документацию, и большинство крупных площадок его поддерживают. Так что если вы решили использовать этот протокол в своем проекте — это хороший выбор.

Идентификационный токен и токен доступа: в чем разница?

«Давайте воспользуемся токеном для защиты вызова API. Что мне использовать: ID-токен или Access токен? ID токен мне кажется предпочтительнее. В конце концов, если я знаю, кто является пользователем, я могу принимать более обоснованные решения об авторизации, верно?»

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

«Что в конце концов изменится? Это всего лишь токены. Я могу использовать их по своему усмотрению. Что такого плохого может случиться?»

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

Что такое идентификационный токен?

ID токен — это артефакт, подтверждающий, что пользователь прошел аутентификацию. Он был представлен OpenID Connect (OIDC), открытым стандартом аутентификации, используемым многими системами идентификации такими, как Google, Facebook и, конечно же, Auth0. Ознакомьтесь с этим документом для получения дополнительных сведений об OpenID Connect. Давайте кратко рассмотрим проблему, которую призван решить OIDC.

Рассмотрим следующую схему:

Здесь пользователь со своим браузером аутентифицируется через провайдер OpenID и получает доступ к веб-приложению. Результатом процесса аутентификации на основе OpenID Connect является ID токен, который передается приложению в качестве доказательства того, что пользователь прошел аутентификацию.

Подтверждение аутентификации пользователя это всего лишь базовое представление об ID токене. Рассмотрим это подробнее.

Идентификационный токен JSON Web Token (JWT) — стандартный формат, который позволяет вашему приложению легко проверить его содержимое и убедиться, что оно исходит от ожидаемого эмитента и что никто другой его не менял. Если вы хотите узнать больше о JWT, посмотрите «The JWT Handbook».

Проще говоря, пример ID токена выглядит так:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwOi8vbXktZG9tYWluLmF1dGgwLmNvbSIsInN1YiI6
ImF1dGgwfDEyMzQ1NiIsImF1ZCI6IjEyMzRhYmNkZWYiLCJleHAiOjEzMTEyODE5NzAsImlhdCI6MTMxMTI4MDk3MCwibm
FtZSI6IkphbmUgRG 9lIiwiZ2l2ZW5fbmFtZSI6IkphbmUiLCJmYW1pbHlfbmFtZSI6IkRvZSJ9

Конечно, просто «на глазок» это не прочесть, поэтому вам нужно расшифровать его, чтобы увидеть, какой контент содержит JWT. Между прочим, ID токен не зашифрован, а закодирован только в Base 64. Вы можете использовать одну из множества доступных библиотек для его декодирования или самостоятельно проверить его с помощью сайта jwt.io.

Не вдаваясь в подробности, соответствующая информация, содержащаяся в указанном выше ID токене, выглядит следующим образом:

Эти свойства JSON называются «claims (заявки)», и они представляют собой заявления о пользователе и самом токене. Заявки о пользователе позволяют определить его личность.

Фактически, спецификации OpenID Connect не требуют, чтобы ID токен содержал заявку о пользователе. В своей минимальной структуре он содержит данные только для аутентификации.

Одним из важных требований является «aud» заявка. Оно определяет получателя, то есть веб-приложение, которое должно быть конечным получателем токена. В случае с использованием ID токена, значением «aud» будет Client ID приложения, которое должно использовать токен.

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

Идентификационный токен может содержать дополнительную информацию о пользователе: адрес его электронной почты, фотографию, день рождения и т. д.

Наконец, возможно, самое важное: ID токен подписывает эмитент своим закрытым ключом. Для вас это гарантия происхождения токена и того, что он не был подделан. Это можно проверить, используя открытый ключ эмитента.

Здорово! Теперь вы знаете, что такое идентификационный токен. Но что вы можете с ним делать?

Во-первых, он демонстрирует, что пользователь был аутентифицирован организацией, которой вы доверяете (провайдер OpenID), и поэтому вы можете доверять его личным данным.

Кроме того, ваше приложение может персонализировать взаимодействие с пользователями, используя данные о пользователе, включенные в ID токен. Например, вы можете показать имя в пользовательском интерфейсе или отобразить сообщение «С наилучшими пожеланиями» в день рождения. Самое интересное в том, что вам не нужно делать дополнительных запросов, поэтому вы можете немного повысить производительность своего приложения.

Что такое токен доступа?

Теперь, когда вы знаете, что такое идентификационный токен, давайте попробуем понять, что такое Access токен.

Начнем с описания сценария, в который вписывается токен доступа:

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

В контексте OAuth 2 Access токен позволяет клиентскому приложению получать доступ к определенному ресурсу для выполнения определенных действий от имени пользователя. Что известно как сценарий делегированной авторизации: пользователь делегирует клиентскому приложению доступ к ресурсу от своего имени. Это значит, например, что вы можете от своего имени разрешить приложению LinkedIn доступ к API Twitter для перекрестной публикации на обеих социальных платформах. Заметьте, что вы разрешаете LinkedIn только публиковать свои сообщения в Twitter. Вы не разрешаете ему удалять их, изменять данные вашего профиля или делать что-то еще. Это ограничение очень важно в сценарии делегированной авторизации и достигается с помощью областей действия, или scopes. Области действия — это механизм, позволяющий пользователю авторизовать стороннее приложение для выполнения только определенных операций.

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

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

В спецификации OAuth 2 ничего не говорится о формате Access токена. Это может быть строка в любом формате. Распространенным форматом, используемым для токенов доступа, является JWT, и на данный момент этот стандарт в разработке. Однако это не значит, что Access токены должны быть именно в этом формате.

Хорошо! Теперь вы знаете, что такое ID-токен и Access токен. Итак, вы готовы использовать их, не боясь ошибиться. Но подождите. Мне кажется, вы не уверены. Возможно, вам нужна другая информация. Ok. Итак, давайте посмотрим, для чего эти токены не подходят.

Для чего НЕ подходит ID-токен?

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

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

Однако даже в этом сценарии безопасность вашего приложения, состоящего из клиента и API, может быть под угрозой. Фактически, не существует механизма, который привязывает ID токен к каналу клиентского API. Если злоумышленнику удастся украсть вашу «личность», он может использовать ее для вызова вашего API как законного клиента.

С другой стороны, для Acces токена существует набор методов, известных как ограничение отправителя (sender constraint), которые позволяют привязать токен доступа к определенному отправителю. Это гарантия того, что даже если злоумышленник украдет Access токен, он не сможет использовать его для доступа к вашему API, поскольку токен привязан к клиенту, который изначально его запросил.

В сценарии делегированной авторизации, когда сторонний клиент хочет вызвать ваш API, нельзя использовать ID токен для вызова API. Помимо отсутствия механизмов привязки к клиенту есть несколько других причин, по которым этого не следует делать.

Если ваш API принимает ID токен в качестве токена авторизации, вы сначала игнорируете предполагаемого получателя, указанного в aud (audience claim). В этом утверждении говорится, что он предназначен для вашего клиентского приложения, а не для сервера ресурсов (т. е. API).

Можно подумать, что это всего лишь формальность, но такой подход может повлечь за собой риски для безопасности.

Прежде всего, кроме прочих проверок, ваш API не должен принимать токен, который для него не предназначен. Если это произойдет, его безопасность окажется под угрозой. Фактически, если вашему API все равно, предназначен ли для него токен, для доступа к нему может быть использован ID токен, украденный из любого клиентского приложения, может быть использован для доступа к вашему API. Разумеется, для предотвращения несанкционированного доступа, проверка aud — это всего лишь одна из проверок, которую должен выполнять ваш API.

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

Для чего НЕ подходит Access токен?

Что касается Access токена, то он был задуман, чтобы продемонстрировать, что вы авторизованы для доступа к ресурсу, например, для вызова API.

Ваше клиентское приложение должно использовать его только с этой целью. Другими словами, Access токен не должен проверяться клиентским приложением. Он предназначен для сервера ресурсов, и клиентское приложение должно обрабатывать Access токены как непрозрачные строки, то есть строки без определенного значения. Даже если вам известен формат Access токена, не следует пытаться интерпретировать его содержимое в клиентском приложении. Как уже говорилось, формат Access токена — это соглашение между сервером авторизации и сервером ресурсов, и клиентское приложение не должно вмешиваться. Подумайте, что может случиться, если однажды формат Access токена изменится. Если ваш клиентский код (client code) проверял этот Access токен, в этом случае он будет тотчас сломан.

Краткий обзор

Путаница с использованием ID и Access токенов очень распространена, и, возможно, трудно понять различия между ними. Может быть, это в основном связано с отсутствием четкого понимания различных целей каждого артефакта, определенных в спецификациях OAuth и OpenID Connect. Кроме того, понимание сценариев, в которых изначально должны были действовать эти артефакты, играет важную роль в предотвращении путаницы при их использовании. Тем не менее, я надеюсь, что теперь эта тема немного прояснилась.

В иллюстрации кратко изложено то, что можно и чего нельзя делать с ID и Access токенами:

Авторизация и аутентификация для всех и каждого, часть 2

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

Проблема входа в систему

После того как OAuth 2.0 обеспечил возможность доступа к сторонним API, создатели приложений также захотели, чтобы их пользователи могли логиниться при помощи других аккаунтов. Возьмем пример. Скажем, приложение HireMe123 хочет, чтобы пользователь MyCalApp мог логиниться в HireMe123, используя аккаунт MyCalApp — несмотря на то, что в самом HireMe123 у него нет аккаунта.

Но, как уже говорилось, OAuth 2.0 — это про делегированный доступ. Это НЕ протокол аутентификации. Тем не менее, это не остановило людей в их попытках использовать OAuth 2.0 именно с целью аутентификации, и это породило проблемы.

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

Если HireMe123 полагает, что успешный вызов API MyCalApp при помощи токена доступа означает, что пользователь может считаться аутентифицированным в HireMe123, мы сталкиваемся с проблемами. Дело в том, что у нас нет возможности проверить, был ли токен доступа выпущен для данного человека.

  • Кто-нибудь мог украсть токен доступа другого пользователя.
  • Токен доступа мог быть получен от другого клиента (не HireMe123) и вставлен в HireMe123.

Эта проблема получила название confused deputy. HireMe123 не знает, откуда пришел токен и для кого он был выпущен. Давайте припомним: аутентификация — это проверка, действительно ли пользователь является тем, за кого себя выдает. То, что HireMe123 может использовать токен доступа для доступа к API, не дает ему оснований полагать, что пользователь действительно является тем, кем назвался.

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

OpenID Connect

Это привело нас к спецификации под названием OpenID Connect (OIDC).

OIDC это спецификация поверх OAuth 2.0, которая говорит, как аутентифицировать пользователей. Стандарты OIDC разрабатываются OpenID Foundation (OIDF).

OIDC — это слой идентификации для аутентификации пользователей при помощи сервера авторизации.

Вы помните, что сервер авторизации выпускает токены. Токены — это закодированные кусочки данных для передачи информации между разными сторонами (такими как сервер авторизации, приложение или API). В случае OIDC и аутентификации сервер авторизации выпускает ID-токены.

ID-токены

ID-токены предоставляют информацию о событии аутентификации и идентифицируют пользователя. ID-токены предназначены для клиента. Они имеют фиксированный формат, понятный для клиента: клиент может извлечь идентифицирующую информацию из токена и таким образом аутентифицировать пользователя.

OIDC декларирует фиксированный формат для ID-токенов —

JSON Web Token (JWT)

JSON Web Tokens (JWT, иногда произносится как «джот») составляются из трех URL-безопасных строковых сегментов, соединенных точками.

Заголовок JWT

Первый сегмент токена это заголовок. Он может выглядеть примерно так:

Заголовок токена это JSON-объект, содержащий алгоритм подписи и тип токена. Он зашифрован при помощи алгоритма base64Url (бинарные данные, представленные в виде текста).

В расшифрованном виде это выглядит примерно так:

Полезная нагрузка JWT

Второй сегмент токена — полезная нагрузка. Выглядеть этот сегмент может так:

Это объект JSON, содержащий заявления (claims) — предложения о пользователе и событии аутентификации. Например:

Этот сегмент тоже base64Url-зашифрован.

Крипто-сегмент

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

Получая ID-токен, клиент проверяет подпись (тоже при помощи ключа).

(При использовании асимметричного алгоритма для подписи и проверки используются разные ключи. В таком случае только у сервера авторизации есть возможность подписывать токены).

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

Заявления

Теперь, когда мы знаем анатомию JWT, давайте остановимся на заявлениях (claims) — тех самых предложениях из сегмента полезной нагрузки токена. Как следует из самого их названия, ID-токены предоставляют идентифицирующую информацию, а содержится она в заявлениях.

Заявления аутентификации

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

Среди необходимых заявлений об аутентификации в ID-токенах можно назвать:

  • iss (issuer): сторона, генерирующая JWT, т. е., сервер авторизации;
  • aud (audience): список получателей JWT. Для ID-токенов это клиентский идентификатор приложения, получающего токен;
  • exp (expiration time): время в формате Unix Time, определяющее момент, когда токен станет не валидным (expiration);
  • iat (issued at time): время выпуска ID-токена (тоже в формате Unix Time).

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

Заявления идентичности

Заявления также включают предложения о конечном пользователе. Вот несколько примеров таких заявлений:

Среди стандартных заявлений профиля в ID-токенах можно назвать:

  • sub (subject): уникальный идентификатор пользователя (указывается обязательно);
  • email ;
  • email_verified ;
  • birthdate (дата рождения).

Итак, мы прошли краткий курс по важным спецификациям (OAuth 2.0 и OpenID Connect). Теперь давайте посмотрим, как можно применить эти знания в работе.

Аутентификация при помощи ID-токенов

Давайте посмотрим, как происходит OIDC-аутентификация.

Примечание. Учитывайте, что это упрощенная схема. В зависимости от архитектуры вашей системы у вас будет несколько других потоков.

Рассмтариваемые нами сущности: браузер, приложение, запущенное в браузере, и сервер авторизации. Когда пользователь хочет войти в систему (залогиниться в приложении), это приложение отсылает запрос авторизации на сервер авторизации. Пользовательские логин и пароль проверяются сервером авторизации. Если все сходится, сервер выпускает ID-токен для приложения.

Затем клиентское приложение расшифровывает ID-токен (JWT) и проверяет его. В проверку входит проверка подписи, а также заявлений:

  • issuer ( iss ): выпущен ли токен именно тем сервером авторизации, от которого мы ждали ответа?
  • audience ( aud ): является ли наше приложение тем получателем, для которого был выпущен токен?
  • expiration ( exp ): не истек ли срок годности этого токена?
  • nonce ( nonce ): можем ли мы привязать этот токен к запросу авторизации, который мы посылали?

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

Итак, пользователь аутентифицирован. Время взаимодействовать с API.

Доступ к API при помощи токенов доступа

Выше мы уже немного поговорили о токенах доступа — когда рассматривали, как работает делегированный доступ с использованием OAuth 2.0 и серверов авторизации. Теперь давайте разберем все это подробнее. Для этого вернемся к нашему сценарию с HireMe123 и MyCalApp.

Токены доступа

Токены доступа используются для предоставления доступа к ресурсам. Благодаря токену доступа, выпущенному сервером авторизации MyCalApp, HireMe123 может получить доступ к API MyCalApp.

В отличие от ID-токенов, которые OIDC определяет как JSON веб-токены, токены доступа не имеют четко определенного формата. Они не обязательно являются JWT. Тем не менее, во многих решениях для токенов доступа все же используются JWT, потому что этот формат позволяет валидацию.

Токены доступа непрозрачны для клиента

Токены доступа предназначаются для API ресурса и важно, чтобы они были непрозрачны для клиента. Почему?

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

Доступ к API ресурса

Допустим, мы хотим использовать токен доступа для вызова API одностраничного приложения. Как это происходит?

Выше мы рассматривали процесс аутентификации. Предположим, что пользователь залогинился в наше JS-приложение в браузере. Это приложение отсылает запрос авторизации к серверу авторизации, запрашивая токен доступа для вызова API.

Затем, когда наше приложение хочет вступить во взаимодействие с этим API, мы прилагаем токен доступа к заголовку запроса, вот так:

Авторизованный запрос отсылается к API, который проверяет токен при помощи промежуточного ПО. Если все сходится, API возвращает данные (например, JSON) приложению, запущенному в браузере.

Это все хорошо, но выше мы упоминали, что OAuth решает проблему чрезмерных прав доступа. Как это происходит?

Делегирование с областью видимости

Как API узнает, какой уровень доступа нужно дать приложению? Это определяется путем установления области видимости (scopes).

Область видимости «ограничивает, что именно приложение может делать в интересах пользователя». Она не позволяет выдать права, которых у пользователя уже нет. Например, если пользователь MyCalApp не имеет права создавать новые корпоративные аккаунты, область видимости гарантирует, что HireMe123 тоже не позволит пользователю создавать новые корпоративные аккаунты.

Области видимости делегируют контроль доступа самому API или ресурсу. За соответствие областей видимости правам пользователя отвечает API.

Давайте рассмотрим это на примере.

Я использую приложение HireMe123. HireMe123 хочет получить доступ к стороннему API MyCalApp для создания события в календаре от моего имени. Приложение HireMe123 уже запросило токен доступа к MyCalApp на сервере авторизации MyCalApp. В этом токене содержится важная информация:

  • sub : (мой пользовательский ID в MyCalApp);
  • aud : MyCalAppAPI (этот токен создан для доступа к API MyCalApp);
  • scope : write:events (область видимости предполагает, что HireMe123 может использовать API для записи событий в моем календаре).

HireMe123 посылает запрос к API MyCalApp с токеном доступа в заголовке авторизации. Когда API MyCalApp получает этот запрос, он видит, что в нем установлена область видимости write:events.

Но на MyCalApp содержатся аккаунты с календарями сотен тысяч пользователей. Поэтому, чтобы убедиться, что этот запрос от HireMe123 будет касаться только моих прав создавать события в моем аккаунте, промежуточное ПО API MyCalApp должно проверить не только область видимости, но и sub — идентификатор субъекта.

В контексте делегированной авторизации области видимости обозначают, что именно приложение сможет делать от имени пользователя. Это подмножество прав пользователя в целом.

Проверка согласия

Помните, мы говорили, что сервер авторизации спрашивает пользователя HireMe123, согласен ли он разрешить HireMe123 воспользоваться правами пользователя для доступа к MyCalApp?

Этот диалог выглядит примерно так:

HireMe123 может попросить предоставить ему самые разные права, на пример:

  • write:events (запись событий)
  • read:events (чтение событий)
  • read:settings (чтение настроек)
  • write:settings (запись настроек)
  • и т. д.

В целом, следует избегать давать разрешения на чисто пользовательские действия. Области видимости предназначены для прав, делегированных приложениям. Но если ваш сервер авторизации имеет функционал для контроля доступа на основе ролей (Role-Based Access Control, RBAC), вы можете устанавливать разные области видимости для разных пользователей.

При помощи RBAC на сервере авторизации можно установить разные права для разных групп пользователей. После этого сервер авторизации при выпуске токенов доступа сможет включать в scopes указание ролей пользователей.

Итоги

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

Types of tokens in oidc and oauth

Understanding id_token, access_token and refresh_token

## OIDC, oAuth2.0, JWT, RS256, HS256, Tokens — don’t let the jargons be a barrier!

Key points

id_token

  • An id_token is a JWT — make note of that!
  • It contains claims about the identity of the user/resource owner
  • Having a valid id_token means that the user is authenticated

access_token

  • An access_token is a bearer token
  • A bearer token means that the bearer can access the resource without further identification
  • An access_token can be a JWT (see Appendix point 1.) or opaque

refresh_token

  • Are long lived opaque tokens used to obtain new access_token

Details

id_token is typically used for:

  • Stateless sessions: The presence of a valid id_token (jwt) provides information about the session. e.g. For browsers, cookies can store id_token
  • User information: The client app receives claims about the user as part of the id_token
  • Token exchange: The ID token may be exchanged for an access token at the token endpoint of an OAuth 2.0 authorization server. (see Appendix 3.)
  • Has one and only one use, i.e. to establish which resource the bearer has access to
  • The token is meant to be opaque to the client application
  • But for the resource server, the access_token maps to the scope or claims that the bearer has
  • If this is a jwt, it may contain scope as part of the token; which the resource server can verify on the fly (without introspection)

If you are looking for a practical example on how jwt are used as access_tokens, I wrote an authentication-authorization piece for graphql here: https://github.com/mannharleen/graphql-auth-implementation

The story of scopes & claims

Remember: Claims are grouped under Scope. e.g. claims ‘email’, ‘name’, ‘age’, etc. are part of the scope called ‘profile’

scope

A scope is a space separated list of identifiers that specify what access privileges are being requested by the client application

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *