Содержание

Автор: Владимир Недорослев

Протокол работы ЕСИ

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

Данный документ описывает конфигурацию работы ЕСИ.

Discovery document

Discovery document – это документ в формате JSON, показывающий информацию об ЕСИ - адреса Endpoint’ов, поддерживаемые scope, какую информацию о пользователе можно выдать и пр.

Его можно найти по адресу:

https://{Базовый адрес ЕСИ}/.well-known/openid-configuration  

Содержит следующие поля:

ID Token

Для аутентификации пользователя OpenID Connect вводит понятие ID Token’а. Это структура данных, которая хранит информацию об аутентификации пользователя ЕСИ. Представляется в виде JSON Web Token (JWT). ЕСИ выдаёт ID Token со следующими полями:

Authentication request

Authentication request (Запрос на аутентификацию) — это GET или POST запрос клиента в Authorization Endpoint, который требует, чтобы пользователь аутентифицировался в ЕСИ.

В случае GET запроса, параметры запроса указывается непосредственно в самом запросе.
В случае POST запроса, параметры запроса указываются в теле запроса (Content-Type: application/x-www-form-urlencoded)

Параметры запроса

PKCE

Так как ЕСИ использует Authorization Code flow with PKCE (RFC7636), при запросе на аутентификацию необходимо дополнительно сделать следующее:

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. Информация об ошибке будет представлена в виде параметров.

Возможны следующие параметры:

Примеры

Примеры значений 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://client.example.org/cb
  &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://client.example.org/cb 
  &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://client.example.org/cb
&code_verifier=oV0CFtgI2ywyqV6y5Z2gy49stoKn0T2daY_nLvXDeWRNqQeJ

Валидация запроса

ЕСИ валидирует запрос следующим образом:

  1. Аутентифицирует клиента по полученным client_id и client_secret.
  2. Проверит авторизационный код. Действительно ли он был выдан данному клиенту. Правильный ли он, не был ли он использован до этого, был ли выдан в результате запроса на аутентификацию.
  3. Сравнит полученный redirect_uri со значением redirect_uri полученном при запроса на аутентификацию.
  4. Сформирует code_challenge из полученнго code_verifier и сравнит с ранее полученным code_challenge при запросе на аутентификацию.

При успешной валидации ЕСИ вернёт Id Token и Access Token в ответ в формате application/json, а также следующие поля:

При возникновении ошибки, информация о ней вернётся в том же формате, что и при запросе на аутентификацию.

Пример успешного ответа ЕСИ с 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"
}

Если пользователь заходит как юридическое лицо:

HTTP/1.1 200 OK
Content-Type: application/json
{
   "sub": "1000000",
   "organization_tin": "ОсОО \"/Компания\"",
   "position_name": "Директор",
   "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"
}