e-ID SSO нэгтгэх заавар
Таны platform дээр sso.gerege.mn-р дамжуулан e-ID Mongolia нэвтрэлт нэмнэ. OpenID Connect (OIDC) стандартаар ажиллана. Аливаа 3-р талын систем чөлөөтэй холбогдох боломжтой.
Тойм
Бүх 3-р талын platform-д нээлттэй
sso.gerege.mn нь аливаа систем, platform, апп-д нээлттэй OIDC provider. developer.gerege.mn дээр app бүртгүүлж client_id авахад хангалттай. Хэлний болон framework-ийн хязгаарлалтгүй — стандарт OIDC дэмжсэн дурын технологи ашиглаж болно.
sso.gerege.mn нь OpenID Connect 1.0 provider бөгөөд e-ID Mongolia смарт картаар баталгаажуулсан иргэний мэдээллийг OAuth 2.0 Authorization Code Flow-р 3-р талын системд дамжуулна.
Flow:
- Хэрэглэгч таны сайт дээр "e-ID-р нэвтрэх" товч дарна
- sso.gerege.mn руу redirect хийгдэнэ
- e-ID Mongolia смарт картаар нэвтэрнэ
- Таны callback URL руу authorization code-тэй буцна
- Сервер талаас code → access_token + id_token солилцоно
- ID token-оос иргэний мэдээлэл уншина
Алхам 1: App бүртгүүлэх
developer.gerege.mn/dashboard/apps/new хуудаснаас шинэ app бүртгүүлнэ.
App нэр
Таны системийн нэр (хэрэглэгчдэд харагдана)
Redirect URI
Нэвтрэлт амжилттай болсны дараа буцах URL. Жишээ: https://myapp.mn/api/auth/callback/gerege-sso
Scopes
openid (заавал) + profile, pos, social, payment
Анхааруулга
client_secret зөвхөн нэг удаа харагдана. Хадгалаагүй бол шинэ app үүсгэх шаардлагатай.
Алхам 2: OIDC тохиргоо
sso.gerege.mn нь стандарт OIDC Discovery endpoint дэмждэг:
https://sso.gerege.mn/.well-known/openid-configuration
Endpoint-ууд:
| Authorization | https://sso.gerege.mn/oauth/authorize |
| Token | https://sso.gerege.mn/oauth/token |
| UserInfo | https://sso.gerege.mn/oauth/userinfo |
| JWKS | https://sso.gerege.mn/.well-known/jwks.json |
| Introspect | https://sso.gerege.mn/oauth/introspect |
| Revoke | https://sso.gerege.mn/oauth/revoke |
Алхам 3: Authorization Request
Хэрэглэгчийг authorize endpoint руу redirect хийнэ:
GET https://sso.gerege.mn/oauth/authorize ?response_type=code &client_id=YOUR_CLIENT_ID &redirect_uri=https://myapp.mn/callback &scope=openid profile &state=random-csrf-token &nonce=random-nonce
Параметрүүд:
| response_type | code (заавал) |
| client_id | Dashboard-аас авсан client_id |
| redirect_uri | Бүртгүүлсэн redirect URI |
| scope | openid profile (нэмэлт: pos, social, payment) |
| state | CSRF хамгаалалт — random string |
| nonce | Replay attack-аас хамгаалах |
Алхам 4: Token Exchange
Callback URL дээр code авсны дараа token endpoint руу POST хийнэ:
POST https://sso.gerege.mn/oauth/token Content-Type: application/x-www-form-urlencoded grant_type=authorization_code &code=AUTHORIZATION_CODE &redirect_uri=https://myapp.mn/callback &client_id=YOUR_CLIENT_ID &client_secret=YOUR_CLIENT_SECRET
Хариу:
{
"access_token": "eyJhbGciOiJFUzI1NiI...",
"token_type": "Bearer",
"expires_in": 3600,
"id_token": "eyJhbGciOiJFUzI1NiI...",
"refresh_token": "dGhpcyBpcyBh..."
}Алхам 5: ID Token Claims
ID Token (JWT) decode хийхэд дараах мэдээлэл агуулагдана:
{
"sub": "eid-12345678",
"name": "БАТБОЛД Ганбаатар",
"given_name": "Ганбаатар",
"family_name": "БАТБОЛД",
"cert_serial": "ABC123DEF456",
"identity_assurance_level": "high",
"amr": ["eid"],
"locale": "mn-MN",
// pos, social scope нэмсэн үед:
"tenant_id": "t_abc123",
"tenant_role": "owner",
"plan": "pro",
"iss": "https://sso.gerege.mn",
"aud": "YOUR_CLIENT_ID",
"exp": 1744200000,
"iat": 1744196400,
"nonce": "your-nonce"
}Алхам 6: UserInfo Endpoint
Access token ашиглан нэмэлт мэдээлэл авах:
GET https://sso.gerege.mn/oauth/userinfo
Authorization: Bearer ACCESS_TOKEN
// Хариу:
{
"sub": "eid-12345678",
"name": "БАТБОЛД Ганбаатар",
"given_name": "Ганбаатар",
"family_name": "БАТБОЛД",
"cert_serial": "ABC123DEF456"
}Жишээ: Next.js
// lib/auth.ts
import NextAuth from "next-auth"
export const { handlers, signIn, signOut, auth } = NextAuth({
providers: [{
id: "gerege-sso",
name: "e-ID Mongolia",
type: "oidc",
issuer: "https://sso.gerege.mn",
clientId: process.env.EID_CLIENT_ID!,
clientSecret: process.env.EID_CLIENT_SECRET!,
authorization: { params: { scope: "openid profile" } },
}],
})
// .env.local
// EID_CLIENT_ID=dashboard-аас авсан client_id
// EID_CLIENT_SECRET=dashboard-аас авсан secretЖишээ: Go
package main
import (
"golang.org/x/oauth2"
"github.com/coreos/go-oidc/v3/oidc"
)
func main() {
ctx := context.Background()
provider, _ := oidc.NewProvider(ctx, "https://sso.gerege.mn")
oauth2Config := &oauth2.Config{
ClientID: os.Getenv("EID_CLIENT_ID"),
ClientSecret: os.Getenv("EID_CLIENT_SECRET"),
RedirectURL: "https://myapp.mn/callback",
Scopes: []string{oidc.ScopeOpenID, "profile"},
Endpoint: provider.Endpoint(),
}
// 1. Redirect
url := oauth2Config.AuthCodeURL("state", oidc.Nonce("nonce"))
http.Redirect(w, r, url, http.StatusFound)
// 2. Callback
token, _ := oauth2Config.Exchange(ctx, r.URL.Query().Get("code"))
rawIDToken, _ := token.Extra("id_token").(string)
verifier := provider.Verifier(&oidc.Config{ClientID: os.Getenv("EID_CLIENT_ID")})
idToken, _ := verifier.Verify(ctx, rawIDToken)
var claims struct {
Sub string `json:"sub"`
Name string `json:"name"`
GivenName string `json:"given_name"`
}
idToken.Claims(&claims)
}Жишээ: Python (Flask)
from authlib.integrations.flask_client import OAuth
oauth = OAuth(app)
oauth.register(
name="gerege",
server_metadata_url="https://sso.gerege.mn/.well-known/openid-configuration",
client_id="YOUR_CLIENT_ID",
client_secret="YOUR_CLIENT_SECRET",
client_kwargs={"scope": "openid profile"},
)
@app.route("/login")
def login():
redirect_uri = url_for("callback", _external=True)
return oauth.gerege.authorize_redirect(redirect_uri)
@app.route("/callback")
def callback():
token = oauth.gerege.authorize_access_token()
userinfo = token["userinfo"]
# userinfo["sub"], userinfo["name"], userinfo["given_name"]Жишээ: PHP (Laravel)
// config/services.php
'gerege' => [
'client_id' => env('EID_CLIENT_ID'),
'client_secret' => env('EID_CLIENT_SECRET'),
'redirect' => env('APP_URL') . '/auth/callback',
],
// Laravel Socialite custom provider
use Laravel\Socialite\Facades\Socialite;
Route::get('/login', fn() =>
Socialite::driver('gerege')
->scopes(['openid', 'profile'])
->redirect()
);
Route::get('/auth/callback', function () {
$user = Socialite::driver('gerege')->user();
// $user->getId() — sub
// $user->getName() — full name
// $user->getRaw() — бүх claims
});Scopes тайлбар
| Scope | Тайлбар | Нэмэлт claims |
|---|---|---|
openid | Заавал | sub, iss, aud, exp, iat |
profile | Хэрэглэгчийн мэдээлэл | name, given_name, family_name, cert_serial |
pos | POS Plugin API | tenant_id, tenant_role, plan |
social | Social Commerce API | tenant_id, tenant_role, plan |
payment | Payment API | tenant_id, tenant_role, plan |
Аюулгүй байдал
- state параметр — CSRF халдлагаас хамгаална. Санамсаргүй string үүсгэж session-д хадгалаад callback дээр тулгана.
- nonce параметр — ID Token дотор буцаж ирнэ. Replay attack-аас хамгаалахад хэрэглэнэ.
- HTTPS заавал — Redirect URI заавал HTTPS байх ёстой (localhost-г эс тооцвол).
- client_secret хамгаалалт — Secret-г зөвхөн сервер талд хадгална. Frontend-д ДАМЖУУЛАХГҮЙ.
- Token шалгалт — ID Token-ийн iss, aud, exp, nonce зэргийг заавал шалгана.
- Redirect URI тулгалт — Dashboard-д бүртгүүлсэн URI-тай яг тохирох ёстой.
Алдааны кодууд
| invalid_client | Буруу client_id эсвэл client_secret |
| invalid_redirect_uri | Бүртгэлгүй redirect URI |
| invalid_scope | Зөвшөөрөгдөөгүй scope |
| invalid_grant | Хугацаа дууссан эсвэл ашиглагдсан code |
| access_denied | Хэрэглэгч нэвтрэлтийг цуцалсан |
Тусламж
Асуудал гарвал dev@gerege.mn хаягаар холбогдоно уу. App бүртгэлийн бүх тохиргоог Dashboard → Apps хуудаснаас хийнэ.