> ## Documentation Index
> Fetch the complete documentation index at: https://docs.diyanet.pro/llms.txt
> Use this file to discover all available pages before exploring further.

# Kimlik ve Yetki — Genel Bakış

> Çift-realm Keycloak, iki JwtBearer şeması, claim modeli ve katmanlı authorization

Bu sistemde **authentication** (kimlik doğrulama) Keycloak'a, **authorization** (yetkilendirme)
uygulamaya aittir. Keycloak sadece "bu token gerçek ve geçerli" der; "bu kullanıcı bu işlemi
yapabilir mi" sorusunu uygulama yanıtlar.

| Sorumluluk                                             | Yer                                                        |
| ------------------------------------------------------ | ---------------------------------------------------------- |
| Kullanıcı kimliği, parola, MFA, SSO, OAuth federasyonu | **Keycloak**                                               |
| Token üretimi (access, refresh, id\_token)             | **Keycloak**                                               |
| Token imza doğrulama (JWKS / RS256)                    | **API — JwtBearer middleware**                             |
| Rol → permission haritası                              | **Uygulama (DB, `role_permission` seed)**                  |
| Endpoint başına permission kontrolü                    | **Uygulama (`DynamicPermissionPolicyProvider`)**           |
| Hesap durumu (Active/Pending/Banned) gate'i            | **Uygulama (`ActiveAccountAuthorizationHandler`)**         |
| Multi-tenant ayrımı                                    | **Uygulama (JWT claim + `AuthorizationPipelineBehavior`)** |

## İki ayrı kimlik dünyası

API iki ayrı Keycloak realm'ından token kabul eder. Her realm için ayrı bir
JWT Bearer scheme kaydedilir (`src/BuildingBlocks/BuildingBlocks.Keycloak/KeycloakSchemeNames.cs`):

| Taraf                  | Realm (dev)                  | Client            | Scheme adı       | Cookie              |
| ---------------------- | ---------------------------- | ----------------- | ---------------- | ------------------- |
| Vatandaş (Website SPA) | `diyanet-vatandas-dev-realm` | `diyanet-website` | `VatandasScheme` | `kc_vatandas_token` |
| Personel (Admin SPA)   | `diyanet-yonetim-dev-realm`  | `diyanet-admin`   | `PersonelScheme` | `kc_personel_token` |

```csharp theme={null}
// BuildingBlocks.Keycloak/KeycloakSchemeNames.cs
public const string Vatandas = "VatandasScheme";
public const string Personel = "PersonelScheme";
public const string Any      = $"{Vatandas},{Personel}";
```

İki dünya birbirinden bağımsızdır: kullanıcı havuzları ayrı, scheme'ler ayrı,
cookie isimleri ayrı (yan yana login durabilir), claim modelleri farklı
(vatandaşta `citizen_id`, personelde `user_id`).

```mermaid theme={null}
flowchart LR
    subgraph Vatandas["Vatandaş tarafı"]
        V[Website SPA] --> RV["diyanet-vatandas-dev-realm<br/>client: diyanet-website"]
        RV --> SV["VatandasScheme<br/>cookie: kc_vatandas_token"]
    end
    subgraph Personel["Personel tarafı"]
        P[Admin SPA] --> RP["diyanet-yonetim-dev-realm<br/>client: diyanet-admin"]
        RP --> SP["PersonelScheme<br/>cookie: kc_personel_token"]
    end
```

Her iki scheme `BuildingBlocks.Keycloak/DependencyInjection.cs` içinde `AddJwtBearer` ile
kaydedilir; default scheme `PersonelScheme`'tir:

```csharp theme={null}
services.AddAuthentication(KeycloakSchemeNames.Personel)
    .AddJwtBearer(KeycloakSchemeNames.Vatandas, options => ConfigureScheme(options, opts.Vatandas))
    .AddJwtBearer(KeycloakSchemeNames.Personel, options => ConfigureScheme(options, opts.Personel));
```

## Token içindeki claim modeli

Doğrulanan token bir dizi claim taşır. Bazıları doğrudan Keycloak Protocol Mapper'dan,
bazıları API tarafındaki `ClaimsTransformation` zincirinden gelir
(`DiyanetCleanArchitectureClaimTypes`):

| Claim                           | Kaynak                                     | Kullanım                                           |
| ------------------------------- | ------------------------------------------ | -------------------------------------------------- |
| `sub`                           | Keycloak                                   | Keycloak kullanıcı kimliği; transformation girdisi |
| `realm_access.roles`            | Keycloak                                   | Rol claim'lerine dönüştürülür                      |
| `permissions[]` (multivalued)   | Keycloak Protocol Mapper + DB              | `PermissionAuthorizationHandler`                   |
| `organization_id` / `tenant_id` | Keycloak Protocol Mapper                   | Multi-tenant izolasyonu                            |
| `user_id`                       | API (`UserContextClaimsTransformation`)    | Local DB `User.Id`                                 |
| `citizen_id`                    | API (`CitizenContextClaimsTransformation`) | Vatandaş aggregate kimliği                         |
| `account_status`                | API (her istekte güncel)                   | `ActiveAccountAuthorizationHandler`                |
| `token_version`                 | Keycloak / local                           | `TokenVersionMiddleware` invalidasyonu             |

<Note>
  `organization_id` ve `tenant_id` eşdeğer kabul edilir. `HttpContextCurrentTenant` önce
  `tenant_id`, yoksa `organization_id` claim'ine düşer. Dev provisioning yapılandırması
  `organization_id` Protocol Mapper'ı kurar.
</Note>

## İstek başına akış

```mermaid theme={null}
sequenceDiagram
    autonumber
    participant SPA as SPA (Admin/Website)
    participant API as .NET API
    participant DB as PostgreSQL
    SPA->>API: GET /api/admin/users<br/>Cookie/Bearer: <jwt>
    API->>API: JwtBearer — JWKS ile imza + issuer + audience doğrula
    API->>API: ClaimsTransformation zinciri<br/>(roller + permissions + user_id + account_status)
    API->>API: TokenVersionMiddleware (opsiyonel)
    API->>API: Authorization — DynamicPermissionPolicyProvider<br/>+ ActiveAccountRequirement
    API->>DB: SELECT (tenant filtreli)
    API-->>SPA: 200 / 401 / 403
```

Middleware sırası `Program.cs` içinde nettir:

```csharp theme={null}
app.UseAuthentication();
app.UseTokenVersionValidation();  // Feature flag: Security:TokenVersionValidation
app.UseAuthorization();
```

## Dört koruma katmanı

1. **Authentication** — `JwtBearer` token imzasını (RS256, JWKS), issuer'ı ve audience'ı doğrular.
2. **Dynamic permission policy** — `[RequirePermission("users:read")]` → `Permission:users:read`
   policy adı → `PermissionAuthorizationHandler` `permissions` claim'ini kontrol eder.
3. **Active-account guard** — tüm policy'lere implicit `ActiveAccountRequirement` eklenir;
   `Pending/Banned/Suspended` hesaplar geçemez (`[AllowPendingAccount]` ile bypass).
4. **Token version** — `TokenVersionMiddleware` JWT'deki `token_version` ile DB'deki
   `User.TokenVersion`'ı karşılaştırır; eşleşmezse 401 (RBAC değişiminde anında invalidasyon).

```mermaid theme={null}
flowchart TD
    REQ["HTTP Request + JWT"] --> AUTH["JwtBearer Authentication"]
    AUTH --> CT["ClaimsTransformation<br/>roller + permissions + account_status"]
    CT --> TV["TokenVersionMiddleware"]
    TV --> POL["DynamicPermissionPolicyProvider"]
    POL --> PH["PermissionAuthorizationHandler"]
    POL --> AH["ActiveAccountAuthorizationHandler"]
    PH --> R["200 / 403"]
    AH --> R
```

## Bu bölümde

<CardGroup cols={2}>
  <Card title="Authentication" href="/security/authentication">
    Token edinimi, dual JwtBearer, cookie + header + query, refresh rotation, token version.
  </Card>

  <Card title="Authorization" href="/security/authorization">
    Dinamik permission policy, handler'lar, roller, RolePermission seed.
  </Card>

  <Card title="Multi-Tenancy" href="/security/multi-tenancy">
    `organization_id`/`tenant_id` claim, soft-tenant, pipeline izolasyonu.
  </Card>

  <Card title="Keycloak Genel Bakış" href="/keycloak/overview">
    Çift realm, client'lar, provisioning ve ortam yönetimi.
  </Card>
</CardGroup>
