{
  "title": "Login-Consent App",
  "slug": "team/backend/services/login-consent-app",
  "url": "/docs/team/backend/services/login-consent-app",
  "frontmatter": {
    "layout": "doc",
    "title": "Login-Consent App",
    "description": "سرویس واسط مستقل بین Ory Hydra و Ory Kratos (Login & Consent flow + Token Hook)",
    "version": "1.0.0",
    "status": "APPROVED",
    "author": "Backend Team",
    "owner": "Backend Team",
    "created_at": "2026-07-15",
    "updated_at": "2026-07-15",
    "tags": "",
    "reviewers": ""
  },
  "sections": [
    {
      "level": 1,
      "heading": "Login-Consent App",
      "content": "**Login-Consent App — واسط مستقل Login & Consent (Ory Hydra ↔ Ory Kratos)**\n\n> این سرویس **تنها کد اختصاصی** در حوزه توکن است. مستقل از `token-service` (Hydra) و `auth-service` (Kratos) عمل می‌کند.\n> مرجع تصمیمات: [`ADR-Backend-006`](../../backend/ADR/ADR-Backend-006) — مشخصات فنی: [`blueprint.md` (token-service) §۲، §۳.۲، §۴](../services/token-service.md)\n\n---"
    },
    {
      "level": 2,
      "heading": "۱. هدف سرویس",
      "content": "**Service Objective**\n\n`login-consent-app` سرویس اختصاصی Go است که طبق الگوی رسمی Ory، بین **Ory Hydra** (صدور توکن) و **Ory Kratos** (هویت/نشست) قرار می‌گیرد و جریان‌های **Login & Consent** و **Token Hook** را پیاده‌سازی می‌کند. این سرویس:\n\n- نشست Kratos را تأیید می‌کند و subject را به Hydra معرفی می‌کند.\n- consent را برای first-party clients مدیریت می‌کند.\n- claims توکن را پیش از صدور غنی‌سازی می‌کند (نقش از iam-service).\n\n**مسیر کد:** `nons-api/services/login-consent-app/`\n\n---"
    },
    {
      "level": 2,
      "heading": "۲. چرا سرویس مستقل؟",
      "content": "**Why a Standalone Service**\n\n- auth-service مسئول هویت است؛ login-consent-app مسئول **واسطگری Hydra↔Kratos** — ترکیب آن‌ها coupling ایجاد می‌کند.\n- اگر IdP (Kratos) در آینده عوض شود، فقط login-consent-app تغییر می‌کند، نه auth-service و نه token-service.\n- Kratos Admin API و Hydra Admin API از این واسط ایزوله می‌شوند.\n- طبق [`ADR-Backend-006`](../../backend/ADR/ADR-Backend-006) (D1)، login-consent-app یک سرویس مستقل مانند auth-service و iam-service است — نه بخشی از سرویس دیگر.\n\n---"
    },
    {
      "level": 2,
      "heading": "۳. مسئولیت‌ها",
      "content": "**Responsibilities**\n\n- پیاده‌سازی endpoint `/login` — دریافت `login_challenge`، استعلام نشست Kratos، accept کردن Login Request در Hydra.\n- پیاده‌سازی endpoint `/consent` — accept کردن Consent Request برای first-party (با `skip_consent`).\n- پیاده‌سازی endpoint `/token-hook` — دریافت session context از Hydra و بازگرداندن JSON حاوی claims غنی‌شده.\n- انتشار رویدادهای `nons.token.issued` / `nons.token.revoked` به NATS (از طرف حوزه توکن).\n- اجرای ترتیب صحیحLogout (ابتدا Hydra revoke، سپس Kratos logout).\n\n---"
    },
    {
      "level": 2,
      "heading": "۴. خارج از مسئولیت‌ها",
      "content": "**Non-Responsibilities**\n\n- **صدور توکن:** بر عهده Hydra (token-service) است — login-consent-app صرفاً واسط است.\n- **مدیریت هویت و نشست:** بر عهده Kratos (auth-service) است.\n- **مدیریت نقش‌ها/مجوزها:** بر عهده iam-service است؛ login-consent-app فقط claims را از آن دریافت و به توکن تزریق می‌کند.\n\n---"
    },
    {
      "level": 2,
      "heading": "۵. جریان‌های اصلی",
      "content": "**Core Flows**"
    },
    {
      "level": 3,
      "heading": "۵.۱ Login Flow",
      "content": "```\n[مرورگر] → GET /oauth2/auth → [Hydra]\n[Hydra] → 302 → [login-consent-app]/login?login_challenge=<X>\n[login-consent-app] → GET /admin/oauth2/auth/requests/login?login_challenge=<X> → [Hydra Admin]\n[login-consent-app] → GET /sessions/whoami (Cookie: ory_kratos_session) → [Kratos Public]\n  ├─ نشست معتبر:\n  │   [login-consent-app] → PUT /admin/oauth2/auth/requests/login/accept\n  │                          {subject: \"<kratos-identity-id>\", remember: true}\n  │   [Hydra] → 302 → [login-consent-app]/consent?consent_challenge=<Y>\n  └─ نشست نامعتبر:\n      [login-consent-app] → 302 → [Kratos Login]\n```\n\n**نکات حیاتی:**\n- **کوکی `ory_kratos_session` باید forward شود** (درخواست از کاربر به whoami Kratos). بدون آن whoami همیشه ۴۰۱ است.\n- **`subject` = Kratos Identity ID** (identity.id)، نه email/username.\n- **هر login_challenge یک‌بار مصرف.** خطا → restart flow."
    },
    {
      "level": 3,
      "heading": "۵.۲ Consent Flow",
      "content": "- برای first-party clients، `skip_consent: true` در Hydra client تنظیم شده → login-consent-app مستقیماً `PUT .../consent/accept` را فراخوانی می‌کند.\n- برای third-party (آینده)، login-consent-app صفحه consent را رندر و پس از تأیید کاربر accept می‌کند."
    },
    {
      "level": 3,
      "heading": "۵.۳ Token Hook (Claims Enrichment)",
      "content": "پیش از صدور توکن، Hydra POST به `http://login-consent-app:PORT/token-hook` می‌زند. login-consent-app:\n\n1. session object را از Hydra دریافت می‌کند.\n2. نقش کاربر را از iam-service استعلام می‌کند.\n3. JSON حاوی claims غنی‌شده (نقش، سطح دسترسی) برمی‌گرداند تا در توکن inject شود.\n\n```yaml\noauth2:\n  token_hook:\n    url: http://login-consent-app:PORT/token-hook\n```\n\n---"
    },
    {
      "level": 2,
      "heading": "۶. امنیت و دسترسی",
      "content": "**Security & Access**\n\n- login-consent-app **تنها Pod مجاز** به دسترسی به Hydra Admin API (port 4445) طبق Kubernetes NetworkPolicy (`deploy/helm/hydra/templates/networkpolicy.yaml`).\n- برای سخت‌گیری بیشتر: mTLS بین login-consent-app و Hydra Admin (Roadmap).\n- کوکی `ory_kratos_session` نباید در پاسخ به مرورگر افشا شود؛ فقط درون فراخوانی‌های سرور-to-سرور به Kratos ارسال می‌شود.\n\n---"
    },
    {
      "level": 2,
      "heading": "۷. رویدادها",
      "content": "**Events**\n\n| رویداد | زمان صدور | توضیح |\n|---|---|---|\n| `nons.token.issued` | پس از صدور موفق توکن | `client_id`, `sub`, `scope`, `grantedAt` |\n| `nons.token.revoked` | پس از ابطال توکن / logout | `sub`, `client_id`, `revokedAt` |\n\nتعریف رسمی: `nons-api/catalog/events/token/events.yaml`.\n\n---"
    },
    {
      "level": 2,
      "heading": "۸. پیوند با سایر سرویس‌ها",
      "content": "**Relations**\n\n- **token-service (Hydra):** login-consent-app واسط آن است؛ URLهای `login/consent/logout` به این سرویس اشاره می‌کند.\n- **auth-service (Kratos):** نشست را از طریق `GET /sessions/whoami` استعلام می‌کند.\n- **iam-service:** نقش کاربر را برای Token Hook استعلام می‌کند.\n\n> 📖 مطالعه کامل معماری حوزه توکن: [Token Service](../services/token-service.md) و [ADR-Backend-006](../../backend/ADR/ADR-Backend-006)"
    }
  ]
}