Нээлттэй — Бүх platform-д зориулсан

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:

  1. Хэрэглэгч таны сайт дээр "e-ID-р нэвтрэх" товч дарна
  2. sso.gerege.mn руу redirect хийгдэнэ
  3. e-ID Mongolia смарт картаар нэвтэрнэ
  4. Таны callback URL руу authorization code-тэй буцна
  5. Сервер талаас code → access_token + id_token солилцоно
  6. 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-ууд:

Authorizationhttps://sso.gerege.mn/oauth/authorize
Tokenhttps://sso.gerege.mn/oauth/token
UserInfohttps://sso.gerege.mn/oauth/userinfo
JWKShttps://sso.gerege.mn/.well-known/jwks.json
Introspecthttps://sso.gerege.mn/oauth/introspect
Revokehttps://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_typecode (заавал)
client_idDashboard-аас авсан client_id
redirect_uriБүртгүүлсэн redirect URI
scopeopenid profile (нэмэлт: pos, social, payment)
stateCSRF хамгаалалт — random string
nonceReplay 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
posPOS Plugin APItenant_id, tenant_role, plan
socialSocial Commerce APItenant_id, tenant_role, plan
paymentPayment APItenant_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 хуудаснаас хийнэ.