Что такое openid connect
IdentityServer4. Основные понятия. OpenID Connect, OAuth 2.0 и JWT
Этим постом я хочу открыть ветку статей посвященную IdentityServer4. Начнем мы с основных понятий.
Самым перспективным на текущий момент протоколом аутентификации является OpenID Connect, а протоколом авторизации (предоставления доступа) является OAuth 2.0. IdentityServer4 реализует эти два протокола. Он оптимизирован для решения типичных проблем безопасности.
OpenID Connect — это протокол и стандарт аутентификации, он не дает доступ к ресурсам (Web API), но т.к. он разработан поверх протокола авторизации OAuth 2.0, он позволяет получить параметры профиля пользователя как будто вы получили доступ к ресурсу UserInfo.
JWT (JSON Web Token) представляет собой веб-стандарт, который определяет способ передачи данных о пользователе в формате JSON в зашифрованном виде.
OAuth 2.0 (RFC 6749) — это протокол и стандарт авторизации. Он позволяет приложениям получить доступ к защищенным ресурсам, например к Web API.
Взглянем на диаграмму обращения к защищенному ресурсу и разберемся с основными шагами и принятой терминологией:
Клиент запрашивает у пользователя разрешение пройти авторизацию от его имени. Клиент — это клиентское приложение обращающиеся к защищённым ресурсам от имени владельца ресурсов. Ресурс — это все наши защищенные сервисы Web API.
User разрешает клиентскому приложению пройти авторизацию от его имени, например, вводит логин и пароль. Логин и пароль будут являться грантом авторизации для клиентского приложения. User (владелец ресурса) — программа или человек, который может выдать доступ к защищённым ресурсам, например, путем ввода логина (username) и пароля (password);
Если подлинность приложения подтверждена и разрешение на авторизацию действительно, IdentiryServer4 создаёт access-токен (токен доступа) для приложения и необязательный ключ обновления ( refresh-токен ). Процесс авторизации завершён. Если запрос недопустимый или несанкционированный, то сервер авторизации возвращает код с соответствующим сообщением об ошибке.
Клентское приложение обращается за данными к защищенному Web API, предоставляя при этом токен доступа для авторизации. Если код ответа сервера ресурсов 401, 403 или 498, то токен доступа, используемый для аутентификации, недействителен или просрочен.
Если токен действителен, Web API предоставляет данные приложению.
Типы токенов
Введем еще два понятия:
Authenticatation Server Url — конечная точка для получения ключа доступа. Все запросы на предоставление и возобновление ключей доступа будем направлять на этот URL-адрес.
Resource Url — URL-адрес защищенного ресурса, по которому нужно обращаться, чтобы получить доступ к нему, передавая ему ключ доступа в заголовке авторизации.
Запрос ключа доступа
Для запроса ключа доступа клиент делает POST запрос к конечной точке IdentityServer4 со следующим заголовком
и передавая следующие параметры:
Протокол OAuth 2.0 определяет следующие типы грантов требующие обязательного взаимодействие с пользователям:
И типы грантов, которые могут выполняться без интерактивного взаимодействия с пользователям:
scope — это необязательный параметр. Он определяет область видимости. Токен доступа, возвращенный сервером, будет обеспечивать доступ только к тем службам, которые входят в эту область. Т.е. мы можем несколько служб объединить под одним scope и если клиент получает ключ доступа к этому scope он получает доступ ко всем этим службам. Также scope может использоваться для ограничения прав авторизации (например, доступ на чтение или запись)
Современные стандарты идентификации: OAuth 2.0, OpenID Connect, WebAuthn
Пускать или не пускать? Вот в чем вопрос…
Сейчас на многих сайтах мы видим возможность зарегистрироваться или войти с помощью соцсетей, а некоторые сайты предлагают использовать внешние ключи безопасности или отпечатки пальцев. Что это? Стандарты с хорошо проработанной безопасностью или проприетарные реализации? Можем ли мы доверять этим технологиям и использовать их для разработки сайтов и в повседневной жизни? Давайте разбираться. Итак, сейчас существуют несколько стандартов и технологий для идентификации пользователей OAuth 2.0,OpenID Connect, WebAuthn, SAML 2.0, Credential Management API и др. В статье я расскажу о трех наиболее перспективных протоколах OAuth 2.0, OpenID Connect и WebAuthn. И чтобы понять как их применять на практике, сделаем три лабораторные работы. В качестве платформ для идентификации пользователей будем использовать GitHub и Google, на которых у большинства есть аккаунты.
OAuth 2.0
Начнем с самого известного протокола OAuth 2.0. Он был опубликован в 2012 году, как RFC 6749: The OAuth 2.0 Authorization Framework.
С помощью OAuth 2.0 пользователь разрешает определенному сайту получить свои закрытые данные из соцсетей, но без передачи сайту своих логинов / паролей. Например, когда вы регистрируетесь на сайте через Facebook, то как раз и предоставляете этому сайту разрешение получить из Facebook ваше имя, e-mail адрес и другие закрытые данные.
Давайте разберемся с технической реализацией. Для простоты я буду называть любой сайт, который хранит идентификационные данные пользователя Соцсетью. А MySite буду называть любой сайт или приложение, которое хочет получить данные пользователя из Соцсети.
Стандарт определяет следующие роли:
Authorization flow
OAuth 2.0 Лабораторная работа (GitHub)
Существует множество инструкций, как реализовать OAuth 2.0 авторизацию, используя соцсети. Мне лично понравилась следующая статья: Authentication using GitHub OAuth 2.0 with NodeJS В ней подробно описаны шаги и приведена тестовая программа. Но, чтобы действительно осознать алгоритм, лучше пройти все шаги руками (http запросами из браузера или вызовами curl). Поехали.
Для начала регистрируем свое приложение на GitHub: github.com/settings/applications/new
Получаем от GitHub:
Так выглядит получение Client ID и Secret на сайте GitHub:
Теперь начинаем авторизацию. Считаем, что Шаг 1 уже пройден: пользователь зашел на MySite и выбрал “Войти с помощью GitHub ”. Шаг 2 из call flow — это вызов в REST формате:
Шаг 3: Вводим логин/пароль для доступа на GitHub
Шаг 4: GitHub перенаправляет запрос на Homepage, в этом запросе мы видим code:
По данному адресу нет работающего сайта, но для нас главное знать присланный code, чтобы сформировать следующий Шаг 5:
Шаг 7: Вставляем access_token в заголовок запроса и вызоваем GitHub API:
Шаг 8: В ответ получаем JSON с полезной информацией обо мне, которую можно использовать для формирования профиля на MySite:
На самой деле, мы рассмотрели только один сценарий работы OAuth 2.0. Существует несколько сценариев, каждый из которых используется в зависимости от приложения, соображений безопасности, способу развертывания и т.д. Описание всех сценариев можно найти, например, тут: OAuth 2.0 in a Nutshell.
OpenID Connect
С OAuth 2.0 немного разобрались. Теперь выясним зачем нужен OpenID Connect, который является надстройкой над OAuth 2.0:
OpenID Connect (OIDC) — открытый стандарта OpenID, который разрабатывает консорциум OpenID Foundation. OIDC расширяет OAuth 2.0 следующими основными возможностями:
OpenID Connect: Лабораторная работа (Google)
Теперь посмотрим, чем нас по данной теме порадует Google. Есть подробная инструкция по конфигурации и использованию OpenID Connect от Google и “песочница” по использованию Google API: Google OAuth 2.0 Playground.
Здесь, как и в случае с OAuth 2.0, мы пройдем путь по шагам и посмотрим на приходящие данные. Аналогично считаем, что приложение зарегистрировано, Client ID и Client Secret получены, Шаг 1 пройден. Шаг 2 из call flow — это вызов в REST формате:
У Google немного посложнее, т.к. безопасности они уделяют больше внимания:
Шаг 4: Google перенаправляет запрос на Homepage, в этом запросе мы видим code:
Также как и в случае с GitHub по данному адресу нет работающего сайта, но это и не надо, нам главное знать code, чтобы сформировать следующий Шаг 5. Тут тоже немного посложнее, т.к. Google требует запрос POST, а не GET:
Что теперь делать с этим богатством?
Шаг 7: C access_token все понятно: включаем его в вызов API, например GMail:
Шаг 8: В ответ получаем JSON с полезной информацией:
Теперь давайте проверим утверждение, что в id_token содержится информация для аутентификации пользователя и поддержания сессии. Для этого надо расшифровать содержимое. Самый простой способ сделать это, обратиться к Google API по адресу
oauth2.googleapis.com/tokeninfo и в качестве параметра указать полученный id_token:
Видим, что в id_token содержится информация о логине пользователя, времени получения и времени жизни токена. Можно сделать вывод, что OpenID Connect от Google работает, и его можно применять для соответствующих сценариев.
WebAuthn
По сравнению с OAuth 2.0 в WebAuthn добавляются роли:
Authenticator: внешний ключ безопасности (физический носитель или сканер отпечатков пальцев), который позволяет аутентифицировать пользователя, использую различные технологии, такие как BlueTooth/NFC/USB. Служит для:
Relying Party: выполняет ту же функцию, что и “Authorization Server” в OAuth 2.0, а именно проверяет идентификационные данные пользователя. Только в OAuth 2.0 это были логин/пароль, а в WenAuthn — public key credentials.
User Agent: объединяет браузер и сетевое приложение, служит для тех же целей, что и Client в OAuth 2.0, а именно — с одной стороны взаимодействует с пользователем и предоставляет ему GUI, а с другой стороны взаимодействует с системами, в которых хранятся идентификационные данные пользователя.
Authorization flow
Перед началом процесса аутентификации, также как и в OAuth 2.0, надо совершить подготовительные действия, только в OAuth 2.0 мы регистрировали приложение, а в WebAuth 2.0 регистрируем пользователя. В Web Authentication API специфицировано два вызова:
В результате этого в Authenticator-е пользователя сохранится закрытый ключ для определенного сайта, а в Relying Party сохранится открытый ключ.
После этого процесс аутентификации будет таким:
WebAuthn: Лабораторная работа (Google)
Для реализации WebAuthn только http запросами не обойтись, т.к. нужно вызывать браузерное API для взаимодействия с Authenticator-ом. Но и тут Google радует, сделали песочницу с пошаговой инструкцией: Your first WebAuthn.
В результате выполнения работы получится JS клиент-серверное приложение, которое реализует аутентификацию с помощью отпечатка пальца. Работающая дема находится по адресу.
Если ее запустить на смартфоне с датчиком отпечатков пальцев, то можно посмотреть результат работы. Как обычно, сначала подготовка — регистрируем пользователя:
Создаем логин / пароль и далее привязываем отпечаток пальца:
После этого программа показывает какой открытый ключ привязан к этому отпечатку:
Теперь можно начинать сценарий по аутентификации. Как обычно, считаем, что Шаг 1 пройден и мы находимся на сайте. Чтобы перейти к Шагу 2 надо нажать “Try Reauth”. Браузер выполнит Шаг 3 и вступит во взаимодействие с Authenticator-ом, который на Шаге 4 попросит приложить палец:
И если приложен зарегистрированный палец, то Шаги 5 и 6 успешно пройдут и на Шаге 7 приложение опять покажет окно с соответствующим открытым ключом:
Заключение
Итак, мы рассмотрели три наиболее распространенных и перспективных протокола для идентификации пользователей: OAuth 2.0, OpenID Connect, WebAuthn. Поняли области их применимости:
Выводы
Приложение: остальные протоколы идентификации
Для полноты картины перечислю остальные актуальные протоколы и технологии, используемые для идентификации пользователей:
SAML 2.0 (Security Assertion Markup Language)
Зрелый протокол 2005 года, но имеет ограниченный набор сценариев для построения систем SSO. Использует формат данных на основе XML. Подробнее можно посмотреть в статье: “Кто использует протокол аутентификации SAML 2.0”
Credential Management API
Разработкой занимается та же организация, что и WebAuthn — W3C. Стандарт Credential Management позволяет:
Вкратце об OpenID Connect
Медленно, но неотвратимо наступает смена решений SSO на основе SAML на решения OpenID стека. С недавних пор компания Google реализовала поддержку OpenID Connect протокола на своих серверах. Насколько он может быть приемлем для Вашего проекта и как с ним работать, оценить по спецификации протокола довольно трудно. Немного облегчить это решение должна статья одного из авторов спецификации в своём блоге, перевод которой я и предоставляю аудитории хабра. В целях упростить понимание, некоторые моменты были добавлены от себя, таким образом, чтобы не приходилось обязательно читать ссылки на используемые технологии, но ознакомится с некоторыми из них всё же я рекомендую.
Когда вы читаете спецификацию по OpenID Connect, вы можете испытывать довольно неприятные чувства от лёгкой испуганности до полнейшего разочарования. Всё это происходит потому, что они написаны на “сухом” языке спецификации, и по большей части они описывают граничные случаи, исключения и т.д. Тем не менее, когда вы переводите их на нормальный человеческий язык и переключаетесь на конкретные случаи, всё становится довольно очевидно. Итак, давайте приступим! (Ремарочка: большая часть текста совпадает с первоначальным предложением, написанным Дэвидом Рекордоном. В основном, мои правки затронули лишь некоторые из имен параметров и другие мелочи)
Создание запроса OpenID Connect
Для того, чтобы клиент мог совершить OpenID Connect запрос, он должен иметь следующую информацию о сервере:
Построение клиентом запроса OAuth 2.0, для получения токена.
Для того чтобы превратить запрос OAuth 2.0 в запрос OpenID Connect, просто добавьте ключ OpenID в качестве одной из требуемых наборов данных (параметр scope). Установив в параметре ключ OpenID, клиент запрашивает идентификатор для пользователя, а также контекст аутентификации. Если вы хотите получить URL профиля пользователя, имя или фотографию, вы можете запросить дополнительные наборы данных (к примеру — профиль). Сервер (и пользователь) может выбирать информацию о профиле доступном клиенту. Если клиент хочет получить адрес электронной почты пользователя, он должен добавить ключ “email” в запросе. То же самое относится и к адресу (address) и телефону (phone).
Например:
Несмотря на то, что предварительная регистрация вашего клиента на сервере может быть не обязательна, вполне вероятно, что сервера будут иметь различные ограничения и требования к клиентам для запросов к информации пользователей.
Получение OpenID Connect ответа
Если пользователь будет авторизован клиентским запросом, то клиент получит токен. Ответ авторизации OAuth 2.0 как правило, включает в себя два параметра: access_token и id_token. Информация в id_token закодирована и включает в себя объект JSON с такими полями:
Параметр id_token представляет простой способ, чтобы убедиться, что данные, полученные клиентом через User-Agent потоки (или других ненадежных каналов) не были изменены. Параметр подписывается сервером, используя клиентский ключ, который был ранее передан через доверенный канал. Эта кодировка называется JSON Web Токен (о JWT вкратце и черновая спецификация). К примеру, вот такая строка :
Она состоит из трёх частей которые отделены точками.
Первая часть — заголовок (Header), это JSON объект закодированный Base64url и описывающий алгоритм и тип токена:
Вторая часть — полезная нагрузка (Payload), это так-же JSON объект закодированный Base64url:
Третью часть сервер получил след образом:
Обратите внимание, что base64url кодировка в отличии от base64 использует два других символа и не содержит отступов.
Сервер авторизации должен выдавать подтверждения об идентификаторах пользователей только в пределах своих доменов. Клиент в свою очередь должен убедиться, что aud соответствует его client_id, а iss соответствует домену (включая суб-домен) эмитента в client_id. Сервер авторизации отвечает за управление собственным локальным пространством имен и обеспечивает локальную уникальность и неповторяемость (непереназначаемость) каждого user_id.
Когда клиент сохраняет идентификатор пользователя, он должен сохранить кортеж из user_id и iss в своём локальном хранилище. Параметр user_id должен не превышать 255 ASCII символов в длину.
Что-бы удостовериться в аутентичности данных клиент может проверить подпись. Если клиент не проверяет подпись, он должен выполнить HTTP запрос к точке проверки идентификатора, чтобы проверить его. — немножко непонятно зачем ему это делать
Доступ к информации о пользователях (опционально)
Информация о пользователе является обычным OAuth 2.0 ресурсом, который возвращается вместе с токеном в виде документа в формате JSON. Клиент делает HTTPS «GET» запрос по адресу предоставления пользовательской информации и включает в себя токен в качестве параметра.
Ответ представляет собой объект JSON, который содержит некоторые (или все) из следующих зарезервированных ключей (json-объекта):
Сервер по необходимости может добавить дополнительные данные в этот ответ (к примеру такие как переносимые контакты) пока они не изменяют зарезервированные ключи OpenID Connect. (Примечание: есть более четко определенные ключи, но для краткости, я опущу их описание.)
Открытие (опционально)
При использовании OpenID Connect вполне вероятно, что клиент может иметь или кнопки для регистрации через популярные сервисы, или текстовое поле для ввода адреса электронной почты или URL. OpenID Connect напрямую не решает проблему NASCAR
(Проблема NASCAR — это отсылка на мешанину из значков брендов веб-сайтов, через которые осуществляется вход, подчёркивая схожесть страницы логина с коллажами наклеек спонсорской рекламы на трековых автомобилях в гонках NASCAR).
Цель этапов открытия и регистрации для клиента состоит в том, чтобы получить адрес сервера авторизации, конечный адрес точки выдачи токена, идентификатора клиента, секрет клиента, и получения API пользовательских данных. Если клиент предварительно зарегистрирован на сервере, то эта информация уже будет известна. В противном случае клиенту нужно будет получить их при помощи этапа открытия.
Пользователь нажимает на кнопку на клиенте, чтобы выбрать сервер. В этом случае разработчик клиента сможет выбрать предпочтительные сервера и таким образом, уже зная их адреса авторизации (и, возможно, другую информацию). Клиент может быть или не быть предварительно зарегистрированным.
В другом случае, пользователь (или User-Agent, действующим от его имени) вводит URL или адрес электронной почты. Для этого клиенту необходимо будет выполнить обнаружение и определить, является ли валидным URL-адрес сервера авторизации. Шаги:
Ответ представляет собой объект JSON, который включает в себя конечную точку и другую информацию.
Например:
Незарегистрированные клиенты и динамическая регистрация (опционально)
Независимо от используемого механизма обнаружения (Discovery), клиент может быть или не быть уже зарегистрирован на сервере. Сервера могут иметь разные ограничения на то, какую информацию могут получить клиенты в зависимости от того, являются ли они предварительно зарегистрированными (что подразумевает согласие на условия предоставления услуг) или клиент использует динамическую регистрацию.
Если клиент не имеет валидный идентификатор клиента и ключ, он может сделать следующий HTTPS POST запрос на адрес регистрации сервера (см. Открытие) со перечисленными запрашиваемыми параметрами в формате JSON в теле POST запроса: redirect_uris — Массив URL адресов для получения ответов OpenID.
Например:
Перед тем, как ответить на запросы, сервер должен проверить, зарегистрирован ли URL коллбек за пределами этого потока OpenID. Если да, сервер отправит информацию с реакцией на ошибку. Серверу необходимо будет разработать политику для обработки таких случаев, когда переданные redirect_uri были предварительно зарегистрированы разработчиком клиента, при запросах динамической регистрации. Такое поведение может означать, к примеру, что новые запросы динамической регистраций с этими redirect_uri приведут к ошибке, но запросы с использованием уже осуществлённой динамической регистраций продолжат работать, пока не устареют.
Для обеспечения динамической ассоциации, сервер включает в себя следующие параметры ответа JSON:
Клиенту необходимо хранить свои данные динамической регистрации для работы с токенами сервера. Для каждой динамической регистрации клиенту необходимо будет хранить идентификатор клиента, ключ клиента, время истечения, пользовательский URL, поддерживаемые потоки, а также API пользовательской информации. Время окончания срока следует хранить как абсолютное время или метку того, что регистрация будет длится вечно.
Как видите, основные процессы веб-клиента OpenID Connect достаточно просты, и так же просты, как те, которые предлагались первоначально. В то же время, могут быть использованы дополнительные функциональные возможности, например запрос конкретных наборов данных, а не набор по умолчанию. Эти дополнительные возможности доступны, когда они необходимы и не превращают простые взаимодействия в крупные проблемы для клиентов, с большим числом OpenID провайдеров.
OpenID Connect: авторизация внутренних приложений от самописных к стандарту
Несколько месяцев назад я занимался реализацией OpenID Connect сервера для управления доступом сотен наших внутренних приложений. От собственных наработок, удобных на меньших масштабах, мы перешли к общепринятому стандарту. Доступ через центральный сервис значительно упрощает монотонные операции, сокращает затраты на реализацию авторизаций, позволяет находить много готовых решений и не ломать голову при разработке новых. В этой статье я расскажу об этом переходе и о шишках, которые мы успели набить.
Давным-давно… С чего все начиналось
Несколько лет назад, когда внутренних приложений стало слишком много для ручного управления, мы написали приложение для контроля доступов внутри компании. Это было простое Rails-приложение, которое подключалось к базе данных с информацией о сотрудниках, где настраивался доступ к различному функционалу. Тогда же мы подняли первое SSO, которое основывалось на проверке токенов со стороны клиента и сервера авторизации, токен передавался в шифрованном виде с несколькими параметрами и сверялся на сервере авторизации. Это был не самый удобный вариант так, как на каждом внутреннем приложении нужно было описывать немалый слой логики, а базы сотрудников и вовсе синхронизировались с сервером авторизации.
Спустя некоторое время мы решили упростить задачу централизованной авторизации. SSO перевели на балансер. С помощью OpenResty на Lua добавили шаблон, который проверял токены, знал в какое приложение идет запрос и мог проверить, есть ли туда доступ. Такой подход сильно упростил задачу контроля доступов внутренних приложений — в коде каждого приложения уже не нужно было описывать дополнительную логику. В итоге мы закрыли трафик внешне, а само приложение ничего не знало об авторизации.
Однако одна из проблем осталась нерешенной. Как быть с приложениями, которым нужна информация о сотрудниках? Можно было написать API для сервиса авторизации, но тогда пришлось бы добавлять дополнительную логику для каждого такого приложения. К тому же мы хотели избавиться от зависимости от одного нашего самописного приложения, ориентированного в дальнейшем на перевод в OpenSource, от нашего внутреннего сервера авторизации. О нем мы расскажем как-нибудь в другой раз. Решением обеих проблем стал OAuth.
К общепринятым стандартам
OAuth — это понятный, общепринятый стандарт авторизации, но так как только его функционала недостаточно, рассматривать стали сразу OpenID Connect (OIDC). Сам по себе OIDC — это третья реализация открытого аутентификационного стандарта, которая перетекла в надстройку над протоколом OAuth 2.0 (открытый протокол авторизации). Такое решение закрывает проблему отсутствия данных о конечном пользователе, а также дает возможность смены провайдера авторизации.
Однако мы не стали выбирать конкретного провайдера и решили для нашего существующего сервера авторизации добавить интеграцию с OIDC. В пользу такого решения послужило, то что OIDC очень гибок в плане авторизации конечного пользователя. Таким образом была возможность внедрить поддержку OIDC на своем текущем сервере авторизации.
Наш путь реализации собственного OIDC-сервера
1) Привели данные в нужный вид
Для интеграции OIDC необходимо привести текущие данные о пользователях в вид, понятный стандарту. В OIDC это называется Claims. Клеймы по сути — это конечные поля в базе данных о пользователях (name, email, phone и т.д.). Существует стандартный список клеймов, а все, что не входит в этот список, считается кастомным. Поэтому первый момент, на который необходимо обратить внимание, если вы захотите выбрать существующий OIDC-провайдер – возможность удобной кастомизации новых клеймов.
Группа клеймов объединяется в следующее подмножество – Scope. При авторизации идет запрос доступа не к конкретным клеймам, а именно к скоупам, даже если часть клеймов из скоупа не нужна.
2) Реализовали нужные гранты
Следующей частью интеграции OIDC является выбор и реализация типов авторизации, так называемых грантов. От выбранного гранта будет зависеть дальнейший сценарий взаимодействия выбранного приложения с авторизационным сервером. Примерная схема выбора нужного гранта представлена на рисунке ниже.
Для нашего первого приложения мы использовали самый распространенный грант – Authorization Code. Его отличием от других является то, что он является трехшаговым, т.е. проходит дополнительную проверку. Сначала пользователь делает запрос на разрешение авторизации, получает токен – Authorization Code, затем с этим токеном, словно с билетом на проезд, запрашивает токен доступа. Все основное взаимодействие данного сценария авторизации основано на редиректах между приложением и авторизационным сервером. Подробнее почитать об этом гранте можно здесь.
OAuth придерживается концепции, что токены доступа, полученные после авторизации, должны быть временными и меняться желательно в среднем каждые 10 минут. Грант Authorization Code является трехшаговой проверкой через редиректы, каждые 10 минут такой шаг проворачивать, честно говоря, не самое приятное для глаз занятие. Для решения этой проблемы существует еще один грант – Refresh Token, который мы у себя также задействовали. Тут все проще. Во время проверки с другого гранта, помимо основного токена доступа выдается еще один – Refresh Token, который можно использовать только один раз и время его жизни, как правило, существенно больше. С этим Refresh Token’ом, когда закончится TTL (Time to Live) основного токена доступа, запрос нового токена доступа придет на endpoint уже другого гранта. Использованный Refresh Token сразу обнуляется. Такая проверка является двухшаговой и может быть выполнена в фоне, незаметно для пользователя.
3) Настроили форматы вывода пользовательских данных
После того, как выбранные гранты реализованы, авторизация работает, стоит упомянуть о получении данных о конечном пользователе. В OIDC есть отдельный endpoint для этого, на котором со своим текущим токеном доступа и при его актуальности можно запросить данные о пользователях. И если данные пользователя не меняются так часто, а ходить за текущими нужно по многу раз, можно прийти к такому решению, как JWT-токены. Эти токены также поддерживаются стандартом. Сам по себе JWT-токен состоит из трех частей: header (информация о токене), payload (любые нужные данные) и signature (подпись, токен подписывается сервером и в дальнейшем можно проверить источник его подписи).
В имплементации OIDC JWT-токен называется id_token. Он может быть запрошен вместе с обычным токеном доступа и все, что остается – проверить подпись. У сервера авторизации для этого существует отдельный endpoint со связкой публичных ключей в формате JWK. И говоря об этом, стоит упомянуть, что существует еще один endpoint, который на основе стандарта RFC5785 отражает текущую конфигурацию OIDC-сервера. В нем содержатся все адреса endpoint’ов (в том, числе адрес связки публичных ключей, используемых для подписи), поддерживаемые клеймы и скоупы, используемые алгоритмы шифрования, поддерживаемые гранты и т.д.
Таким образом с помощью id_token’а можно передавать все нужные клеймы в payload токена и не обращаться каждый раз на сервер авторизации для запроса данных о пользователе. Минусом такого подхода является то, что изменение пользовательских данных от сервера приходит не сразу, а вместе с новым токеном доступа.
Итоги реализации
Так, после реализации собственного OIDC сервера и настройки подключений к нему на стороне приложений, мы решили проблему передачи информации о пользователях.
Так как OIDC — это открытый стандарт, у нас появилась возможность выбора существующего провайдера или реализации сервера. Мы пробовали Keycloak, который оказался очень удобным в конфигурировании, после настройки и смены конфигураций подключения на стороне приложений он готов к работе. На стороне приложений остается только сменить конфигурации подключения.
Говоря о существующих решениях
В рамках нашей организации в качестве первого OIDC-сервера мы собрали свою реализацию, которая дополнялась по мере необходимости. После подробного рассмотрения других готовых решений, можно сказать, что это спорный момент. В пользу решения реализации своего сервера послужили опасения со стороны провайдеров в отсутствии необходимого функционала, а также наличие старой системы в которой присутствовали разные кастомные авторизации для некоторых сервисов и хранилось уже довольно много данных о сотрудниках. Однако в готовых реализациях, присутствуют удобства для интеграции. Например, в Keycloak своя система менеджмента пользователей и данные хранятся прямо в ней, а перегнать своих пользователей туда не составит большого труда. Для этого в Keycloak есть API, которое позволит в полной мере осуществить все необходимые действия по переносу.
Еще один пример сертифицированной, интересной, на мой взгляд, реализации — Ory Hydra. Интересна она тем, что состоит из разных компонентов. Для интеграции вам понадобится связать свой сервис менеджмента пользователей с их сервисом авторизации и расширять по мере необходимости.
Keycloak и Ory Hydra — не единственные готовые решения. Лучше всего подбирать сертифицированную OpenID Foundation реализацию. Обычно у таких решений есть значок OpenID Certification.
Также не забывайте о существующих платных провайдерах, если вы не хотите держать свой сервер OIDC. На сегодняшний день хороших вариантов много.