1. Token edinimi — SPA → Keycloak (Authorization Code + PKCE)
Her iki SPA da (Website, Admin) public client’tır vekeycloak-js ile Authorization Code +
PKCE (S256) akışını kullanır. Client’lar PublicClient: true, StandardFlowEnabled: true,
PkceRequired: true olarak provision edilir; DirectAccessGrantsEnabled: false.
Backend-driven bir varyant da mevcuttur (KeycloakOAuthClient,
src/DiyanetCleanArchitecture.Infrastructure.Services.OAuth/Keycloak/KeycloakOAuthClient.cs):
PKCE code_verifier’ı Redis’te keycloak_pkce_{state} anahtarıyla 10 dakika saklar, callback’te
tek kullanımlık olarak okuyup siler.
2. API tarafında JWT doğrulama
Her schemeBuildingBlocks.Keycloak/DependencyInjection.cs → ConfigureScheme ile yapılandırılır.
Önemli noktalar:
Issuer: internal vs public
Docker dev’de API Keycloak’a iç ağ üzerinden (http://diyanet-keycloak:8080) ulaşır ama
tarayıcı http://localhost:8080’i görür. Token’ın iss claim’i public URL’i taşır. Bu yüzden
hem internal hem public issuer kabul edilir:
KeycloakSchemeOptions (BuildingBlocks.Keycloak/KeycloakOptions.cs) URL’leri BaseUrl
(internal) ve PublicBaseUrl (browser) üzerinden hesaplar:
account audience’ı kabul edilir.
3. Token kaynak önceliği — OnMessageReceived
API token’ı üç kaynaktan, şu öncelikle okur:
kc_vatandas_token, personel kc_personel_token
(appsettings.Development.json → Keycloak:*:CookieName).
Query string
access_token yalnızca /hubs ve /files yollarında kabul edilir — çünkü
EventSource (SSE) ve dosya <img>/indirme istekleri özel header taşıyamaz. Diğer yollarda
query token yok sayılır.Hata teşhisi
OnAuthenticationFailed her başarısız doğrulamada response header’a teşhis bilgisi yazar
(curl -v / DevTools’tan görünür):
OnChallenge ise default 401’i bastırıp RFC 7807 application/problem+json döner; scheme,
detail ve traceId alanlarıyla hangi scheme’in neden reddettiği görünür.
4. Vatandaş portali — OTP / TOTP (özet)
Vatandaş portalinde Keycloak SSO dışında telefon/e-posta OTP ve TOTP ile challenge token tabanlı bir akış da vardır. Kullanıcı oluşturma →OtpCode.Generate() → domain event ile
SMS/e-posta gönderimi → doğrulama → oturum başlatma adımlarını izler. Challenge token kısa
ömürlüdür (Jwt:OTPChallenge, Expires: 1 dk).
5. Refresh token rotation
Refresh davranışı iki yerde tanımlıdır:- Keycloak client (provisioning):
RefreshTokenRotationEnabled: true. Vatandaş client’ıRefreshTokenLifespanSeconds: 3600, personel client’ı1800. - Uygulamanın kendi backoffice refresh token’ı (
appsettings→Jwt:RefreshToken:Backoffice):RotationEnabled: true,ReuseDetectionEnabled: true,Expires: 43200(30 gün),TrustedDeviceExpires: 129600(90 gün).
RefreshTokenInfo value object’i token’ı
SHA256 hash’ler — plaintext saklanmaz.
6. Token version invalidasyonu
TokenVersionMiddleware (SeedWork/Middlewares/TokenVersionMiddleware.cs) bir feature flag’e
bağlıdır (appsettings → Security:TokenVersionValidation, dev’de true):
app.UseAuthentication() ile app.UseAuthorization() arasında çalışır
(app.UseTokenVersionValidation()). Rol/izin değişiminde User.TokenVersion artırılır; eski
token’lar bir sonraki istekte 401 alır. Bu, “izni geri al → anında etkili olsun” senaryosunu
token süresini beklemeden çözer.
İlgili
Authorization
Permission policy ve handler’lar.
OTP Flow
Vatandaş OTP/TOTP challenge akışı.
Client Yapılandırması
PKCE, redirect URI, web origins.
Sorun Giderme
Issuer mismatch, invalid audience, JWKS unreachable.