Это старая версия документа!
Содержание
Автор: Владимир Недорослев
Протокол работы ЕСИ
Все запросы в данном руководстве разделены построчно для удобства чтения.
Данный документ описывает конфигурацию работы ЕСИ.
Discovery document
Discovery document – это документ в формате JSON, показывающий информацию об ЕСИ - адреса Endpoint’ов, поддерживаемые scope, какую информацию о пользователе можно выдать и пр.
Его можно найти по адресу:
https://{Базовый адрес ЕСИ}/.well-known/openid-configuration
Содержит следующие поля:
- issuer – URL идентификатор ЕСИ. ЕСИ использует его для сравнения с полем iss в ID Token’е.
- jwks_uri – URL JWK документа. Содержит ключи, которые клиенты должны использовать при проверке подписей ЕСИ.
- authorization_endpoint – URL адрес Authorization Endpoint’а.
- token_endpoint – URL адрес Token Endpoint’а.
- userinfo_endpoint - URL адрес UserInfo Endpoint’а.
- end_session_endpoint- endpoint закрытия сессии.
- revocation_endpoint - endpoint отзыва Access Token'а.
- scopes_supported – JSON массив, содержащий список всех значений scope, поддерживаемых ЕСИ:
- openid – обязательный scope для всех запросов. Означает, что используется технология OpenID Connect.
- profile – включает в себя:
- pin - персональный номер.
- citizenship - гражданство. Для граждан Кыргызстана
KGZ. - name - полное имя (ФИО).
- family_name - фамилия.
- given_name - имя.
- middle_name - отчество.
- gender - пол (
maleилиfemale). - birthdate - дата рождения в формате
YYYY-MM-DD. (Например,1990-11-23).
- email – включает в себя email и email_verified.
- phone – включает в себя phone и phone_verified.
- offline_access – нужно ли получение Refresh Token'а.
- organizations - ИНН организаций (юридических лиц), в которых состоит пользователь.
- response_types_supported – JSON массив, содержащий список значений response_type, поддерживаемых ЕСИ.
- response_modes_supported – JSON массив, содержащий список поддерживаемх response_mode, основанный на OAuth 2.0.
- claims_supported – JSON массив, содержащий список данных, которые может выдавать ЕСИ:
- sub – идентификатор пользователя ЕСИ.
- pin – персональный номер.
- family_name – Фамилия.
- given_name – Имя.
- middle_name – Отчество.
- name – Полное имя (ФИО).
- citizenship – гражданство. Для граждан Кыргызстана – KGZ.
- gender – Пол (
maleилиfemale). - birthdate – Дата рождения.
- email – электронная почта.
- email_verified – подтверждена ли почта (true/false).
- phone_number – мобильный телефон в формате E164.
- phone_number_verified – подтвержден ли телефон (true/false).
- organizations - массив, содержащий ИНН организаций (юридических лиц), в которых состоит пользователь.
ID Token
Для аутентификации пользователя OpenID Connect вводит понятие ID Token’а. Это структура данных, которая хранит информацию об аутентификации пользователя ЕСИ. Представляется в виде JSON Web Token (JWT). ЕСИ выдаёт ID Token со следующими полями:
- iss – (Issuer) идентификатор ЕСИ. Это регистрозависимый URL, использующий https, содержащий схему и хост. Может содержать номер порта, путь. Не содержит параметров запроса.
- sub – (Subject) идентификатор пользователя. Уникальный, никогда неменяющийся идентификатор пользователя, который хранит ЕСИ. Например,
24400320. Является регистрозавсимой строкой, длиной не более 255 ASCII символов. - aud – (Audience) массив строк, содержащий идентификаторы клиентов (client_id), которым предназначен данный ID Token.
- exp – (Expiration) срок действия ID Token'a. Время, после которого ID Token не является валидным и не должен обрабатываться. При валидации ID Token'а текущее время должно быть до времени, указанного в этом поле. Значение представляется в виде JSON числа, показывающий количество секунд прошедших с 1970-01-01T0:0:0Z согласно UTC стандарту (см. RFC3339 для подробной информации насчёт времени в UTC).
- iat – (Issued at) время, когда ID Token был создан. Значение представляется в виде JSON числа, показывающий количество секунд прошедших с 1970-01-01T0:0:0Z согласно UTC стандарту.
- auth_time – (Authentication time) время, когда была произведена аутентификация пользователя. Значение представляется в виде JSON числа, показывающий количество секунд прошедших с 1970-01-01T0:0:0Z согласно UTC стандарту.
- nonce – регистрозависимая строка, ассоциирующая сессию клиента с ID Token’ом, чтобы избежать атак повторного воспроизведения (replay attacks). Клиенты должны проверять, чтобы это значение было равно значению nonce в authentication request'e.
- amr – (Authentication methods references) JSON массив строк, хранящий методы аутентификации, использованные при аутентификации пользователя. Например, может покаазть, что при аутентификации был использован пароль и OTP.
- at_hash – хэш Access Token’а. Хэш вычисляется по левой половине хэшей октетов Access Token“a в формате ASCII. Примененный хэш-алгоритм указан в головной части (header) ID Token’a в значении
alg.
Authentication request
Authentication request (Запрос на аутентификацию) — это GET или POST запрос клиента в Authorization Endpoint, который требует, чтобы пользователь аутентифицировался в ЕСИ.
В случае GET запроса, параметры запроса указывается непосредственно в самом запросе.
В случае POST запроса, параметры запроса указываются в теле запроса (Content-Type: application/x-www-form-urlencoded)
Параметры запроса
- scope (Обязательный) – разделенные пробелом значения, показывающие, какие данные необходимы клиенту. Обязательно должно содержать значение
openid. - response_type (Обязательный) – определяет способ процесса авторизации. В случае с ЕСИ используется значение
code. - client_id (Обязательный) – идентификатор клиента, выданный ЕСИ.
- redirect_uri (Обязательный) – URI, куда будет отправлен ответ ЕСИ после того, как пользователь пройдёт аутентификацию в ЕСИ. Он задаётся вместе с
client_idпри регистрации клиента. - nonce (Опциональный) – регистрозависимая строка ассоциирующая сессию клиента с ID Token’ом, чтобы избежать атак повторного воспроизведения (replay attacks).
- state (Опциональный) – значение для сохраниния состояние между запросом и callback’ом. Обычно для борьбы с CSRF это значение криптографически привязывается к куки браузера.
PKCE
Так как ЕСИ использует Authorization Code flow with PKCE (RFC7636), при запросе на аутентификацию необходимо дополнительно сделать следующее:
- Сформировать и сохранить code_verifier (он ещё понадобится при запросе на получение токенов) - криптографически случайная строка размером от 43 до 128 символов, и состоящая из символов
a-z A-Z 0-9 -._~ - Сформировать code_challenge следующим образом:
base64url(sha256(code_verifier))
- Добавить в запрос следующие параметры:
&code_challenge={сформированный code_challenge}
code_challenge_method=S256
Валидация запроса
При получении запроса на аутентификацию ЕСИ проверит, чтобы все параметры запроса соответствовали стандарту OAuth 2.0 и OpenId Connect. Подразумевается наличие обязательных параметров scope, response_type, client_id, redirect_uri. В случае, если запрос составлен не верно, ЕСИ вернёт ошибку на указанный redirect_uri. Информация об ошибке будет представлена в виде параметров.
Возможны следующие параметры:
- error (Обязательный) – название ошибки. Может принимать следующие значения:
- invalid_request – неправильный запрос. Возникает, если в запросе отсутствует обязательный параметр, запрос содержит неправильное значение параметра, включает в себя одинаковый параметр более одного раза и пр.
- unauthorized_client – неавторизованный клиент. Клиент не авторизован и не может получить авторизационный код.
- access_denied – отказано в доступе. Пользователь либо ЕСИ отколнили запрос.
- unsupported_response_type – неподдерживаемый возвращаемый тип. ЕСИ не поддерживает получение авторизационного кода указанным методом.
- invalid_scope – неправильный scope. Запрашиваемое(-ые) значения scope неверны, неизвестны, либо составлены неправильно.
- server_error – ошибка сервера. Ошибка со стороны ЕСИ, которая не позволяет обработать запрос.
- temporarily_unavailable – временно недоступно. В данный момент ЕСИ не может обработать запрос из-за перегрузки либо технических работах на сервере.
- invalid_request_uri – неправильный redirect_uri. redirect_uri возвращает ошибку при перенаправлении либо содержит неправильные данные.
- error_description (Опциональный) – описание ошибки понятное человеку.
- error_uri (Опциональный) – URI веб-страницы, на которой находится дополнительная информация об ошибке.
- state (Опциональный) – состояние согласно OAuth 2.0. Ставится значение, полученное от клиента.
Примеры
Примеры значений scope:
scope=openid profile email scope=openid profile notification_api phone
Пример ответа клиента, который перенаправляет браузер пользователя к Authorization endpoint для запроса на аутентификацию:
302 Found
Location: https://{базовый-адрес-ЕСИ}/connect/authorize?
response_type=code
&scope=openid%20profile%20email
&client_id=s6BhdRkqt3
&state=af0ifjsldkj
&redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb
&code_challenge=UTGRtxSHqyGSX1z54iTOBB6Z3WdAMeFv7iYSC6yqx0w
&code_challenge_method=S256
Пример запроса, который отправит браузер пользователя к ЕСИ в ответ на redirect ответ клиента:
GET https://{базовый-адрес-ЕСИ}/connect/authorize?
response_type=code
&scope=openid%20profile%20email
&client_id=s6BhdRkqt3
&state=af0ifjsldkj
&redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb
&code_challenge=UTGRtxSHqyGSX1z54iTOBB6Z3WdAMeFv7iYSC6yqx0w
&code_challenge_method=S256
Пример ошибки:
HTTP/1.1 302 Found Location: https://client.example.org/cb? error=invalid_request &error_description=Unsupported%20response_type%20value &state=af0ifjsldkj
Пример ответа ЕСИ при успешной валидации запроса на аутентификацию:
HTTP/1.1 302 Found Location: https://client.example.org/cb? code=SplxlOBeZQQYbYS6WxSbIA &state=af0ifjsldkj
Token request
Для получения ID Token’а и Access Token’а клиент должен отправить POST запрос в Token Endpoint ЕСИ, предоставив полученный авторизационный код (code), свой client_id, client_secret и redirect_uri.
client_id и client_secret должны находится в заголовке запроса Authorization типа Basic в качестве имени пользователя и пароля соответственно.
В теле запроса должны находится следующие параметры (Content-Type: application/x-www-form-urlencoded):
grant_type=authorization_code
&code={ваш авторизационный код}
&redirect_uri={ваш redirect_uri}
&code_verifier={code_verifier, который вы сгенерировали на этапе Authentication request}
Пример запроса к Token Endpoint
POST https://{базовый-адрес-ЕСИ}/connect/token
Content-Type: application/x-www-form-urlencoded
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA
&redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb
&code_verifier=oV0CFtgI2ywyqV6y5Z2gy49stoKn0T2daY_nLvXDeWRNqQeJ
Валидация запроса
ЕСИ валидирует запрос следующим образом:
- Аутентифицирует клиента по полученным client_id и client_secret.
- Проверит авторизационный код. Действительно ли он был выдан данному клиенту. Правильный ли он, не был ли он использован до этого, был ли выдан в результате запроса на аутентификацию.
- Сравнит полученный redirect_uri со значением redirect_uri полученном при запроса на аутентификацию.
- Сформирует code_challenge из полученнго code_verifier и сравнит с ранее полученным code_challenge при запросе на аутентификацию.
При успешной валидации ЕСИ вернёт Id Token и Access Token в ответ в формате application/json, а также следующие поля:
- token_type – по стандарту всегда имеет значение
Bearer. - refresh_token – токен, позволяющий получить новый access token после того, как он истёк. Выдаётся в случае, если было указано значение scope
offline_accessво время authentication request. - expires_in – значение в секундах, показывающее через сколько access token станет недействительным.
При возникновении ошибки, информация о ней вернётся в том же формате, что и при запросе на аутентификацию.
Пример успешного ответа ЕСИ с ID Token'ом и Access Token'ом:
HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store
Pragma: no-cache
{
"access_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6ImNhZzBDYk1UYzh4d293MDVaVDRpRFEiLCJ0eXAiOiJhdCtqd3QifQ.eyJuYmYiOjE1ODQ0NDExNTAsImV4cCI6MTU4NDQ0NDc1MCwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo3MDAwIiwiYXVkIjoibm90aWZpY2F0aW9uX2FwaSIsImNsaWVudF9pZCI6Im12Yy1jbGllbnQiLCJzdWIiOiIxMDAwMDAwIiwiYXV0aF90aW1lIjoxNTg0NDQxMTQ4LCJpZHAiOiJsb2NhbCIsInNjb3BlIjpbInByb2ZpbGUiLCJvcGVuaWQiLCJlbWFpbCIsInBob25lIiwibm90aWZpY2F0aW9uX2FwaSJdLCJhbXIiOlsibWZhIl19.KC-_Ua4k3rbRAVEkWF_NffnlGqInfSsSiD-zEk5dmLn5a7PAiiptDNqGpmSJbMhl2rbyFqTrBtUDxmkSbXALDWTAvuRqagTkEvlu2uUpJSQ9c_aYLsW4QdUdR2uAKliRlNAQFygWkN4xsXPSaB6E0B71YKmQcYutssBBcP3tBu_E4EDMW30Vky_osQeB8moHkPthMxXkpBxLSKieY77FOQDJzbaVmzrm9wmIor7OuwFtp0b9yKdpAsg9cGbgcmqW5pYNSa2GdhEzYrf6tkfF7tyuw-LYbJjCklfPwIQNk-RT1TicSwdZzsBWoAS8pWiBfwN4MAaA6TP4O6LA7hcdZw",
"token_type": "Bearer",
"refresh_token": "8xLOxBtZp8",
"expires_in": 3600,
"id_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6ImNhZzBDYk1UYzh4d293MDVaVDRpRFEiLCJ0eXAiOiJKV1QifQ.eyJuYmYiOjE1ODQ0NDExNTAsImV4cCI6MTU4NDQ0MTQ1MCwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo3MDAwIiwiYXVkIjoibXZjLWNsaWVudCIsIm5vbmNlIjoiNjM3MjAwMzc5MzYyNjEzMzE0LlkyTmtZVGN3T0dFdFl6Y3pNaTAwTURreUxUbGhPVFF0T0RJd1pXVmxPVGMxTURVeFpXUTJNemd3TXpJdE9XTmlZaTAwWVROakxUZzFaREV0WkdFMU1XVTJNbVJsWVRFNCIsImlhdCI6MTU4NDQ0MTE1MCwiYXRfaGFzaCI6ImhpOWItMURYanVtSWRCeFJ1VGRlb3ciLCJzX2hhc2giOiJFNXdOMzRlMFZkVl9jSVJQREZGS0h3Iiwic2lkIjoiMjc1SEtZRE1QS0EtRGt1NXJWdjNJdyIsInN1YiI6IjEwMDAwMDAiLCJhdXRoX3RpbWUiOjE1ODQ0NDExNDgsImlkcCI6ImxvY2FsIiwiYW1yIjpbIm1mYSJdfQ.dkcyzcRHrTZAGATA2p3Q8x7PMeQRQdWYq9h0ptMD0lx_2LvKNc9ItEncBFm1Kjjtq8oY2wiIGILJTBwiyO7IGCePHCLLXTy2csxcd-gL83nXL5aosIOxOjTiIc7Wo4mCVIsnk-fHdroHmfPmB-gAEAnoEpOTbN5IZ-lpAJl_WhB-utbiNVyEVrzm03usHppbu2-ev-9vWOuiQy6Ryg-GBWTkv0Hi3Q5mnG1FBA-ac-13JXBIhSEPtKWFw6Ck3-OVi4IoTzh5uz-IPFv_1H12ervVE7Qf9tv6sEbrGj2q1x3KbAkAEeaGpJWduJfHLNthxwk99Gbl8JL710cZGGCpdQ"
}
UserInfo request
Для получения информации о пользователе, клиенту необходимо отправить GET или POST запрос в UserInfo Endpoint с заголовком Authorization типа Bearer со значением полученного Access Token'а.
Рекомендуется использовать GET запрос.
Пример запроса:
GET https://{базовый-адрес-ЕСИ}connect/userinfo
Host: server.example.com
Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6ImNhZzBDYk1UYzh4d293MDVaVDRpRFEiLCJ0eXAiOiJhdCtqd3QifQ.eyJuYmYiOjE1ODQ0NDExNTAsImV4cCI6MTU4NDQ0NDc1MCwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo3MDAwIiwiYXVkIjoibm90aWZpY2F0aW9uX2FwaSIsImNsaWVudF9pZCI6Im12Yy1jbGllbnQiLCJzdWIiOiIxMDAwMDAwIiwiYXV0aF90aW1lIjoxNTg0NDQxMTQ4LCJpZHAiOiJsb2NhbCIsInNjb3BlIjpbInByb2ZpbGUiLCJvcGVuaWQiLCJlbWFpbCIsInBob25lIiwibm90aWZpY2F0aW9uX2FwaSJdLCJhbXIiOlsibWZhIl19.KC-_Ua4k3rbRAVEkWF_NffnlGqInfSsSiD-zEk5dmLn5a7PAiiptDNqGpmSJbMhl2rbyFqTrBtUDxmkSbXALDWTAvuRqagTkEvlu2uUpJSQ9c_aYLsW4QdUdR2uAKliRlNAQFygWkN4xsXPSaB6E0B71YKmQcYutssBBcP3tBu_E4EDMW30Vky_osQeB8moHkPthMxXkpBxLSKieY77FOQDJzbaVmzrm9wmIor7OuwFtp0b9yKdpAsg9cGbgcmqW5pYNSa2GdhEzYrf6tkfF7tyuw-LYbJjCklfPwIQNk-RT1TicSwdZzsBWoAS8pWiBfwN4MAaA6TP4O6LA7hcdZw
Ответ от ЕСИ:
HTTP/1.1 200 OK
Content-type: application/json
{
"sub":"1000000",
"pin":"20101199012345",
"citizenship":"KGZ",
"family_name":"Андреев",
"given_name":"Андрей",
"middle_name":"Андреевич",
"name":"Андреев Андрей Андреевич",
"gender":"male",
"birthdate":"1990-01-01",
"email":"some.email@gmail.com",
"email_verified":"True",
"phone_number":"+996000123456",
"phone_number_verified":"True"
}
