@gerege-systems/eid-mongolia-sdk 0.13.0 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +78 -102
- package/dist/button.cjs +952 -0
- package/dist/button.d.cts +79 -0
- package/dist/button.d.ts +79 -0
- package/dist/button.js +923 -0
- package/dist/index.cjs +350 -282
- package/dist/index.d.cts +122 -142
- package/dist/index.d.ts +122 -142
- package/dist/index.js +349 -278
- package/package.json +12 -4
package/README.md
CHANGED
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
RP-API v3, Smart-ID нийцтэй. Бүрэн баримт: <https://developer.eidmongolia.mn/>.
|
|
6
6
|
|
|
7
7
|
> ⚠️ SDK **backend**-д ажиллана: бүх дуудлага API secret (`rp_sk_…`)-ээр баталгаажна, secret-ийг браузер/гар утсанд
|
|
8
|
-
> хэзээ ч задлахгүй. Браузерт зөвхөн таны backend-ийн өгсөн холбоос/QR/товч харагдана — «eID-ээр нэвтрэх» товч
|
|
9
|
-
>
|
|
10
|
-
>
|
|
8
|
+
> хэзээ ч задлахгүй. Браузерт зөвхөн таны backend-ийн өгсөн холбоос/QR/товч харагдана — «eID-ээр нэвтрэх» товч
|
|
9
|
+
> (`/button`) ч таны backend-ийг л дуудна (§1a). `@gerege-systems/eid-mongolia-sdk/browser`-ийн legacy device-link
|
|
10
|
+
> туслахууд 2026-10-07-оос ажиллахгүй (§4).
|
|
11
11
|
|
|
12
12
|
## Суулгах
|
|
13
13
|
|
|
@@ -22,125 +22,104 @@ Node.js ≥ 22 (global `fetch`, `node:crypto`).
|
|
|
22
22
|
RP-г eID Mongolia-гийн оператор бүртгэнэ — хүсэлтээ <eIDsupport@gerege.com> эсвэл 7777-3773-аар гаргана
|
|
23
23
|
(нийтийн `POST /v3/rp-applications` 2026-10-14-нөөс засвартай: `503 rp_applications_maintenance`). Оператор
|
|
24
24
|
баталсны дараа **relyingPartyUUID** ба **API secret** (`rp_sk_…`) олгогдоно; secret **зөвхөн нэг удаа** харагдана.
|
|
25
|
-
Шаардлагатай мэдээлэл (байгууллага, зорилго `AUTH`/`SIGN`, `callbackHosts
|
|
25
|
+
Шаардлагатай мэдээлэл (байгууллага, зорилго `AUTH`/`SIGN`, `callbackHosts`…):
|
|
26
26
|
<https://developer.eidmongolia.mn/#registration>.
|
|
27
27
|
|
|
28
|
-
## 1a. «eID-ээр нэвтрэх»
|
|
28
|
+
## 1a. «eID-ээр нэвтрэх» — нэг товч
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
(
|
|
33
|
-
хуудасгүйгээр шууд eID апп нээгдэнэ. Гэрээ: <https://developer.eidmongolia.mn/#oidc>.
|
|
30
|
+
Smart-ID-тэй RP-үүдийн хэв маяг: хөтөчид **нэг товч**, бүх eID дуудлага таны **backend**-д (API secret-ээр). SDK хоёр
|
|
31
|
+
хэсэг өгнө — backend-ийн бэлэн урсгал `createEidLogin` ба хөтчийн товч `@gerege-systems/eid-mongolia-sdk/button`.
|
|
32
|
+
Доорх нь §2/§4-ийн RP-API (device link v3, push, `ResponseValidator`)-ийг л ашиглана; тусдаа протокол биш.
|
|
34
33
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
34
|
+
| Хаана | Юу болно |
|
|
35
|
+
|---|---|
|
|
36
|
+
| Desktop хөтөч | Цонх: QR (секунд тутам шинэчлэгдэнэ) + «регистрийн дугаараар утас руу мэдэгдэл» (push), үлдсэн хугацаа, шууд төлөв |
|
|
37
|
+
| Утасны хөтөч | Товч → `start?mode=web2app` → сервер 302 → eID апп (Web2App). Апп баталгаажуулаад `/auth/eid/callback` руу буцаана |
|
|
38
|
+
| Backend | session эхлүүлэх, QR угсрах (`sessionSecret` серверт), poll, `validateAuth` (гинж + ACSP_V2 + `flowType` + Web2App-д `userChallengeVerifier`) → таны `onSuccess` |
|
|
39
39
|
|
|
40
|
-
|
|
41
|
-
RP-д `AUTH` эрх, OIDC асаалттай, `redirect_uri` (https, ≤ 10) бүртгэлтэй байна — authorize/token-ий `redirect_uri`
|
|
42
|
-
бүртгэлтэйтэй **тэмдэгт бүрээрээ** таарах ёстой. Иргэний ETSI дугаар (`pnomn` claim) хэрэгтэй бол `PNOMN` эрх
|
|
43
|
-
хүсэж, `scope: "openid pnomn"`. Token endpoint-д RP-ийн IP allowlist мөрдөгдөнө.
|
|
40
|
+
**Endpoint-ууд** (`/auth/eid` дор — eID сервер Web2App буцах замыг үргэлж `/auth/eid/callback` болгож нормчилдог):
|
|
44
41
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
`
|
|
49
|
-
|
|
42
|
+
| | Хүсэлт | Хариу |
|
|
43
|
+
|---|---|---|
|
|
44
|
+
| `POST /auth/eid/start` | `{"mode":"qr"}` эсвэл `{"mode":"push","idCode":"УБ12345678"}` (JSON заавал) | `{mode, vc, qr?, expiresIn}` + `Set-Cookie: eid_login` |
|
|
45
|
+
| `GET /auth/eid/start?mode=web2app` | утасны хөтөч (товчны навигаци) | `302` → eID апп |
|
|
46
|
+
| `GET /auth/eid/status` | cookie | `PENDING` (+шинэ `qr`, `expiresIn`) · `WAIT_CALLBACK` · `OK` (`redirect`, `data`) · `FAILED` (`error`) · `EXPIRED` |
|
|
47
|
+
| `GET /auth/eid/callback` | апп буцаана: `?sessionId&userChallengeVerifier` | `303` → `onSuccess`-ийн `redirect` / `successRedirect`, алдаа бол `failureRedirect?eid_error=<код>` |
|
|
50
48
|
|
|
51
|
-
|
|
52
|
-
import { Agent } from "undici";
|
|
53
|
-
const oidc = new EidOidcClient({
|
|
54
|
-
clientId: process.env.EID_RP_UUID!,
|
|
55
|
-
clientSecret: process.env.EID_SECRET!,
|
|
56
|
-
redirectUri: "https://bank.example.mn/auth/eid/callback",
|
|
57
|
-
dispatcher: new Agent({ connect: { cert: clientCertPem, key: clientKeyPem } }), // RP-API-ийн cert
|
|
58
|
-
useMtlsEndpointAliases: true, // token → https://rp.eidmongolia.mn/oauth2/token
|
|
59
|
-
});
|
|
60
|
-
```
|
|
49
|
+
**Backend** (нэг instance-ийг модулийн түвшинд):
|
|
61
50
|
|
|
62
51
|
```ts
|
|
63
|
-
import {
|
|
52
|
+
import { EidClient, createEidLogin } from "@gerege-systems/eid-mongolia-sdk";
|
|
64
53
|
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
redirectUri: "https://bank.example.mn/auth/eid/callback",
|
|
69
|
-
// issuer анхдагч https://login.eidmongolia.mn, scope анхдагч "openid"
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
const TX = "eid_oidc_tx";
|
|
73
|
-
const cookieOpts = { httpOnly: true, secure: true, sameSite: "lax", path: "/auth/eid", maxAge: 600_000 } as const;
|
|
74
|
-
|
|
75
|
-
// GET /auth/eid/login — товчны href
|
|
76
|
-
app.get("/auth/eid/login", async (_req, res) => {
|
|
77
|
-
const a = await oidc.createAuthorization(); // { url, state, nonce, codeVerifier }
|
|
78
|
-
res.cookie(TX, JSON.stringify({ state: a.state, nonce: a.nonce, codeVerifier: a.codeVerifier }), cookieOpts);
|
|
79
|
-
res.set("Cache-Control", "no-store").redirect(302, a.url);
|
|
54
|
+
const eid = new EidClient({
|
|
55
|
+
credentials: { rpUUID: process.env.EID_RP_UUID!, rpName: "Интернэт банк", apiSecret: process.env.EID_SECRET! },
|
|
56
|
+
trust: { trustAnchorsPem: [process.env.EID_NATIONAL_ROOT_CA_PEM!] },
|
|
80
57
|
});
|
|
81
58
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
59
|
+
export const eidLogin = createEidLogin({
|
|
60
|
+
client: eid,
|
|
61
|
+
callbackUrl: "https://bank.example.mn/auth/eid/callback", // host нь RP-ийн callbackHosts-д; утасны урсгалд заавал
|
|
62
|
+
async onSuccess(id) {
|
|
63
|
+
// id.etsi (PNOMN-…) — хэрэглэгчийг ҮҮГЭЭР таньна; id.givenName/surname (латин), id.person (кирилл, байвал)
|
|
64
|
+
const user = await users.findOrCreateByEtsi(id.etsi);
|
|
65
|
+
const sid = await sessions.create(user.id); // ШИНЭ session (session fixation)
|
|
66
|
+
return {
|
|
67
|
+
redirect: "/dashboard",
|
|
68
|
+
headers: { "Set-Cookie": `app_session=${sid}; Path=/; HttpOnly; Secure; SameSite=Lax` },
|
|
69
|
+
};
|
|
70
|
+
},
|
|
71
|
+
// store: redisStore, // олон instance / serverless бол (анхдагч — процессын санах ой)
|
|
72
|
+
// rateLimit: (key) => redisLimiter.allow(key), // "start:<ip>", "push:<idCode>"; анхдагч push 3/мин нэг дугаарт
|
|
96
73
|
});
|
|
97
74
|
```
|
|
98
75
|
|
|
99
|
-
Next.js App Router
|
|
100
|
-
callback → `oidc.handleCallback(request.nextUrl.searchParams, tx)` (зөвхөн query уншина — прокси ард host хамаагүй).
|
|
76
|
+
Next.js App Router — `app/auth/eid/[action]/route.ts`:
|
|
101
77
|
|
|
102
|
-
|
|
103
|
-
|
|
78
|
+
```ts
|
|
79
|
+
import { eidLogin } from "@/lib/eid";
|
|
80
|
+
export const dynamic = "force-dynamic";
|
|
81
|
+
export const GET = (req: Request) => eidLogin.handle(req);
|
|
82
|
+
export const POST = (req: Request) => eidLogin.handle(req);
|
|
83
|
+
```
|
|
104
84
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
padding: 0 1.25rem; border: 1px solid #d0d5dd; border-radius: 6px; background: #fff; color: #111827;
|
|
113
|
-
font: 500 1rem/1 system-ui, sans-serif; text-decoration: none; }
|
|
114
|
-
.eid-login:hover { background: #f5f7fa; }
|
|
115
|
-
.eid-login:focus-visible { outline: 2px solid currentColor; outline-offset: 2px; }
|
|
116
|
-
</style>
|
|
85
|
+
Express:
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
app.use("/auth/eid", express.json(), async (req, res) => {
|
|
89
|
+
const r = await eidLogin.handleRequest({ method: req.method, url: req.originalUrl, headers: req.headers, body: req.body, ip: req.ip });
|
|
90
|
+
res.status(r.status).set(r.headers).send(r.body);
|
|
91
|
+
});
|
|
117
92
|
```
|
|
118
93
|
|
|
119
|
-
|
|
120
|
-
татаж өөрийн хостоос үйлчил). Google/Apple-ийн товч шиг саармаг (цагаан, хүрээтэй) — таны сайтын бусад нэвтрэх
|
|
121
|
-
товчтой зэрэгцэж болно. Жишээ: <https://demo.eidmongolia.mn>.
|
|
94
|
+
**Хөтөч** — Web Component (React/Vue/энгийн HTML аль нь ч):
|
|
122
95
|
|
|
123
|
-
|
|
96
|
+
```html
|
|
97
|
+
<script type="module">import "@gerege-systems/eid-mongolia-sdk/button";</script>
|
|
98
|
+
<eid-login-button start-url="/auth/eid/start" status-url="/auth/eid/status" lang="mn"></eid-login-button>
|
|
99
|
+
<script type="module">
|
|
100
|
+
document.querySelector("eid-login-button").addEventListener("eid-login-success", (e) => {
|
|
101
|
+
// e.detail = { state: "OK", redirect, data } — preventDefault() хийвэл redirect хийхгүй
|
|
102
|
+
});
|
|
103
|
+
</script>
|
|
104
|
+
```
|
|
124
105
|
|
|
125
|
-
|
|
126
|
-
(`
|
|
127
|
-
|
|
128
|
-
|
|
106
|
+
эсвэл `mountEidLoginButton(el, { startUrl, statusUrl, lang: "en", successUrl, onSuccess, onError })`.
|
|
107
|
+
Атрибут: `lang` (`mn` | `en`), `mode` (`auto` анхдагч — утас → Web2App, бусад → QR цонх; `qr`; `app`), `success-url`.
|
|
108
|
+
Үйл явдал: `eid-login-success`, `eid-login-error` (`detail.error`: `USER_REFUSED…`, `VALIDATION`, `EXPIRED` …).
|
|
109
|
+
Дизайн нь eID нэвтрэх хуудсынх (лого, өнгө, light/dark); `--eid-accent`, `--eid-bg` г.м. CSS хувьсагчаар, `::part(button)`-оор
|
|
110
|
+
тохируулна. Гадны хамааралгүй (QR encoder дотроо), цонх нь focus trap, Esc, `aria-live` төлөвтэй.
|
|
129
111
|
|
|
130
112
|
**Аюулгүй байдал.**
|
|
131
113
|
|
|
132
|
-
- `
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
- `
|
|
136
|
-
|
|
137
|
-
`
|
|
138
|
-
|
|
139
|
-
- `
|
|
140
|
-
-
|
|
141
|
-
(`prefersEphemeralWebBrowserSession = false`), Android Custom Tabs. **WebView хориотой.** `redirect_uri` = таны
|
|
142
|
-
https Universal Link / App Link (custom scheme дэмжихгүй). `state` / `nonce` / `codeVerifier` апп-ын санах ойд;
|
|
143
|
-
code-ийг таны backend `client_secret`-ээр солино (`client_secret`-ийг аппад хадгалахгүй).
|
|
114
|
+
- `sessionToken`, `sessionSecret`, `rpChallenge` серверт (store) үлдэнэ; хөтөчид зөвхөн HttpOnly, Secure, SameSite=Lax cookie
|
|
115
|
+
(`<sessionId>.<binding>`, store-д binding-ийн SHA-256). Status ба callback зөвхөн нэвтрэлтийг **эхлүүлсэн хөтөчид** хариулна —
|
|
116
|
+
өөр хөтчид нээгдсэн callback URL (verifier-тэй ч) хүлээн авагдахгүй (login CSRF).
|
|
117
|
+
- `start` POST нь JSON заавал (simple request биш → cross-origin preflight), `Sec-Fetch-Site: cross-site` → 403.
|
|
118
|
+
- `OK` нь зөвхөн `validateAuth` амжилттай үед: QR → `flowType=QR`, push → `Notification`, утас → `Web2App` + callback-ийн
|
|
119
|
+
`userChallengeVerifier`. Web2App session-ийг poll дуусгахгүй (`WAIT_CALLBACK`). `onSuccess` нэг session-д нэг л удаа
|
|
120
|
+
(store-ийн `delete` атомар байх ёстой — Redis `DEL`).
|
|
121
|
+
- `onSuccess`-ийн `data` хөтөчид очно — нууц бүү оруул. Иргэний бүртгэлтэй эсэхийг push алдаагаар задлахгүй (`eid_unavailable`).
|
|
122
|
+
- Олон instance / serverless (Vercel г.м.) дээр анхдагч санах ойн store ажиллахгүй — `EidLoginStore` (`get`/`set`/`delete`)-ийг Redis-ээр.
|
|
144
123
|
|
|
145
124
|
## 2. Нэвтрэлт (push)
|
|
146
125
|
|
|
@@ -445,7 +424,6 @@ OK ирж болзошгүй. Иймд `ResponseValidator`:
|
|
|
445
424
|
| `ApiError` | бусад HTTP алдаа (`.status`, `.body`, серверийн `.code`, `.retryAfterMs`, `.headers`, `.retryable` — ж: 404 `ORG_NOT_FOUND`) |
|
|
446
425
|
| `ResponseTooLargeError` | хариу SDK-ийн хязгаараас их (JSON 4 MiB, PDF `pdfMaxBytes`) — `.op`, `.limit` |
|
|
447
426
|
| `NetworkError` | timeout/сүлжээ (`.op` — таних тэмдэггүй зам, `.timeout`) |
|
|
448
|
-
| `EidOidcError` | «eID-ээр нэвтрэх» (OIDC) — `.code`: `access_denied`, `login_required`, `state_mismatch`, `invalid_grant`, `invalid_id_token`, `server_error` … |
|
|
449
427
|
| `DeviceLinkError` | device-link холбоос угсрах боломжгүй (`deviceLinkBase` https биш, token/secret/lang хэлбэр, төрөлд хэрэгтэй талбар дутуу) |
|
|
450
428
|
|
|
451
429
|
## mTLS (eIDAS qualified орчин)
|
|
@@ -469,9 +447,7 @@ npm test # build + node --test
|
|
|
469
447
|
### Гэрээний шалгалт
|
|
470
448
|
|
|
471
449
|
SDK-ийн дууддаг RP-API зам бүр (`src/contract.ts`) live [`/.well-known/eid`](https://rp.eidmongolia.mn/.well-known/eid)-ийн
|
|
472
|
-
`endpoints`-д байх
|
|
473
|
-
талбарууд) [discovery](https://login.eidmongolia.mn/.well-known/openid-configuration)-тэй таарах ёстой. Discovery-д
|
|
474
|
-
байгаа ч SDK хамраагүй замууд WARN (fail биш). Сүлжээ шаарддаг тул `npm test`-д ордоггүй:
|
|
450
|
+
`endpoints`-д байх ёстой. Discovery-д байгаа ч SDK хамраагүй замууд WARN (fail биш). Сүлжээ шаарддаг тул `npm test`-д ордоггүй:
|
|
475
451
|
|
|
476
452
|
```bash
|
|
477
453
|
npm run test:contract
|