Allows to authenticate in ESIA and get authenticated individual personal information.
Implemented as adapter to the PHP League's OAuth 2.0 Client.
To install, use composer:
composer require ekapusta/oauth2-esia
Usage is the same as the normal client, using Ekapusta\OAuth2Esia\Provider\EsiaProvider
as the provider:
use Ekapusta\OAuth2Esia\Provider\EsiaProvider;
use Ekapusta\OAuth2Esia\Security\JWTSigner\OpenSslCliJwtSigner;
use Ekapusta\OAuth2Esia\Security\Signer\OpensslPkcs7;
$provider = new EsiaProvider([
'clientId' => 'XXXXXX',
'redirectUri' => 'https://your-system.domain/auth/finish/',
'defaultScopes' => ['openid', 'fullname', '...'],
// For work with test portal version
// 'remoteUrl' => 'https://esia-portal1.test.gosuslugi.ru',
// 'remotePublicKey' => EsiaProvider::RESOURCES.'esia.test.public.key',
// For work with GOST3410_2012_256 signatures (instead of default RS256)
// 'remoteCertificatePath' => EsiaProvider::RESOURCES.'esia.gost.prod.public.key',
], [
'signer' => new OpensslPkcs7('/path/to/public/certificate.cer', '/path/to/private.key'),
// For work with GOST3410_2012_256 signatures (instead of default RS256)
// 'remoteSigner' => new OpenSslCliJwtSigner('/path/to/openssl'),
]);
- If you use RSA keys, then
OpensslPkcs7
is enough. - If you use GOST keys and compiled PHP with GOST ciphers, then
OpensslPkcs7
is enough. - If you use GOST keys and have openssl-compatible tool, then use
OpensslCli
. It hastoolpath
param. - If you use GOST keys and you are docker-addict, then you can use
'toolpath' => 'docker run --rm -i -v $(pwd):$(pwd) -w $(pwd) rnix/openssl-gost openssl'
.
- If your system electronic signature algorythm is default RS256, then do nothing. Under the hood it uses Sha256 remote signer.
- If you use GOST3410_2012_256 signature, then use
OpenSslCliJwtSigner
, passing to it path toopenssl
tool. For dockers pass to it something likedocker run --rm -i -v $(pwd):$(pwd) -v /tmp/tmp -w $(pwd) rnix/openssl-gost openssl'
./tmp
volume is important there!
Auth flow is standard.
// https://your-system.domain/auth/start/
$authUrl = $provider->getAuthorizationUrl();
$_SESSION['oauth2.esia.state'] = $provider->getState();
header('Location: '.$authUrl);
exit;
// https://your-system.domain/auth/finish/?state=...&code=...
if ($_SESSION['oauth2.esia.state'] !== $_GET['state']) {
exit('The guard unravels the crossword.');
}
$accessToken = $provider->getAccessToken('authorization_code', ['code' => $_GET['code']]);
$esiaPersonData = $provider->getResourceOwner($accessToken);
var_export($esiaPersonData->toArray());
If you don't like classes with about 20 public methods, there is simplified facade-class.
use Ekapusta\OAuth2Esia\EsiaService;
$service = new EsiaService($provider);
// https://your-system.domain/auth/start/
$_SESSION['oauth2.esia.state'] = $service->generateState();
$authUrl = $service->getAuthorizationUrl($_SESSION['oauth2.esia.state']);
header('Location: '.$authUrl);
exit;
// https://your-system.domain/auth/finish/?state=...&code=...
$esiaPersonData = $service->getResourceOwner($_SESSION['oauth2.esia.state'], $_GET['state'], $_GET['code'])
var_export($esiaPersonData->toArray());
{
"resourceOwnerId": 1000404446,
"stateFacts": [
"EntityRoot"
],
"firstName": "Имя006",
"lastName": "Фамилия006",
"middleName": "Отчество006",
"birthDate": "26.05.2000",
"birthPlace": "Москва",
"gender": "F",
"trusted": true,
"citizenship": "RUS",
"snils": "000-000-600 06",
"inn": "585204118212",
"updatedOn": 1523386683,
"contacts": {
"stateFacts": [
"hasSize"
],
"size": 3,
"eTag": "5F535ACCAEB3018D0AAA8C46027E3CF2C4BD0197",
"elements": [
{
"stateFacts": [
"Identifiable"
],
"id": 14216773,
"type": "EML",
"vrfStu": "VERIFIED",
"value": "EsiaTest006@yandex.ru",
"verifyingValue": "EsiaTest006@yandex.ru",
"vrfValStu": "VERIFYING",
"isCfmCodeExpired": true,
"eTag": "17DCA3945F1B8B54496F59EB146BDC7DADAD7BC8"
},
{
"stateFacts": [
"Identifiable"
],
"id": 14249750,
"type": "PHN",
"vrfStu": "NOT_VERIFIED",
"value": "+7(840)0000006",
"eTag": "943C1145E4973324599CD0E4FF136186502C93C5"
},
{
"stateFacts": [
"Identifiable"
],
"id": 14244504,
"type": "MBT",
"vrfStu": "VERIFIED",
"value": "+7(000)0000006",
"verifyingValue": "+7(111)1111111",
"vrfValStu": "VERIFYING",
"isCfmCodeExpired": true,
"eTag": "F3AA3B18B35BC12E53E0B7A7EAF13EC41EBD02AD"
}
]
},
"addresses": {
"stateFacts": [
"hasSize"
],
"size": 2,
"eTag": "47B43F0210344E272F338073C382C5955651C5E2",
"elements": [
{
"stateFacts": [
"Identifiable"
],
"id": 530,
"type": "PLV",
"addressStr": "г Чебоксары, пр-кт Мира",
"fiasCode": "bb5f4fab-64ea-4042-a61b-9b2bdb55442d",
"flat": "1",
"countryId": "RUS",
"house": "1",
"zipCode": "428022",
"city": "Чебоксары",
"street": "Мира",
"region": "Чувашская Республика",
"eTag": "3553085EBBC08CEBFD73957B7D5BAFDFDA096CCA"
},
{
"stateFacts": [
"Identifiable"
],
"id": 15893,
"type": "PRG",
"addressStr": "г Чебоксары, пр-кт Мира",
"fiasCode": "bb5f4fab-64ea-4042-a61b-9b2bdb55442d",
"flat": "1",
"countryId": "RUS",
"house": "1",
"zipCode": "428022",
"city": "Чебоксары",
"street": "Мира",
"region": "Чувашская Республика",
"eTag": "C90BE244DC0650255C9D3078C7C7EDEA8013BB6E"
}
]
},
"documents": {
"stateFacts": [
"hasSize"
],
"size": 2,
"eTag": "E752C6CFC8CBAE112527BF2AA07CB0A173143065",
"elements": [
{
"stateFacts": [
"EntityRoot"
],
"id": 3571,
"type": "RF_PASSPORT",
"vrfStu": "VERIFIED",
"series": "5303",
"number": "925695",
"issueDate": "01.01.2006",
"issueId": "006006",
"issuedBy": "УФМС006",
"eTag": "2E1F79E93B9DF6F5A579F95069630742D41C6AFB"
},
{
"stateFacts": [
"EntityRoot"
],
"id": 21213,
"type": "RF_DRIVING_LICENSE",
"vrfStu": "NOT_VERIFIED",
"series": "1222",
"number": "884455",
"issueDate": "01.09.2014",
"expiryDate": "01.08.2024",
"eTag": "E9D14F10321D0021A1267B8D363B22B102387735"
}
]
},
"vehicles": {
"stateFacts": [
"hasSize"
],
"size": 1,
"eTag": "9D0855F880F882EBCFD93C329C4720D5DB4058D9",
"elements": [
{
"stateFacts": [
"Identifiable"
],
"id": 17743,
"name": "Моя птичка",
"numberPlate": "А123АА111",
"regCertificate": {
"series": "1231",
"number": "231231"
},
"eTag": "A99823275D311CB97A371A420A59AA6BB08B42B7"
}
]
},
"status": "REGISTERED",
"verifying": false,
"rIdDoc": 3571,
"containsUpCfmCode": false,
"eTag": "61F2A6BF9D17B97E6B56F8B10EB28A7C814FF0B4"
}
Node is used for interactive headless chrome auth bot.
vendor/bin/phpunit --debug
There are three ESIA user identification levels:
- simple
- standard
- confrimed
Information system can ask info about user from individuals register.
ESIA user could be:
- individual
- individual entrepreneur (individual + flag "is entrepreneur")
- individual connected to legal entities accounts
- individual connected to public authorities accounts
Users after individual can be only of confirmed identification level.
After user's permission his/her info can be read through REST.
To get some info about user system should ask it through "scope" param. Same param entered in paper-written application for connection to ESIA.
Scope is analog of permissions in mobile apps, but for user's data.
Here are list of possible scopes: fullname, birthdate, gender, snils, inn, id_doc, birthplace, medical_doc, military_doc, foreign_passport_doc, drivers_licence_doc, vehicles, email, mobile, contacts, kid_fullname.
ESIA REST supports both RSA2048+SHA256 and GOST3410-2001+GOST341194 algos.
There are two ways to authenticate user: SAML 2.0 and OpenID Connect 1.0 (OAuth 2.0 extension). SAML 2.0 is only for public authorities.
For legal entities OpenID Connect is used.
ESIA from Russian "ЕСИА", which is "Единая система идентификации и аутентификации". Translated as "Unified identification and authentication system".