fr05t1k / esia
OpenID ESIA authenticating
Requires
- php: ^8.3
- ext-json: *
- ext-openssl: *
- php-http/discovery: ^1.19
- psr/http-client: ^1.0
- psr/http-factory: ^1.0
- psr/http-message: ^1.1 || ^2.0
- psr/log: ^1.1 || ^2.0 || ^3.0
Requires (Dev)
- codeception/codeception: ^5.1
- codeception/module-asserts: ^3.0
- ergebnis/composer-normalize: ^2.43
- friendsofphp/php-cs-fixer: ^3.64
- nyholm/psr7: ^1.8
- php-http/mock-client: ^1.6
- phpstan/phpstan: ^2.0
- symfony/http-client: ^6.4 || ^7.0
Suggests
- guzzlehttp/guzzle: PSR-18 HTTP client and PSR-17 factories (^7.9)
- nyholm/psr7: Lightweight PSR-7/PSR-17 message and factory implementation
- symfony/http-client: Alternative PSR-18 HTTP client
This package is auto-updated.
Last update: 2026-08-16 16:16:40 UTC
README
PHP-компонент для авторизации через Единую систему идентификации и аутентификации (ЕСИА) портала «Госуслуги».
⚠️ Обновляйтесь на свой страх и риск. У авторов и контрибьюторов не всегда есть доступ к реальной среде ЕСИА: и промышленный контур, и тестовый стенд
esia-portal1.test.gosuslugi.ruдоступны только из РФ и требуют зарегистрированной ИС и ГОСТ-сертификата. Поэтому изменения проверяются офлайн и против реального ЕСИА могут быть не протестированы. Если обновление заработало (или нет) с реальной средой, пожалуйста, оставьте короткий отчёт в обсуждении: Отчёты о совместимости с реальной средой ЕСИА.
Основная цель библиотеки — получение токена ЕСИА. Получив токен, вы можете выполнять запросы к API; библиотека предоставляет самые базовые методы, а не все существующие в API ЕСИА.
Оглавление
- Требования
- Установка
- Быстрый старт
- Организации и роли
- OAuth state (защита от CSRF)
- Конфигурация
- Проверка JWT (подпись и claim'ы)
- Подпись запросов (сигнеры)
- Работа с токеном и oid
- Обратная совместимость и обновление
- Тестирование
- Лицензия
Требования
PHP >= 8.3, расширения ext-openssl и ext-json.
Библиотека не привязана к конкретному HTTP-клиенту и использует стандарты PSR-18 (HTTP Client) и PSR-17 (HTTP Factories). Необходимо установить любую их реализацию, например Guzzle:
composer require guzzlehttp/guzzle
Подойдёт любой PSR-18 клиент (Guzzle, Symfony HTTP Client, и т.д.) вместе с
PSR-17 фабрикой (nyholm/psr7, guzzlehttp/psr7 и т.п.). Реализация
находится автоматически (через php-http/discovery), либо её можно передать
явно в конструктор OpenId:
$esia = new \Esia\OpenId($config, $psr18Client, $psr17RequestFactory, $psr17StreamFactory);
Установка
При помощи composer:
composer require --prefer-dist fr05t1k/esia
Или добавьте в composer.json
"fr05t1k/esia" : "^3.0"
Быстрый старт
Пример получения ссылки для авторизации
<?php $config = new \Esia\Config([ 'clientId' => 'INSP03211', 'redirectUrl' => 'http://my-site.com/response.php', 'portalUrl' => 'https://esia-portal1.test.gosuslugi.ru/', 'scope' => ['fullname', 'birthdate'], ]); $esia = new \Esia\OpenId($config); $esia->setSigner(new \Esia\Signer\SignerPKCS7( 'my-site.com.pem', 'my-site.com.pem', 'password', '/tmp' )); ?> <a href="<?=$esia->buildUrl()?>">Войти через портал госуслуги</a>
После редиректа на ваш redirectUrl вы получите в $_GET['code'] код для получения токена
Пример получения токена и информации о пользователе
$esia = new \Esia\OpenId($config); // Вы можете использовать токен в дальнейшем вместе с oid $token = $esia->getToken($_GET['code']); $personInfo = $esia->getPersonInfo(); $addressInfo = $esia->getAddressInfo(); $contactInfo = $esia->getContactInfo(); $documentInfo = $esia->getDocInfo(); // Организации и роли пользователя (нужен полученный токен): $roles = $esia->getRoles(); // членство в организациях + роли (одним запросом) $organizations = $esia->getOrganizations(); // подробные данные по каждой организации
Организации и роли
Метод getRoles() возвращает список организаций, в которых состоит пользователь,
вместе с ролями (эндпоинт rs/prns/{oid}/roles). Данные приходят одним запросом —
каждый элемент содержит oid организации, краткое/полное наименование, ОГРН,
флаги chief/admin и т.д. Если пользователь не состоит ни в одной организации,
возвращается пустой массив.
Метод getOrganizations() использует коллекцию rs/prns/{oid}/orgs, элементы
которой — ссылки на ресурсы организаций; каждая ссылка догружается и возвращается
полными данными организации.
// Токен уже получен через getToken() $roles = $esia->getRoles(); foreach ($roles as $role) { echo $role['shortName'], PHP_EOL; } $organizations = $esia->getOrganizations();
OAuth state (защита от CSRF)
state — одноразовый идентификатор запроса авторизации. Библиотека генерирует
его автоматически при вызове buildUrl()/getToken() и сохраняет в Config,
поэтому его можно получить и сверить при возврате пользователя:
$config = new \Esia\Config([/* ... */]); $esia = new \Esia\OpenId($config); $url = $esia->buildUrl(); $state = $config->getState(); // сохраните в сессии // ... после редиректа сверьте $_GET['state'] с сохранённым значением
Свой state можно передать и напрямую в buildUrl($state) — удобно, когда
нужно различать несколько одновременно открытых окон входа. Переданное значение
попадёт в URL и сохранится в Config:
$url = $esia->buildUrl($myState);
Можно задать свой state — через параметр конфигурации или setState() — тогда
он будет использован вместо сгенерированного:
$config = new \Esia\Config([/* ... */, 'state' => $myState]); // или $config->setState($myState);
Конфигурация
| Параметр | По умолчанию | Описание |
|---|---|---|
clientId |
— | ID вашего приложения. |
redirectUrl |
— | URL, куда будет перенаправлен ответ с кодом. |
portalUrl |
https://esia-portal1.test.gosuslugi.ru/ |
Домен портала для авторизации (только домен), по умолчанию — тестовая среда. Для продуктивной среды укажите https://esia.gosuslugi.ru/. |
codeUrlPath |
aas/oauth2/v2/ac |
URL для получения кода авторизации. Прежний путь aas/oauth2/ac выведен из эксплуатации; при необходимости старое значение можно вернуть через этот параметр. |
tokenUrlPath |
aas/oauth2/v3/te |
URL для получения токена. Прежний путь aas/oauth2/te выведен из эксплуатации; при необходимости старое значение можно вернуть через этот параметр. |
clientCertificateHash |
пусто | Хэш (fingerprint) сертификата системы-клиента в hex-формате. Обязателен для актуального эндпоинта получения токена aas/oauth2/v3/te (иначе ЕСИА вернёт ESIA-007014). Сертификат должен быть предварительно зарегистрирован в ЕСИА и привязан к УЗ системы-клиента. Значение — отпечаток сертификата по SHA-256 в hex (например, openssl x509 -in cert.pem -noout -fingerprint -sha256); точный способ вычисления см. в методических рекомендациях ЕСИА. Если не задан, не отправляется (обратная совместимость). |
scope |
fullname birthdate gender email mobile id_doc snils inn |
Запрашиваемые права у пользователя. |
privateKeyPath |
— | Путь до приватного ключа. |
privateKeyPassword |
— | Пароль от приватного ключа. |
certPath |
— | Путь до сертификата. |
tmpPath |
— | Путь до директории, где будет проходить подпись (должна быть доступна для записи). |
state |
пусто | OAuth-идентификатор запроса (анти-CSRF). Если не задан, генерируется автоматически при buildUrl()/getToken() и сохраняется в Config (доступен через getState()). Можно задать свой — он будет использован вместо сгенерированного. |
esiaCertPath |
пусто | Путь до сертификата подписи ЕСИА (для продуктивной среды — GOST-2012). Если задан, полученный JWT автоматически проверяется: подпись, exp/nbf/iat, iss и аудитория (aud/client_id). Если не задан, проверка пропускается (обратная совместимость). |
esiaTokenIssuer |
пусто | Ожидаемое значение claim iss в токене. Если не задано, iss не проверяется. |
tokenLeeway |
60 |
Допустимое отклонение (в секундах) при проверке временных claim'ов (exp, nbf, iat) для компенсации рассинхронизации часов. |
Проверка JWT (подпись и claim'ы)
По умолчанию библиотека не проверяет подпись полученного от ЕСИА токена — это
сохраняет обратную совместимость. Чтобы включить проверку, укажите путь до
сертификата подписи ЕСИА через esiaCertPath (и, при необходимости,
esiaTokenIssuer):
$config = new \Esia\Config([ // ... остальные параметры 'esiaCertPath' => '/path/to/esia-signing-cert.pem', 'esiaTokenIssuer' => 'http://esia.gosuslugi.ru/', ]); $esia = new \Esia\OpenId($config); // getToken выбросит наследника InvalidTokenException при некорректном токене: // SignatureInvalidException — неверная подпись, // TokenExpiredException — истёк срок (exp) или ещё не действителен (nbf), // InvalidClaimException — неверный iss / аудитория (aud/client_id). $token = $esia->getToken($_GET['code']);
Проверка сделана подключаемой (pluggable): вы можете передать собственную
реализацию \Esia\Token\TokenValidatorInterface (например, с проверкой
GOST-подписи через CryptoPro) через \Esia\OpenId::setTokenValidator().
Стандартная реализация \Esia\Token\JwtValidator проверяет подпись через
\Esia\Token\OpenSslSignatureVerifier (RSA из коробки; алгоритмы GOST-2012 —
при наличии GOST-движка в OpenSSL).
Подпись запросов (сигнеры)
Для получения токена запрос к ЕСИА должен быть подписан. ЕСИА требует подпись
ГОСТ Р 34.10-2012 (RSA больше не поддерживается в продуктивной среде).
Сигнер задаётся через \Esia\OpenId::setSigner() и должен реализовывать
\Esia\Signer\SignerInterface. Доступны следующие реализации:
| Сигнер | Механизм | Требования |
|---|---|---|
\Esia\Signer\SignerPKCS7 |
Нативный openssl_pkcs7_sign() |
Стандартный PHP с ext-openssl. Не умеет ГОСТ в обычной сборке OpenSSL — подходит только для тестов/RSA. |
\Esia\Signer\CliSignerPKCS7 |
Вызов openssl smime -engine gost |
OpenSSL, собранный с GOST-движком (libengine-gost-openssl1.1), в PATH. Ключ и сертификат ГОСТ в PEM. |
\Esia\Signer\CliCryptoProSigner |
Вызов утилиты csptest |
Установленный КриптоПро CSP с утилитой csptest. Ключ ГОСТ в контейнере CSP, указывается по имени контейнера. |
\Esia\Signer\CryptoProSigner |
PHP-расширение КриптоПро (\CPRawSignature) |
Проприетарное PHP-расширение КриптоПро. Сертификат ГОСТ в хранилище My текущего пользователя. |
Пример с CLI-сигнером ГОСТ (OpenSSL + GOST-движок):
$esia->setSigner(new \Esia\Signer\CliSignerPKCS7( '/path/to/gost-cert.pem', '/path/to/gost-key.pem', 'key-password', '/tmp' ));
Пример с КриптоПро через утилиту csptest (подпись формируется по
методическим рекомендациям ЕСИА: «сырое» значение подписи разворачивается
побайтово и кодируется в base64 url-safe):
$esia->setSigner(new \Esia\Signer\CliCryptoProSigner( 'my-container', // имя контейнера ключа в CSP 'password', // пароль контейнера (если задан) 'csptest', // путь до csptest (по умолчанию 'csptest') '/tmp' // каталог для временных файлов (по умолчанию системный) ));
Пример с КриптоПро через PHP-расширение:
$esia->setSigner(new \Esia\Signer\CryptoProSigner( '745187e5c161cd2e3130d886f9df4492fa270685', // отпечаток сертификата 'pin' // PIN контейнера (если задан) ));
Все сигнеры поддерживают PSR-3 логгер через setLogger().
Сигнер и логгер также можно передать сразу в конструктор \Esia\OpenId
(удобно для DI-контейнеров), не прибегая к сеттерам:
$esia = new \Esia\OpenId( $config, $httpClient, // ?Psr\Http\Client\ClientInterface $requestFactory, // ?Psr\Http\Message\RequestFactoryInterface $streamFactory, // ?Psr\Http\Message\StreamFactoryInterface $signer, // ?Esia\Signer\SignerInterface $logger // ?Psr\Log\LoggerInterface );
Любой из аргументов можно передать как null — тогда используется значение по
умолчанию. Методы setSigner() и setLogger() продолжают работать.
Работа с токеном и oid
Токен — JWT-токен, который вы получаете от ЕСИА для дальнейшего взаимодействия.
oid — уникальный идентификатор владельца токена.
Как получить oid?
Есть 2 способа:
- oid содержится в JWT-токене — расшифровав его;
- после получения токена oid сохраняется в
Configи доступен так:
$esia->getConfig()->getOid();
Переиспользование токена
Дополнительно укажите токен и идентификатор в конфиге:
$config->setToken($jwt); $config->setOid($oid);
Обратная совместимость и обновление
Начиная с версии 3.0 значения по умолчанию обновлены под актуальный API ЕСИА
(Методические рекомендации): эндпоинты aas/oauth2/v2/ac и aas/oauth2/v3/te,
portalUrl использует https://. Актуальный aas/oauth2/v3/te требует параметр
clientCertificateHash. Если вы полагались на прежние значения по умолчанию
(aas/oauth2/ac, aas/oauth2/te, http://), задайте их явно через Config.
Обновляетесь с 2.x? См. подробное руководство по обновлению 2.4.2 → 3.0.0.
Тестирование
Основное покрытие в библиотеке — офлайн, без обращения к ЕСИА (HTTP-моки,
JWT-фикстуры, локальный ГОСТ round-trip и end-to-end против локального
мок-сервера ЕСИА). Живой тестовый стенд esia-portal1.test.gosuslugi.ru
доступен только из РФ и требует зарегистрированной ИС и ГОСТ-сертификата.
Быстрый запуск:
composer install vendor/bin/codecept build # генерирует акторов для наборов unit и e2e vendor/bin/codecept run # все наборы vendor/bin/codecept run e2e # только end-to-end против мок-сервера
Подробнее — как устроено офлайн-тестирование, как запускать ГОСТ-тесты и на что
библиотека настроена для реального стенда ЕСИА по умолчанию — в руководстве по
тестированию (docs/testing.md).
Лицензия
Распространяется под лицензией MIT.