ЕСОЗ - публічна документація

UA_Access tokens JWT format

Призначення та вимоги

  1. Генерація токенів доступу у форматі JWT реалізована для зменшення навантаження на службу mithril, яка існує під час будь-якого виклику API eHealth, який використовує заголовок авторизації з токеном доступу.

  2. У форматі JWT можна використовувати лише токени доступу, які використовуються для отримання доступу до кінцевих точок електронної охорони здоров’я (наприклад, створення/оновлення запиту особи, створення запиту на декларацію, отримання відомостей про підтвердження особи тощо). Будь-які інші токени, які використовуються в потоці OAuth (тобто авторизаційний_код, refresh_token, session_token), усе ще генеруються в існуючому форматі.

  3. Формат створення токену доступу контролюється параметром конфігурації - ACCESS_TOKEN_JWT.

  4. Перевірка існуючого формату генерації токену доступу має бути активною та робочою.

  5. Токен доступу у форматі JWT містить лише дані, пов’язані з користувачами та клієнтами, дані брокера все ще перевіряються за допомогою перевірки API-ключа через службу Mithril за допомогою існуючого процесу, описаного тут MIS authorization

  6. Маркери доступу у форматі JWT не зберігаються в базі даних mithril, оскільки вони перевіряються лише на стороні служби Kong.

Впровадження

Генерація токену доступу в форматі JWT

Наступні методи використовуються для генерації токену доступу для користувача:

Exchange oAuth Code Grant to Access Token

https://e-health-ua.atlassian.net/wiki/spaces/PCAB/pages/17415667759

https://e-health-ua.atlassian.net/wiki/spaces/PCAB/pages/17415798881

https://e-health-ua.atlassian.net/wiki/spaces/PCAB/pages/17415340883

https://e-health-ua.atlassian.net/wiki/spaces/PCAB/pages/17416060933

Методи перевіряють значення конфігураційного параметру ACCESS_TOKEN_JWT:

  • true - маркери доступу для користувачів генеруються у форматі JWT;

  • false - маркери доступу для користувачів генеруються в непрозорому форматі (захешований рядок запису в базі даних mithril, таблиця tokens).

Відповіді методів для згенерованого токену не змінено, токен усе ще повертається в полі value .

Структура JWT

Токен доступу в форматі JWT складається з трьох закодованих base64 рядків, які розділені символом dot:

  • Header

  • Payload

  • Signature

eyJhbGciOiJSUzUxMiIsImtpZCI6IlZ1SGVPX3Nyemhua3h6b1RKYzNURW1CYUZHdkhWcXFXR0V5NzRzM3hWak0iLCJ0eXAiOiJKV1QifQ.eyJhY2Nlc3NfdHlwZSI6IkJST0tFUiIsImFwcGxpY2FudF9wZXJzb25faWQiOiJiZjExNDU0Zi1hMmIwLTRhYjQtYjhiZC1jMmFiZjhkYWM0NDAiLCJhcHBsaWNhbnRfdXNlcl9pZCI6IjE1YzcyZTBiLWM2MDktNGViZC1iZmM5LWE0NWQzM2E3M2JjNSIsImF1ZCI6IkVIZWFsdGgiLCJjbGllbnRfaWQiOiI4YTk5ZmZkZi0zMTRlLTQ0MTktOTMxZC1hNzZmNDFmOGM0NTYiLCJleHAiOjE3MTc4NzQzODQsImdyYW50X3R5cGUiOiJwaXNfYXV0aCIsImlhdCI6MTY4NjMxNzQ1OCwiaXNzIjoiRUhlYWx0aCIsImp0aSI6ImQ3NzFmN2M0LTNkZjUtNGRmYy1iNDQ2LTYwMzk1MGU3ZTFhMiIsIm5iZiI6MTY4NjMxNzQ1NywicGVyc29uX2lkIjoiYmYxMTQ1NGYtYTJiMC00YWI0LWI4YmQtYzJhYmY4ZGFjNDQwIiwicmVmcmVzaF90b2tlbiI6ImJucFNORVY2WW10QlVEWmhNM2xxTHpaelUwRjFaejA5Iiwic2NvcGUiOiJhcHA6cmVhZCBwcm9maWxlOnJlYWQiLCJzdWIiOiIxNWM3MmUwYi1jNjA5LTRlYmQtYmZjOS1hNDVkMzNhNzNiYzUiLCJ0eXAiOiJhY2Nlc3NfdG9rZW4ifQ.dxurQjxcv_LQR9YiG7we0vZl8CKd1c2dZ2i8XhDUt7CNxLINFoLgpmcVnUSMf_Slk-YkXOELgT4sjyWkaeoZpWhcWfTeHMNh7KQzMH9Mnn_8_oGGc4yt3ZPYiHxng4KY2BqrLniPYel_FtaZoBKrfpwh6zh7RUdau_irOLIF6C_RTQ7BD-wOyCEeRjc2CchBFk5ZN3Cagwx5RbA_Y__nUpe4nK00HbRENBgDySq4k2lqfkfUUGG7HWMs0r9Ik7neRB1holb0-RrkYFs4NVVkl1N078ryqDhTXoHM8_9Z9FiU9eEE53QGRchVO2Tmo85gynPqfsXVJghykMH56hsvag
{ "alg": "RS512", "kid": "VuHeO_srzhnkxzoTJc3TEmBaFGvHVqqWGEy74s3xVjM", "typ": "JWT" } . { "access_type": "BROKER", "app_id": "ce21628e-317b-4edb-bda6-0de661f24666", "applicant_person_id": "bf11454f-a2b0-4ab4-b8bd-c2abf8dac440", "applicant_user_id": "15c72e0b-c609-4ebd-bfc9-a45d33a73bc5", "aud": "EHealth", "client_id": "8a99ffdf-314e-4419-931d-a76f41f8c456", "exp": 1717874384, "grant_type": "pis_auth", "iat": 1686317458, "iss": "EHealth", "jti": "d771f7c4-3df5-4dfc-b446-603950e7e1a2", "nbf": 1686317457, "person_id": "bf11454f-a2b0-4ab4-b8bd-c2abf8dac440", "redirect_uri": "https://example_uri.com/redirect", "refresh_token": "bnpSNEV6YmtBUDZhM3lqLzZzU0F1Zz09", "scope": "app:read profile:read", "sub": "15c72e0b-c609-4ebd-bfc9-a45d33a73bc5", "typ": "access_token" } . dxurQjxcv_LQR9YiG7we0vZl8CKd1c2dZ2i8XhDUt7CNxLINFoLgpmcVnUSMf_Slk-YkXOELgT4sjyWkaeoZpWhcWfTeHMNh7KQzMH9Mnn_8_oGGc4yt3ZPYiHxng4KY2BqrLniPYel_FtaZoBKrfpwh6zh7RUdau_irOLIF6C_RTQ7BD-wOyCEeRjc2CchBFk5ZN3Cagwx5RbA_Y__nUpe4nK00HbRENBgDySq4k2lqfkfUUGG7HWMs0r9Ik7neRB1holb0-RrkYFs4NVVkl1N078ryqDhTXoHM8_9Z9FiU9eEE53QGRchVO2Tmo85gynPqfsXVJghykMH56hsvag

Хедер

Хедер JWT містить наступні поля:

Поле

Опис

Приклад

Поле

Опис

Приклад

alg

підпис або алгоритм шифрування, який використовується для створення JWT

RS512

kid

ідентифікатор закритого ключа, який використовується для підпису JWT

VuHeO_srzhnkxzoTJc3TEmBaFGvHVqqWGEy74s3xVjM

typ

тип токену

JWT

Сервіс Mithril використовує RS512 JWT алгоритм підпису з типом токену JWT.

Пейлоад

Пейлоад JWT містить наступні поля:

Поле

Опис

Приклад

Поле

Опис

Приклад

aud

audiene (для кого або для чого призначений токен)

EHealth

exp

термін дії токена та час у форматі unix

1714840995

iat

дата і час генерації токена в unix-форматі

1680685233

nbf

маркер недійсний до дати й часу у форматі unix

1680685232

jti

унікальний ідентифікатор маркера у форматі uuid

481aa86b-7bfa-462c-8bcb-1a9e9edff192

sub

предмет маркера (user_id) у форматі uuid

9cf6f222-2a6a-4ef2-b7f0-6331e1d706ae

iss

назва емітенту токену

EHealth

access_type

тип доступу клієнта, якщо BROKER - потрібна додаткова перевірка api-ключа, якщо DIRECT - перевірка api-ключа не потрібна

BROKER

app_id

identifier of approval between user, applicant user and client that was used to issue access token

ce21628e-317b-4edb-bda6-0de661f24666

applicant_user_id

ідентифікатор користувача, який ініціював створення токену доступу для суб’єкта (користувача) у форматі uuid

9cf6f222-2a6a-4ef2-b7f0-6331e1d706ae

applicant_person_id

ідентифікатор особи у форматі uuid, який пов’язаний з користувачем, який ініціював генерацію токену доступу для суб’єкта (користувача), якщо існує

38a72dcc-8cb4-4204-ab3a-913fe1dadb8f

client_id

ідентифікатор клієнта, який ініціював генерацію токену доступу для суб’єкта (користувача) у форматі uuid

8a99ffdf-314e-4419-931d-a76f41f8c456

grant_type

тип дозволу, який використовувався для видачі токену доступу, якщо існує

authorization_code

person_id

ідентифікатор особи у форматі uuid, пов’язаний із суб’єктом токену (користувачем), якщо такий існує

38a72dcc-8cb4-4204-ab3a-913fe1dadb8f

redirect_uri

uri перенаправлення, який використовувався клієнтом для створення токену доступу, якщо існує

https://example_uri.com/redirect

refresh_token

токен оновлення, створений за допомогою маркера доступу

Tm5hRkx2U0hIOUxPMjg5ZlFlK3gzQT09

scope

список скоупів, дозволених виданим токеном доступу, розділених пробілом

app:read profile:read

typ

тип токену

access_token

Сервіс Mithril формує поле пейлоад на основі даних, що використовуються для генерації токену (user_id, client_id, перелік запитаних скоупів, токен сессії, etc).

Підпис

Підпис JWT містить підпис вмісту токену з використанням алгоритму, описаного в полі alg із заголовка.

Служба Mithril використовує асиметричний алгоритм підпису – вміст маркера підписується за допомогою закритого ключа, який зберігається в параметрі JWT_PRIVATE_KEY.

Перевірка токену доступу в форматі JWT

Токен доступу у форматі JWT потрібно надіслати в той самий заголовок авторизації для будь-якого методу, який вимагає токен доступу.

curl --location 'https://api.dev.edenlab.com.ua/api/persons/5865b87e-0da0-4d28-8d3c-e24e0d4813e3/verification' \ --header 'api-key: b1lPV3d3blRHRHdOYVYrYmNPU0tJdz09' \ --header 'Authorization: Bearer eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJFSGVhbHRoIiwiZXhwIjoxNjg1NDU4MDkxLCJpYXQiOjE2ODMwMzg4OTEsImlzcyI6IkVIZWFsdGgiLCJqdGkiOiI5OTU2NjVmYS1iYjAyLTQyZWMtYWYyYi1iOWJhMWQyZDkyNDQiLCJuYmYiOjE2ODMwMzg4OTAsInN1YiI6eyJjbGllbnRfaWQiOiI0ZjEyMDUzYi00NTBlLTQyNzUtOWJlYi0yNjU1YjgxNjAxM2YiLCJncmFudF90eXBlIjoiYXV0aG9yaXphdGlvbl9jb2RlIiwicmVkaXJlY3RfdXJpIjoiaHR0cHM6Ly9leGFtcGxlNzMuY29tIiwic2NvcGUiOiJkZWNsYXJhdGlvbjpyZWFkIGRlY2xhcmF0aW9uX3JlcXVlc3Q6YXBwcm92ZSBkZWNsYXJhdGlvbl9yZXF1ZXN0OnJlYWQgZGVjbGFyYXRpb25fcmVxdWVzdDpzaWduIGRlY2xhcmF0aW9uX3JlcXVlc3Q6d3JpdGUgZGl2aXNpb246cmVhZCBlbXBsb3llZTpyZWFkIGVtcGxveWVlX3JlcXVlc3Q6YXBwcm92ZSBlbXBsb3llZV9yZXF1ZXN0OnJlamVjdCBlbXBsb3llZV9yZXF1ZXN0OnJlYWQgbGVnYWxfZW50aXR5OnJlYWQgb3RwOnJlYWQgb3RwOndyaXRlIHBlcnNvbjpyZWFkIHBhdGllbnRfc3VtbWFyeTpyZWFkIGVuY291bnRlcjp3cml0ZSBlbmNvdW50ZXI6cmVhZCBlbmNvdW50ZXI6Y2FuY2VsIGVwaXNvZGU6d3JpdGUgZXBpc29kZTpyZWFkIGpvYjpyZWFkIGNvbmRpdGlvbjpyZWFkIGNvbmRpdGlvbjp3cml0ZSBvYnNlcnZhdGlvbjpyZWFkIG9ic2VydmF0aW9uOndyaXRlIGltbXVuaXphdGlvbjpyZWFkIGltbXVuaXphdGlvbjp3cml0ZSBhbGxlcmd5X2ludG9sZXJhbmNlOnJlYWQgYWxsZXJneV9pbnRvbGVyYW5jZTp3cml0ZSBtZWRpY2F0aW9uX3N0YXRlbWVudDpyZWFkIG1lZGljYXRpb25fc3RhdGVtZW50OndyaXRlIGRldmljZTpyZWFkIGRldmljZTp3cml0ZSByaXNrX2Fzc2Vzc21lbnQ6cmVhZCByaXNrX2Fzc2Vzc21lbnQ6d3JpdGUgbWVkaWNhdGlvbl9kaXNwZW5zZTpyZWFkIGRydWdzOnJlYWQgbWVkaWNhdGlvbl9yZXF1ZXN0OmRldGFpbHMgbWVkaWNhdGlvbl9yZXF1ZXN0OnJlYWQgbWVkaWNhdGlvbl9yZXF1ZXN0OnJlamVjdCBtZWRpY2F0aW9uX3JlcXVlc3Q6cmVzZW5kIG1lZGljYXRpb25fcmVxdWVzdF9yZXF1ZXN0OnJlYWQgbWVkaWNhdGlvbl9yZXF1ZXN0X3JlcXVlc3Q6cmVqZWN0IG1lZGljYXRpb25fcmVxdWVzdF9yZXF1ZXN0OnNpZ24gbWVkaWNhdGlvbl9yZXF1ZXN0X3JlcXVlc3Q6d3JpdGUgZGlhZ25vc3RpY19yZXBvcnQ6cmVhZCBkaWFnbm9zdGljX3JlcG9ydDp3cml0ZSBkaWFnbm9zdGljX3JlcG9ydDpjYW5jZWwgcHJvY2VkdXJlOnJlYWQgcHJvY2VkdXJlOndyaXRlIHByb2NlZHVyZTpjYW5jZWwgc2VydmljZV9yZXF1ZXN0Om1ha2VpbnByb2dyZXNzIHNlcnZpY2VfcmVxdWVzdDpjb21wbGV0ZSBzZXJ2aWNlX3JlcXVlc3Q6cmVjYWxsIHNlcnZpY2VfcmVxdWVzdDpjYW5jZWwgc2VydmljZV9yZXF1ZXN0OndyaXRlIHNlcnZpY2VfcmVxdWVzdDpyZWFkIHNlcnZpY2VfcmVxdWVzdDp1c2UgYXBwcm92YWw6Y3JlYXRlIHByb2dyYW1fc2VydmljZTpyZWFkIG1lZGljYXRpb25fYWRtaW5pc3RyYXRpb246cmVhZCBtZWRpY2F0aW9uX2FkbWluaXN0cmF0aW9uOndyaXRlIGhlYWx0aGNhcmVfc2VydmljZTpyZWFkIGVtcGxveWVlX3JvbGU6cmVhZCBwZXJzb25fcmVxdWVzdDp3cml0ZSBwZXJzb25fcmVxdWVzdDpyZWFkIGF1dGhlbnRpY2F0aW9uX21ldGhvZF9yZXF1ZXN0OndyaXRlIGNhcmVfcGxhbjpyZWFkIGFwcHJvdmFsOnJlYWQgYXBwcm92YWw6Y2FuY2VsIGNhcmVfcGxhbjp3cml0ZSBjb21wb3NpdGlvbjpjcmVhdGUgY29tcG9zaXRpb246c2lnbiBjb21wb3NpdGlvbjpjYW5jZWwgY29tcG9zaXRpb246cmVhZCBjb21wb3NpdGlvbjpzZWFyY2ggbGljZW5zZTpyZWFkIGNsaW5pY2FsX2ltcHJlc3Npb246cmVhZCBydWxlX2VuZ2luZV9ydWxlOnJlYWQgbWVkaWNhbF9ldmVudF9jb250ZXh0OnJlYWQgY2xpbmljYWxfaW1wcmVzc2lvbjp3cml0ZSBwZXJzb25fdmVyaWZpY2F0aW9uOmRldGFpbHMgcGVyc29uX3ZlcmlmaWNhdGlvbjp3cml0ZSBwZXJzb25fZW1lcmdlbmN5X2NvbnRhY3Q6cmVhZCIsInVzZXJfaWQiOiIzNWM4YTFhOS05YzkzLTRmMDEtYmNlZS1jNTJjZjU3NjI2YzQifSwidHlwIjoiYWNjZXNzIn0.vfV6CbHmMOisqbUyLqtaau5gxN2UcPwq8rdg2pQLpvAAAT0mZ0PWO9DtveTjArkDi0x5bU5uf8yOKo882zCAuFip1mWOJNhu0qSHr3uMQMCwvwrtY0JGavuf0wA81hlSCah4mE3U5iPBPuPYgfqMiELxxh1-Mz1OsYQsJfS_KTK_8LSW41eBSmcm-3piRXFeDIOiE2REQDG3GNvkXEJ37SCBJTMv8r_ypVcjymRkWk32_ajrqWS17Y66ax-D59Cp2bf1TWNtk8KKIqnIf-g-nG-sSzruoZGtbNzp6mW4yPZkZ-zG5hVpv0u_i50BU8FittPwNLa-EjX3IDqUUrWwpw'

Токени доступу у форматі JWT перевіряються лише службою Kong, якщо пройдено всі перевірки токенів – список скоупів з поля scope використовується для перевірки доступу до запитуваного методу.

JWT перевіряється згідно наступних кроків:

  1. Перевірити формат заголовку авторизації

    1. якщо токен передається в JWT – перевірити, що це JWT

    2. в іншому випадку – перевірте його за допомогою перевірки існуючого формату токену (згідно перевірки токену методом mithril)

  2. Перевірити підпис JWT з публічним ключем, який зберігається в параметрах JWT_PUBLIC_KEY та JWT_PUBLIC_KEY_OLD

    1. в разі, якщо підпис JWT не перевірено по збереженому публічному ключу - повернути 401 ('access_denied')

  3. Перевірити строк дії токену по полю exp, що значення більше ніж now()

    1. в разі, якщо поле exp не існує або дата закінчення строку в минулому - повернути 401 ('access_denied')

  4. Перевірити, що емітент в полі iss рівний значенню ‘EHeath’

    1. в разі, якщо поле iss не існує або містить будь-які інші дані - повернути 401 ('access_denied')

  5. Перевірити, що audience токену з поля aud рівне значенню ‘EHealth’

    1. в разі, якщо поле aud не існує або містить будь-які інші дані - повернути 401 ('access_denied')

  6. Перевірити, що токен не входить до чорного списку в базі даних кешу Redis за значеннями полів із пейлоад (jti, sub, client_id):

    1. перевірити, що ключ blacklist_jti_<<jti>> не існує (наприклад, blacklist_jti_481aa86b-7bfa-462c-8bcb-1a9e9edff192);

    2. перевірити, що ключ blacklist_user_id_<<sub>> не існує (наприклад, blacklist_user_id_481aa86b-7bfa-462c-8bcb-1a9e9edff192);

    3. перевірити, що ключ blacklist_client_id_<<client_id>> не існує (наприклад, blacklist_client_id_8a99ffdf-314e-4419-931d-a76f41f8c456);

    4. перевірити, що ключ blacklist_user_id_client_id_<<sub>>_<<client_id>> не існує (напраклад, blacklist_user_id_client_id_481aa86b-7bfa-462c-8bcb-1a9e9edff192_8a99ffdf-314e-4419-931d-a76f41f8c456);

      1. якщо будь-який із ключів існує в базі даних кешу Redis - повернути 401 ('access_denied')

    5. перевірити, що ключ blacklist_app_id_<<app_id>> не існує (для прикладу, blacklist_app_id_ce21628e-317b-4edb-bda6-0de661f24666);

      1. якщо будь-який із ключів існує в базі даних кешу Redis - повернути 401 ('access_denied')

ЕСОЗ - публічна документація