# passport-esia-esm

> ESIA authentication strategy for Passport with GOST ciphers support

Latest version **0.1.0** (published 2022-04-19) · ISC license · 0 weekly downloads

## Install

```sh
npm install passport-esia-esm
pnpm add passport-esia-esm
yarn add passport-esia-esm
bun add passport-esia-esm
```

## Health

**Score 5/100 (F)** — status: abandoned.

Positive: no vulnerabilities.

Warnings: low downloads; no types; no esm support; pre 1.0.

Negative: insecure dependencies; abandoned; low maintenance score.

## Facts

| | |
|---|---|
| Version | 0.1.0 |
| Published | 2022-04-19 |
| First published | 2022-04-19 |
| Weekly downloads | 0 |
| License | ISC |
| TypeScript types | none |
| Module format | CommonJS |
| Node | >=7.6.0 |
| Dependencies | 6 |
| Unpacked size | 16.1 KB |
| Known vulnerabilities | 0 (+1 in 1 direct dependencies) |
| Install scripts | no |
| GitHub stars | 1 |
| Author | skylord |
| Maintainers | shika7200 |

## Links

- npm: https://www.npmjs.com/package/passport-esia-esm
- Repository: https://github.com/inkz/passport-esia
- Homepage: https://github.com/inkz/passport-esia#readme
- Issues: https://github.com/inkz/passport-esia/issues
- npm.io page: https://npm.io/package/passport-esia-esm

## Dependencies (6)

- [uuid](https://npm.io/package/uuid.md) ^7.0.0
- [pkijs](https://npm.io/package/pkijs.md) ^2.1.86
- [base64url](https://npm.io/package/base64url.md) ^3.0.1
- [node-gost](https://npm.io/package/node-gost.md) github:romansopov/node-gost
- [passport-oauth2](https://npm.io/package/passport-oauth2.md) ^1.4.0
- [@peculiar/webcrypto](https://npm.io/package/@peculiar/webcrypto.md) ^1.0.23

## Recent versions

- 0.1.0 (latest) — 2022-04-19

## README

# passport-esia

Модуль для Passport.js авторизации через ЕСИА с поддержкой ГОСТовского шифрования.

- не зависит от системного OpenSSL, всё шифрование на чистом JS через интерфейсы WebCrypto
- проверено в production окружении ЕСИА
- автоматически раскодирует и отдает JWT access token ЕСИА с проверкой подписи (если указан публичный ключ и только RSA)
- все ключи и сертификаты задаются в формате PEM (ГОСТовские контейнеры КриптоПро можно сконвертировать при помощи https://github.com/kov-serg/get-cpcert) 

## Использование

Устанавливается стандартно. Подключается аналогично любому модулю Passport. Пример:

	const passport = require('passport'),
			EsiaStrategy = require('passport-esia').Strategy;
	
	passport.use(new EsiaStrategy({
		ca_pub_key: "-----BEGIN PUBLIC KEY-----\
	MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAg4/V4iNjYrC4gBSM7OlD\
	bYHNqpyfUYkoRoZ+GGcTU/Vd47srTLlhFADtTcC4GangTY9p1zpm1DGO7nhVRb6I\
	UKWt49jwRApvH2k/vo4Nlou6bwqZeeg1BVJZRGBH5UtnZ5k5gR3qKyntb+RpG3sA\
	WfZQicH6yfoWbBS6ypfJ0EJ7GNxaeAn5akjSYMwFx4mRVG2pYo+Ly2jjd5XlbWhq\
	nMle6sROvR4y7SaudqW2Bg7sE/8ZrYGJRBdgMn5d83M6uxOEhp4yp8TP3+NnXAxI\
	keK4IMaBMwzfw/OGjbS8a/UMnN1EMT4bkXbk0z/Y/5guI2H1MrrgsIQs6VQorf9J\
	zwIDAQAB\
	-----END PUBLIC KEY-----",	// not required - only to verify JWT signature
		key: "-----BEGIN PRIVATE KEY-----\
	-----END PRIVATE KEY-----",
		certificate: "-----BEGIN CERTIFICATE-----\
	-----END CERTIFICATE-----",
		type: 'gost',		// or 'rsa' by default
		clientID: '<ID>',
		scope: 'fullname birthdate gender id_doc contacts mobile',
		callbackURL: 'https://example.com/esia',
		authorizationURL: 'https://esia.gosuslugi.ru/aas/oauth2/ac',
		tokenURL: 'https://esia.gosuslugi.ru/aas/oauth2/te',
	}, 
	async function(accessToken, refreshToken, token_payload, cb) {
		let info = { messages: [], esia: null };
		let user = false;
		
		if (token_payload) {		
			let esia = {
				oid: token_payload['urn:esia:sbj_id'],
				access: accessToken,
				refresh: refreshToken				
			};
			
			user = await User.updateOne({ esia_id: esia.oid }, { esia_tokens: _.omit(esia, ['oid']) });
			
			// If user not found - return ESIA info out of passport so other routines can use it
			if (!user) {
				info.esia = esia;
			}
		} else {
			info.messages.push('Ошибка проверки подписи ответа ЕСИА.');
		}
				
		return cb(null, user || false, info);
	}
	));

Для последующих вызовов API ЕСИА можно использовать встроенный в стратегию OAuth2, что-то типа:

	let esia = {
		oid: token_payload['urn:esia:sbj_id'],
		access: accessToken,
		refresh: refreshToken				
	};

	let EsiaStrategy = passport._strategy('esia');
	EsiaStrategy._oauth2.useAuthorizationHeaderforGET(true);
	EsiaStrategy._oauth2.getAsync = util.promisify(EsiaStrategy._oauth2.get);

	try {
		let userBaseUrl = 'https://esia.gosuslugi.ru/rs/prns/'+esia.oid;
		esia_user = JSON.parse(await EsiaStrategy._oauth2.getAsync(userBaseUrl, esia.access));
		if (!esia_user) {
			throw 'ESIA user empty';
		}
		if (esia_user.status != 'REGISTERED') {
			throw 'ESIA user not registered';
		}
		if (!esia_user.trusted) {
			throw 'ESIA user not verified';
		}
	} catch (e) {
		let err_data = {};
	
		if (e.data) {
			err_data = JSON.parse(e.data);
		}
	
		// Expired token
		// TODO: repeat request and request fresh token
		if (err_data.code && err_data.code == 'ESIA-005013') {
			console.log('Устарели ключи авторизации - пожалуйста, повторите вход в ЕСИА.');
		}
		console.log('Ошибка получения данных пользователя из ЕСИА.');
	}

***

Copyright (c) 2020 skylord <me@skylord.ru>

Copyright (c) 2018 inkz <inkz@xakep.ru>

---
_Source: https://npm.io/package/passport-esia-esm · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
