Skip to main content
Keycloak entegrasyonunda hataların çoğu URL/issuer/audience uyuşmazlığından kaynaklanır. Bu sayfa en sık görülenleri ve teşhis yollarını toplar.
İlk bakacağınız yer: API console. BuildingBlocks.Keycloak/DependencyInjection.cs açılışta her realm için Authority, PublicIssuer ve metadata erişim durumunu (REACHABLE / UNREACHABLE) yazar. Ayrıca her başarısız doğrulama X-Auth-Fail-{Scheme} response header’ına yazılır.
Console’da şuna benzer satır:
[Keycloak JWT] Personel metadata UNREACHABLE ✗ (http://diyanet-keycloak:8080/realms/.../.well-known/openid-configuration) → HttpRequestException: ...
API, BaseUrl’e ulaşamıyor demektir. JWKS alınamazsa tüm token doğrulama IDX10500 ile patlar.Çözüm:
  • Docker dev’de API container’ı Keycloak’a iç ağ hostname’i ile ulaşmalı (BaseUrl = http://diyanet-keycloak:8080), localhost değil — container içinde localhost API’nin kendisidir.
  • Aynı anda tarayıcının gördüğü URL PublicBaseUrl = http://localhost:8080 olmalı.
  • Test: docker exec diyanet-api curl -s http://diyanet-keycloak:8080/realms/diyanet-yonetim-dev-realm/.well-known/openid-configuration
Token reddediliyor; X-Auth-Fail-... header’ında issuer hatası. Sebep: token’ın iss’i (PublicBaseUrl) ile API’nin beklediği issuer (BaseUrl) farklı.Sistem her ikisini de kabul edecek şekilde tasarlandı:
var validIssuers = scheme.Issuer == scheme.PublicIssuer
    ? new[] { scheme.Issuer }
    : new[] { scheme.Issuer, scheme.PublicIssuer };
Çözüm: PublicBaseUrl’ü token’ın gerçek iss’iyle birebir aynı yapın. iss’i jwt.io ile okuyun; appsettings’teki PublicBaseUrl + /realms/{Realm} bununla eşleşmeli. Sondaki / farkı bile mismatch yaratır.
SecurityTokenInvalidAudienceException. Token’ın aud’u kabul edilen değerlerle eşleşmiyor.Kabul edilenler: client ID ve Keycloak’ın account audience’ı:
ValidAudiences = [scheme.ClientId, "account"];
Çözüm:
  • appsettingsKeycloak:*:ClientId ile token’daki aud aynı olmalı (diyanet-website / diyanet-admin).
  • Geçici teşhis için ValidateAudience: false yapılabilir ama prod’da açık tutun.
Keycloak login sonrası Invalid parameter: redirect_uri veya PKCE hatası.Çözüm:
  • Client’ın Valid redirect URIs listesi SPA origin’ini içermeli: http://localhost:3000/* (website), http://localhost:3001/* (admin) ve Swagger için http://localhost:5005/swagger/oauth2-redirect.html.
  • Web origins SPA origin’ini içermeli (CORS).
  • Client public + PkceRequired: true + method S256 olmalı; SPA keycloak-js ile PKCE gönderiyor olmalı.
Personel token’ı bilinçli olarak 5 dakikadır (AccessTokenLifespanSeconds: 300). Süre dolunca 401 ve Token-Expired: true header’ı gelir.Çözüm: Bu beklenen davranıştır. SPA refresh token rotation ile (lifespan 1800 sn) sessizce yeniler. 5 dakikada bir login’e düşüyorsanız refresh akışınızı kontrol edin; refresh token süresi de dolmuşsa yeniden login gerekir. Saat kayması için 30 sn ClockSkew toleransı vardır.
Authenticated görünüyorsunuz ama her şey 403.Olası sebep: MapInboundClaims açık kalmış → sub claim’i yeniden adlandırılmış → UserContextClaimsTransformation sub’u bulamaz → account_status="Unknown"ActiveAccountRequirement fail.Çözüm: ConfigureScheme’te options.MapInboundClaims = false olduğundan emin olun. Ayrıca kullanıcının DB’deki durumu Active olmalı; yeni kayıt (Pending) ise endpoint [AllowPendingAccount] taşımıyorsa 403 normaldir.
Provisioning [Provisioning] öneki ile loglar:
[Provisioning] Keycloak hazır bekleniyor (max 120s) → http://localhost:8080/realms/master/.well-known/openid-configuration
[Provisioning] ✅ Keycloak hazır.
[Provisioning] Başlatılıyor — mod: RunOnce
[Provisioning] ✅ Tamamlandı.
Keycloak'a ulaşılamıyor tekrarlıyorsa KeycloakProvisioning:Admin:BaseUrl yanlış ya da Keycloak henüz ayağa kalkmadı (120 sn’ye kadar bekler). Hata olsa bile uygulama yine başlar; o yüzden realm yokmuş gibi davranan 401’lerde önce bu logları kontrol edin.
docker logs diyanet-api -f | Select-String "Provisioning|Keycloak JWT"
Müşteri ortamı kurumsal TLS sertifikalı kapalı bir intranet olabilir (Let’s Encrypt çalışmaz).Notlar:
  • KEYCLOAK_BASE_URL / KEYCLOAK_EXTERNAL_URL iç DNS adını işaret etmeli.
  • API, kurumsal kök sertifikaya güvenmeli — gerekirse scripts/export-ca-cert.ps1 ile CA sertifikası container trust store’una eklenir.
  • RequireHttpsMetadata: true tutulur; metadata HTTPS üzerinden alınır.
  • Provisioning kapalı, realm bir kez elle/tek-sefer kurulur.

Hızlı kontrol komutları

# OIDC discovery (issuer / jwks_uri görün)
curl -s http://localhost:8080/realms/diyanet-yonetim-dev-realm/.well-known/openid-configuration | jq '{issuer, jwks_uri}'

# API container'dan Keycloak'a erişim (BaseUrl testi)
docker exec diyanet-api curl -s -o /dev/null -w "%{http_code}\n" \
  http://diyanet-keycloak:8080/realms/diyanet-vatandas-dev-realm/.well-known/openid-configuration

# Başarısız auth teşhis header'ını gör
curl -v http://localhost:5005/api/admin/users -H "Authorization: Bearer <token>" 2>&1 | grep -i "x-auth-fail\|token-expired"

İlgili

Ortamlar

BaseUrl vs PublicBaseUrl ayrımı.

Authentication

Issuer / audience / MapInboundClaims.

Provisioning

Hosted service ve loglar.

Client Yapılandırması

Redirect URI / PKCE ayarları.