eID Gerege — TypeScript RP SDK¶
@eid-mongolia/sdk — Relying Party (RP)-ийн backend дээр ажилладаг Node.js/TypeScript сан.
RP-API (/v3) руу хийх бүх дуудлагыг (нэвтрэлт, гарын үсэг, session poll) нэг EidClient-д
цуглуулж, дээр нь хариуны крипто-баталгаажуулалт (cert chain + signature) нэмнэ.
Энэ бол docs/RP_INTEGRATION.md-д тайлбарласан raw HTTP гэрээний
typed wrapper — ижил endpoint, ижил аюулгүйн загвар, гэхдээ challenge үүсгэх, session
давтаж poll хийх, гэрчилгээ шалгах зэргийг таны оронд хийнэ.
⚠️ Зөвхөн server-side. API secret (
rp_sk_…) браузер/гар утсанд хэзээ ч задрахгүй. SDK ньnode:crypto-д тулгуурладаг тул browser bundle биш.
Эх код: sdk/typescript/src/
1. Суулгах¶
- Node.js ≥ 18 (global
fetch,node:crypto). - ESM ба CommonJS хоёуланг гаргадаг (
import/require).
Package нэр, engine шаардлага: sdk/typescript/package.json.
2. RP бүртгүүлэх¶
RP-г оператор урьдчилан бүртгэнэ (docs/RP_INTEGRATION.md §1). Admin console-оор:
admin.eidmongolia.mn → Холбогдогч тал (RP) → + Шинэ RP.
Бүртгэмэгц UUID ба API secret (rp_sk_…) гарна — secret зөвхөн нэг удаа харагдана.
Эдгээрийг RpCredentials-д дамжуулна:
| Талбар | Утга |
|---|---|
rpUUID |
relying_parties-д бүртгэлтэй RP UUID |
rpName |
Иргэнд харагдах RP нэр (≤ 32 байт UTF-8) |
apiSecret |
API secret (rp_sk_…) — зөвхөн backend-д |
3. Client тохируулах¶
EidClient нь бүх flow-ийн үүд:
import { EidClient } from "@eid-mongolia/sdk";
const eid = new EidClient({
baseUrl: "https://rp-api.eidmongolia.mn", // /v3-гүйгээр — SDK нэмнэ
credentials: {
rpUUID: process.env.EID_RP_UUID!,
rpName: "Хаан Банк",
apiSecret: process.env.EID_SECRET!, // rp_sk_…
},
trust: { trustAnchorsPem: [process.env.EID_ROOT_CA_PEM!] }, // production-д ЗААВАЛ
});
ClientConfig-ийн бүх талбар (client.ts):
| Талбар | Заавал | Утга |
|---|---|---|
baseUrl |
✅ | RP-API суурь URL. SDK /v3-ийг нэмнэ. |
credentials |
✅ | RpCredentials (дээрх). apiSecret хоосон бол constructor алдана. |
trust |
production-д ✅ | TrustConfig — trust anchor (Root CA) + validator тохиргоо. |
defaultCertificateLevel |
QUALIFIED (default) эсвэл ADVANCED. |
|
timeoutMs |
HTTP timeout (мс). Default 15000. | |
dispatcher |
undici Dispatcher — mTLS client cert (§8). |
|
fetchImpl |
fetch орлуулагч (тест). |
Constructor нь baseUrl эсвэл credentials.apiSecret дутвал шууд Error шиднэ.
EidClient нь дараах дэд API-уудыг ил гаргана:
| Талбар | Класс | Үүрэг |
|---|---|---|
eid.auth |
AuthApi |
Нэвтрэлт эхлүүлэх (push / QR) |
eid.sign |
SignApi |
Гарын үсэг эхлүүлэх (digest) |
eid.session |
SessionApi |
Үр дүн poll хийх (long-poll) |
eid.validator |
ResponseValidator |
Хариуг крипто-баталгаажуулах |
4. Үндсэн flow-ууд¶
4.1 Нэвтрэлт (push)¶
eid.auth-ийн method бүр дотроо санамсаргүй rpChallenge үүсгэж, буцаах session-д хавсаргана
(validator үүнийг signature-тэй тулгана). Эх: auth.ts.
// РД / иргэний дугаар / ETSI — аль нь ч болно (сервер төрлийг таьна)
const s = await eid.auth.notificationByEtsi("PNOMN-111949212017", [
{ type: "displayTextAndPIN", displayText60: "Хаан Банк-д нэвтрэх" },
]);
showToUser(s.vc); // ← иргэний утсан дээр харагдах баталгаажуулах код (VC)
const result = await eid.session.waitForResult(s.sessionId); // long-poll (§4.3)
const who = eid.validator.validateAuth(result, s.rpChallenge); // ← крипто-баталгаажуулна
console.log(who.documentNumber, who.subject); // баталгаажсан иргэн
AuthApi-ийн method-ууд:
| Method | Endpoint | Хариу |
|---|---|---|
notificationByEtsi(id, interactions, opts?) |
POST /authentication/notification/etsi/{id} |
NotificationSession |
notificationByDocument(documentNumber, interactions, opts?) |
POST /authentication/notification/document/{id} |
NotificationSession |
deviceLinkAnonymous(interactions, opts?) |
POST /authentication/device-link/anonymous |
DeviceLinkSession |
deviceLinkByEtsi(id, interactions, opts?) |
POST /authentication/device-link/etsi/{id} |
DeviceLinkSession |
- notification (push) — иргэний утас руу шууд мэдэгдэл очно.
NotificationSessionнь{ sessionId, vc, rpChallenge }буцаана. - device-link (QR/App2App) — QR код/deeplink үүсгэхэд.
DeviceLinkSessionнь{ sessionId, sessionToken, sessionSecret, deviceLinkBase, rpChallenge }буцаана.
AuthOptions (auth.ts):
certificateLevel (энэ session-д default-ыг дарж бичих), callbackUrl (same-device App2App
буцах URL — өгвөл initialCallbackUrl-аар илгээнэ).
4.2 Гарын үсэг (qualified signature)¶
RP нь баримтынхаа SHA-256 digest-ийг илгээж, хариунд ирэх signature-ийг тэр digest +
иргэний cert-ийн эсрэг шалгана. Эх: sign.ts.
import { sha256Base64 } from "@eid-mongolia/sdk";
const digest = sha256Base64(pdfBytes); // баримтын SHA-256 (base64)
const s = await eid.sign.digestByEtsi("PNOMN-111949212017", digest, [
{ type: "displayTextAndPIN", displayText60: "Зээлийн гэрээнд гарын үсэг зурах" },
]);
showToUser(s.vc);
const result = await eid.session.waitForResult(s.sessionId);
const sig = eid.validator.validateSign(result, digest); // digest-ийн эсрэг баталгаажна
console.log(sig.signatureValueB64, sig.subject);
SignApi-ийн method-ууд:
| Method | Endpoint | Тайлбар |
|---|---|---|
digestByEtsi(id, digestB64, interactions, opts?) |
POST /signature/notification/etsi/{id} |
Бэлэн digest-ээр (бинар баримт) |
digestByDocument(documentNumber, digestB64, interactions, opts?) |
POST /signature/notification/document/{id} |
Бэлэн digest-ээр (тодорхой төхөөрөмж) |
textByEtsi(id, text, interactions, opts?) |
POST /signature/notification/etsi/{id} |
Текстийн digest-ийг дотроо тооцоод sign |
SignOptions: certificateLevel, callbackUrl, hashType (SHA256 default, эсвэл
SHA384/SHA512 — digest-ийг өөрөө бэлдсэн бол тааруулна).
Тэмдэглэл: sign flow-ийн
NotificationSession.rpChallengeнь хоосон ("") — signature нь challenge биш digest-ийн эсрэг баталгаажна (sign.ts:54).
4.3 Session poll (long-poll)¶
SessionApi (session.ts)
нь RP-API-ийн GET /session/{id}?timeoutMs=-ийг long-poll хэлбэрээр давтана.
| Method | Тайлбар |
|---|---|
poll(sessionId, serverPollMs = 30000) |
Нэг удаагийн long-poll; serverPollMs хүртэл хүлээнэ. |
waitForResult(sessionId, opts?) |
COMPLETE болтол давтаж poll хийнэ. opts = { maxWaitMs?, serverPollMs? }. |
- Default
serverPollMs = 30_000,maxWaitMs = 150_000(иргэн хариу өгөхгүй бол таслана). - HTTP timeout нь серверийн poll-оос 10 сек урт тавигдана.
waitForResultнь хугацаа дуусталCOMPLETEболоогүй бол сүүлчийн (RUNNING) үр дүнг буцаана — validator түүнийг дуусаагүй session мэтValidationErrorболгоно.
SessionResult талбарууд (types.ts):
state, endResult, documentNumber, certificateDerB64, certificateLevel,
signatureValueB64, signatureAlgorithm, interactionTypeUsed.
5. Хариуны баталгаажуулалт — яагаад validator заавал¶
⚠️
endResult === "OK"гэдэгт дангаар нь итгэхгүй. RP-API эвдэрсэн/proxy хийгдсэн бол хуурамч OK ирж болзошгүй.
ResponseValidator (validator.ts)
дараах алхмуудыг гүйцэтгэнэ:
state === COMPLETE && endResult === OK(эс бөгөөсSessionFailedError).- Иргэний гэрчилгээг trust anchor (Gerege Root CA) хүртэл chain-аар баталгаажуулна (issuer нь CA байх ёстой, гүн ≤ 8).
- Гэрчилгээ хүчинтэй хугацаанд (
validFrom/validTo,clockSkewMsзөвшөөрнө) + шаардсанcertificateLevelхангах (QUALIFIEDdefault). - Гарын үсгийг иргэний public key-ээр шалгана:
- auth → ACSP_V2 payload (
LP("ACSP_V2") ‖ LP(rpChallenge) ‖ LP(SPKI)) дээр - sign → RP-ийн өгсөн digest дээр
Аль нэг алхам бүтэлгүйтвэл ValidationError шиднэ — хариунд итгэхгүй.
Нийтийн method:
| Method | Буцаах | Тайлбар |
|---|---|---|
validateAuth(result, rpChallengeB64) |
VerifiedIdentity |
{ documentNumber, certificate, subject, certificateLevel } |
validateSign(result, digestB64) |
VerifiedSignature |
{ documentNumber, signatureValueB64, signatureAlgorithm, certificate, subject } |
checkRevocation(cert) |
Promise<void> |
OCSP/CRL hook (доор). |
5.1 TrustConfig тохиргоо¶
client.trust-д дамжина (validator.ts):
| Талбар | Утга |
|---|---|
trustAnchorsPem |
Root CA PEM-үүд. Production-д ЗААВАЛ. Хоосон бол ValidationError (allowUntrusted-аар л алгасна). |
intermediatesPem |
Intermediate CA PEM-үүд (leaf ↔ root). |
requiredLevel |
Шаардах certLevel (default QUALIFIED). |
clockSkewMs |
Validity шалгахад зөвшөөрөх цагийн зөрүү (default 0). |
allowUntrusted |
true бол chain шалгахгүй — зөвхөн dev/тест. |
revocation |
OCSP/CRL шалгагч hook (RevocationChecker). |
revocationMode |
"hard-fail" (default; unknown-г татгалзана) эсвэл "soft-fail". |
Revocation.
revocationhook тохируулаагүй бол cert-ийн revoke төлөв шалгахгүй — энэ нь RP-ийн үүрэг. ТохируулбалvalidateAuth/validateSign-ийн дарааawait eid.validator.checkRevocation(who.certificate)дуудна (revocation нь сүлжээ I/O тул async, validate нь sync).
6. Алдаа боловсруулалт¶
Бүх алдаа EidError-оос удамшина (errors.ts):
| Алдаа | Утга | Талбар |
|---|---|---|
AuthenticationError |
HTTP 401 — API secret буруу/байхгүй | — |
ForbiddenError |
HTTP 403 — IP allowlist / mTLS зөвшөөрөөгүй | — |
ApiError |
Бусад HTTP алдаа (4xx/5xx) | .status, .body |
NetworkError |
Timeout / сүлжээний алдаа | — |
SessionFailedError |
endResult ≠ OK (TIMEOUT, USER_REFUSED*, DOCUMENT_UNUSABLE, WRONG_VC…) |
.endResult |
ValidationError |
Cert chain / signature / level шалгалт бүтэлгүйтсэн | — |
import { SessionFailedError, ValidationError } from "@eid-mongolia/sdk";
try {
const result = await eid.session.waitForResult(s.sessionId);
const who = eid.validator.validateAuth(result, s.rpChallenge);
} catch (e) {
if (e instanceof SessionFailedError) {
// e.endResult: "USER_REFUSED" | "TIMEOUT" | … → UI мессеж, дахин оролдлого
} else if (e instanceof ValidationError) {
// хуурамч/proxy хийгдсэн байж болзошгүй — хариунд ИТГЭХГҮЙ
}
throw e;
}
7. Крипто туслахууд¶
node:crypto-д тулгуурласан экспорт (crypto.ts):
| Функц | Тайлбар |
|---|---|
sha256Base64(data) |
Текст/байтын SHA-256 digest (base64) — sign flow-ийн digest бэлдэхэд. |
randomChallenge(bytes = 64) |
Санамсаргүй RP challenge (base64). Auth method-ууд дотроо дууддаг. |
buildAcspV2Payload(rpChallengeB64, spkiDER) |
ACSP_V2 payload угсарна — validator ашигладаг. |
⚠️ ACSP_V2 payload нь сервер (
server/internal/crypto/acsp.go), утас, RP SDK гурвуулаа байт-ижил байх ёстой.LP(x) = 4-байт big-endian урт ‖ x.
8. mTLS (eIDAS qualified орчин)¶
Production RP-API-д client cert шаардвал undici Agent-ийг dispatcher-аар өгнө
(http.ts):
import { Agent } from "undici";
const eid = new EidClient({
baseUrl: "https://rp-api.eidmongolia.mn",
credentials: { /* … */ },
trust: { trustAnchorsPem: [ROOT_CA_PEM] },
dispatcher: new Agent({ connect: { cert: clientCertPem, key: clientKeyPem } }),
});
dispatcher өгвөл fetch дуудлага бүрд хэрэглэнэ (зөвхөн Node орчинд).
9. Raw HTTP хувилбартай холбоо¶
SDK нь docs/RP_INTEGRATION.md-ийн raw HTTP гэрээг яг дагадаг — endpoint, body талбар
(relyingPartyUUID, relyingPartyName, certificateLevel, signatureProtocol: "ACSP_V2",
interactions), Bearer auth бүгд ижил. SDK-гүйгээр шууд HTTP-ээр интеграцчлах, эсвэл endpoint-ийн
бүрэн жагсаалт, иргэнийг таних дугааруудыг үзэхийг хүсвэл:
- RP интеграцийн гарын авлага (raw HTTP)
- Ажиллаж буй жишээ RP client:
web/src/lib/rpclient.ts
10. Хөгжүүлэлт¶
Package: sdk/typescript/.
TypeScript нь reference implementation — Go/Python хувилбарууд үүний API гадаргуу, аюулгүйн
загвар (ResponseValidator), wire-contract-ийг дагана (sdk/README.md).