Authorization Server Seçimi: OpenIddict, Duende IdentityServer, Keycloak ve Microsoft Entra ID Karşılaştırması
Doğru authorization server ekibinin neyi işletebileceğine bağlıdır: OpenIddict ve Duende framework, Keycloak ürün, Entra ID managed servis. Üçünü lab'da çalıştırıp discovery dokümanlarından bir yetenek matrisi çıkarıyor, bu matrisin neden dikkatli okunması gerektiğini gösteriyor; lisansları, işletme yükünü, SAML köprüsünü ve kendi authorization server'ını yazmamanın nedenlerini Kasım 2026 bilgisiyle karşılaştırıyoruz.
Sürüm notu: Bu yazıdaki kodlar .NET 10, Duende.IdentityServer 8.0.10, OpenIddict 7.8.0 ve Keycloak 26.8.2 ile derlenip denenmiştir; lisans ve fiyat bilgileri Kasım 2026'da ürünlerin kendi sayfalarından kontrol edilmiştir.
Önce Tahmin Et
Bookstore büyüyor: web, mobil, iki partner uygulaması ve kurumsal müşteriler için bir yönetim paneli. Hepsi tek bir authorization server'a bağlanacak. Ekipte biri "OpenIddict ücretsiz, onu kullanalım" diyor, biri "Entra ID'de her şey hazır", biri de "Keycloak'u Docker'da zaten çalıştırıyoruz". Hangisi doğru? Bir de şu: bu seçimi yaparken bir ürünün discovery dokümanında "DPoP yok" görürsen, o ürün DPoP desteklemiyor mu demektir?
Bu serinin 10 ile 14 arasındaki yazılarında authorization server rolünü Keycloak oynadı. Bu yazıda o rolü üstlenebilecek dört adayı karşılaştırıyoruz: OpenIddict, Duende IdentityServer, Keycloak ve Microsoft Entra ID. Karşılaştırma pazarlama sayfalarından değil; üçünü lab'da ayağa kaldırıp discovery dokümanlarını aynı araçla okuyarak, dördüncüsünün herkese açık discovery dokümanını da aynı araca vererek. Ürün özellikleri ve lisanslar hızlı değişiyor; buradaki her bilgiyi kendi karar anında yeniden doğrula.
Neyi Seçiyorsun?
"Authorization server" tek bir parça gibi duruyor ama birkaç sorumluluğu var: OAuth/OIDC (OpenID Connect) protokolünü konuşmak ve token basmak; kullanıcıları ve parolaları saklamak; giriş, kayıt, parola sıfırlama, MFA (Multi-Factor Authentication) ve passkey ekranlarını sunmak; Google, kurumsal Active Directory ya da bir SAML (Security Assertion Markup Language) IdP'si (Identity Provider) ile federation; client'ları, scope'ları ve key'leri yönetmek; denetim kaydı tutmak. Adaylar bu listenin farklı kısımlarını üstleniyor. En önemli ayrım şu: bir framework mü alıyorsun, bir ürün mü, bir servis mi?
Dört Aday
OpenIddict bir framework. ASP.NET Core uygulamanın içine protokol katmanını ekliyor; kullanıcı deposu, giriş ekranları, onay ekranı ve yönetim arayüzü senin. Çoğu zaman ASP.NET Core Identity ile birlikte kullanılıyor (bu serinin 03 ve 04. yazıları). Lisansı Apache-2.0; ticari kullanımda ücret yok. Esnekliği yüksek, sorumluluğu da: protokolün kenar durumlarını o yönetiyor ama geri kalan her şeyi sen yazıyorsun.
Duende IdentityServer da bir framework, aynı modelle çalışıyor: protokol Duende'nin, kullanıcı ve ekranlar senin. Fark lisansta: ticari bir ürün. Ürün sayfası geliştirme, test ve deneme için lisans gerekmediğini açıkça yazıyor; production'da lisans şart. SAML, multi-tenancy, otomatik key yönetimi gibi özellikler ayrı ücretli eklentiler olarak satılıyor. Lisanssız çalıştırınca log'a yazdığı şey:
fail: Duende.Private.Licencing.V2.LicenseValidator[263521618]
You do not have a valid license key for the Duende software. This is allowed for development and testing scenarios. If you are running in production you are required to have a licensed version. Please start a conversation with us: https://duend...
warn: Duende.Private.Licencing.V2.LicenseValidator[1549918610]
Automatic Key Management is being used but no Duende license is configured. Please start a conversation with us: https://duende.link/l/contact
Keycloak bir ürün. Kullanıcı deposu, giriş ve kayıt ekranları, MFA, passkey, federation, yönetim konsolu, SAML ve multi-tenant senaryolar için organization desteği hazır geliyor. Lisansı Apache-2.0 ve CNCF (Cloud Native Computing Foundation) altında bir proje. Bedeli işletmek: Java tabanlı bir sunucu, bir veritabanı, cluster, sürüm yükseltmeleri. Keycloak'ın LTS (Long-Term Support) sürümü yok; güvenlik düzeltmeleri en yeni minor sürüme geliyor, yani düzenli yükseltme bir seçenek değil, gereklilik.
Microsoft Entra ID bir managed servis: çalışanlar için Entra ID (workforce), müşteriler için Entra External ID. Altyapıyı, ölçeklemeyi, key rotation'ı Microsoft yönetiyor. External ID için Microsoft Learn'deki fiyatlandırma sayfası ilk 50.000 aylık aktif kullanıcının ücretsiz olduğunu söylüyor. Eski Azure AD (Active Directory) B2C (business-to-consumer) ise 1 Mayıs 2025'ten beri yeni müşterilere satılmıyor; mevcut müşteriler için desteğin en az Mayıs 2030'a kadar süreceği yazıyor. Yani bugün başlayan bir B2C projesi için seçenek External ID.
Discovery'den Yetenek Matrisi
Duende ve OpenIddict'i lab'da en küçük hâlleriyle çalıştırdım. Duende tarafı:
// Lisanssız geliştirme/deneme modu: Duende başlangıçta uyarı log'u yazar
builder.Services.AddIdentityServer()
.AddInMemoryIdentityResources([new IdentityResources.OpenId(), new IdentityResources.Profile()])
.AddInMemoryApiScopes([new ApiScope("books.read")])
.AddInMemoryClients(
[
new Client
{
ClientId = "bookstore-inventory-worker",
ClientSecrets = [new Secret(builder.Configuration["WorkerSecret"].Sha256())],
AllowedGrantTypes = GrantTypes.ClientCredentials,
AllowedScopes = ["books.read"]
}
]);
WebApplication app = builder.Build();
app.UseIdentityServer();
OpenIddict tarafı; endpoint'leri ve izin verilen akışları açıkça sen seçiyorsun, kullanmadığın hiçbir şey açık gelmiyor:
builder.Services.AddOpenIddict()
.AddCore(options => options.UseEntityFrameworkCore().UseDbContext<AuthDbContext>())
.AddServer(options =>
{
options.SetAuthorizationEndpointUris("connect/authorize")
.SetPushedAuthorizationEndpointUris("connect/par")
.SetTokenEndpointUris("connect/token")
.SetIntrospectionEndpointUris("connect/introspect")
.SetRevocationEndpointUris("connect/revoke")
.SetEndSessionEndpointUris("connect/logout")
.SetDeviceAuthorizationEndpointUris("connect/device")
.SetEndUserVerificationEndpointUris("connect/verify");
options.AllowAuthorizationCodeFlow().RequireProofKeyForCodeExchange()
.AllowClientCredentialsFlow()
.AllowDeviceAuthorizationFlow()
.AllowRefreshTokenFlow();
// Yalnız lab: kalıcı olmayan key'ler ve HTTP
options.AddEphemeralEncryptionKey().AddEphemeralSigningKey();
options.UseAspNetCore().DisableTransportSecurityRequirement();
});
Sonra discovery dokümanlarını okuyan küçük bir konsol uygulaması yazdım. Entra ID için login.microsoftonline.com/common/v2.0/.well-known/openid-configuration adresindeki herkese açık dokümanı bir kez indirip dosyadan okuttum:
// Discovery dokümanlarından bir yetenek matrisi çıkarır: sunucu bir özelliği ilan ediyor mu?
(string Label, Func<JsonElement, string> Read)[] rows =
[
("PKCE S256", d => Has(d, "code_challenge_methods_supported", "S256")),
("PAR (RFC 9126)", d => Present(d, "pushed_authorization_request_endpoint")),
("DPoP (RFC 9449)", d => Present(d, "dpop_signing_alg_values_supported")),
("mTLS bound tokens", d => Bool(d, "tls_client_certificate_bound_access_tokens")),
("private_key_jwt", d => Has(d, "token_endpoint_auth_methods_supported", "private_key_jwt")),
("iss in auth response", d => Bool(d, "authorization_response_iss_parameter_supported")),
("device flow (RFC 8628)", d => Present(d, "device_authorization_endpoint")),
("introspection", d => Present(d, "introspection_endpoint")),
("revocation", d => Present(d, "revocation_endpoint")),
("end session", d => Present(d, "end_session_endpoint")),
("back-channel logout", d => Bool(d, "backchannel_logout_supported")),
("CIBA", d => Present(d, "backchannel_authentication_endpoint")),
("implicit advertised", d => Has(d, "grant_types_supported", "implicit")),
("password advertised", d => Has(d, "grant_types_supported", "password"))
];
static string Present(JsonElement d, string key) => d.TryGetProperty(key, out _) ? "yes" : "-";
static string Bool(JsonElement d, string key) =>
d.TryGetProperty(key, out JsonElement v) && v.ValueKind == JsonValueKind.True ? "yes" : "-";
static string Has(JsonElement d, string key, string value) =>
d.TryGetProperty(key, out JsonElement v) && v.EnumerateArray().Any(x => x.GetString() == value) ? "yes" : "-";
$ dotnet run --project ascheck
Keycloak 26.8.2 Duende IS 8.0.10 OpenIddict 7.8.0 Entra ID (common)
PKCE S256 yes yes yes -
PAR (RFC 9126) yes yes yes -
DPoP (RFC 9449) yes yes - -
mTLS bound tokens yes - - yes
private_key_jwt yes - yes yes
iss in auth response yes yes yes -
device flow (RFC 8628) yes yes yes yes
introspection yes yes yes -
revocation yes yes yes -
end session yes yes yes yes
back-channel logout yes yes - -
CIBA yes yes - -
implicit advertised yes yes - -
password advertised yes - - -
Bu tablo bir şey söylüyor ama dikkatli okunmalı. Discovery dokümanı sunucunun o anki konfigürasyonunda ilan ettiğini gösterir; ilan edilmeyen her şey desteklenmiyor demek değil. Entra ID PKCE'yi (Proof Key for Code Exchange) destekliyor ama code_challenge_methods_supported'ı yayımlamıyor. Duende'de private_key_jwt var ama benim en küçük kurulumumda açık değil. OpenIddict'te ben açmadığım için implicit ve password yok; Keycloak ise sunucu düzeyinde ilan edip client düzeyinde kapatıyor (10. yazıda gördük). Tersine, ilan edilen bir özellik de senin client'ın için açık olmayabilir. Matrisi bir başlangıç noktası olarak kullan, sonra eksik görünen her satırı ürünün kendi dokümanından ve kendi lab'ında doğrula. Önce Tahmin Et'teki sorunun cevabı da bu: "DPoP yok" satırı yalnız "bu konfigürasyon DPoP ilan etmiyor" demek.
Yine de tablo bazı şeyleri net gösteriyor. 13. yazıda kullandığımız DPoP ve 12. yazıdaki back-channel logout, burada yalnız Keycloak ve Duende'de ilan edildi. Bu iki özellik sana lazımsa OpenIddict ve Entra için cevabı bulmadan karar verme.
Kendin Barındır mı, Managed mı?
Kendin barındırdığında authorization server senin en kritik servisin olur: o çökerse kimse giriş yapamaz. Yüksek erişilebilirlik (en az iki instance ve paylaşılan durum), veritabanı yedeği, imza key'lerinin güvenli saklanması ve rotation'ı, güvenlik açığı bültenlerini izleyip hızlı yükseltme, sızma testleri, denetim log'larının saklanması; hepsi senin işin. Keycloak'ta bu bir ürünü işletmek, OpenIddict ve Duende'de ise kendi yazdığın bir uygulamayı işletmek demek; ikincisinde giriş ekranının, parola sıfırlama akışının ve hesap kilitleme kurallarının güvenliği de senin kodun.
Managed serviste bunların çoğu sağlayıcının; karşılığında başka bedeller var. Aylık aktif kullanıcıya göre fiyatlandırma, kullanıcı sayısı büyüdükçe en büyük kalem olabiliyor. Özelleştirme sınırlı: giriş ekranının görünümünü, token'daki claim'leri, kayıt akışını sağlayıcının izin verdiği ölçüde değiştirebiliyorsun. Bağımlılık gerçek: kullanıcılarının parola hash'lerini başka bir sisteme taşıyabilir misin? Veri nerede saklanıyor, KVKK (Kişisel Verilerin Korunması Kanunu) açısından yurt dışına aktarım sayılıyor mu? Bu soruları satın almadan önce sor.
Ortada bir yol da var: authorization server'ı managed alıp kullanıcı verisini kendi sisteminde tutmak ya da tersine, Keycloak'u bir sağlayıcının managed hizmeti olarak almak. Seçim siyah beyaz değil; ama "ekibimizde bu servisi 7/24 işletecek kim var?" sorusunun cevabı genellikle kararı veriyor.
Federation, SSO ve SAML
Kurumsal müşteriler geldiğinde iki talep hemen ortaya çıkıyor: "çalışanlarımız kendi şirket hesaplarıyla girsin" (federation) ve "bir kez girsinler, tüm uygulamalarınızda oturum açık olsun" (SSO, Single Sign-On). SSO'yu 12. yazıda gördük; aynı Keycloak session'ı iki client'a parola sormadan code verdi. Federation'da authorization server başka bir IdP'ye güveniyor ve kullanıcıyı ona yönlendiriyor.
Modern IdP'lerin çoğu OIDC (OpenID Connect) konuşuyor, ama kurumsal dünyada SAML 2.0 hâlâ yaygın: eski bir AD FS (Active Directory Federation Services) kurulumu, bazı insan kaynakları ve muhasebe SaaS (Software as a Service) uygulamaları, kamu kurumlarının kimlik sistemleri. SAML XML (Extensible Markup Language) tabanlı, imzalı assertion'larla çalışıyor ve tarihsel olarak imza doğrulamasında ciddi açıklar çıkarmış bir format. Senin uygulamanın SAML konuşması gerekmez; authorization server SAML'ı alıp uygulamana OIDC olarak verebilir. Bu "protokol köprüsü" Keycloak'ta yerleşik, Entra ID'de var, Duende'de ücretli bir eklenti, OpenIddict'te yok.
Karar Matrisi
| Soru | OpenIddict | Duende IdentityServer | Keycloak | Entra ID / External ID |
|---|---|---|---|---|
| Ne alıyorsun | Framework | Framework | Ürün | Managed servis |
| Lisans | Apache-2.0 | Ticari; dev/test ücretsiz | Apache-2.0 | Kullanım bazlı; External ID'de 50.000 MAU (Monthly Active Users) ücretsiz |
| Kullanıcı ekranları | Sen yazarsın | Sen yazarsın | Hazır, tema ile | Hazır, sınırlı özelleştirme |
| İşletme yükü | Kendi uygulaman | Kendi uygulaman | Java sunucusu + veritabanı | Sağlayıcıda |
| SAML köprüsü | Yok | Ücretli eklenti | Yerleşik | Var |
| .NET ekibine yakınlık | Çok yüksek | Çok yüksek | Orta (Java, SPI (Service Provider Interface) ile genişletme) | Yüksek (SDK'lar) |
Kabaca: authorization server'ı uygulamanın bir parçası gibi .NET'te yazmak ve tüm ekranları kontrol etmek istiyorsan OpenIddict ya da Duende; aralarındaki seçim çoğu zaman lisans bütçesi ile hazır gelen gelişmiş özellikler arasında. Hazır ekranları ve SAML'ı olan, kendin işleteceğin bir ürün istiyorsan Keycloak. Altyapı işletmek istemiyorsan, kullanıcıların zaten Microsoft hesabıyla geliyorsa ya da kurumsal SSO önceliğinse Entra.
Listede olmayan seçenek de var: kendi authorization server'ını sıfırdan yazmak. Yapma. OAuth ve OIDC'nin güvenliği detaylarda: redirect URI (Uniform Resource Identifier) eşleşmesi, code'un tek kullanımlığı ve tekrar kullanımda token iptali (11. yazıda Keycloak'ın bunu nasıl yaptığını gördük), PKCE downgrade'i, mix-up, refresh token rotation, key rotation, logout türleri. Bu yazı serisinin her yazısı bu listeden bir maddeydi ve liste bitmedi. Framework'ler bu kenar durumlarla yıllarca test edilmiş kodu sana veriyor; OpenID Foundation'ın sertifikasyon testlerinden geçmiş bir ürün seçmek ayrıca iyi bir filtre.
Üretimde Dikkat
Hangisini seçersen seç, client'ları ve konfigürasyonu kod olarak tut: Keycloak'ta realm export ya da bu yazı serisindeki gibi bir kurulum script'i, Duende ve OpenIddict'te seed kodu, Entra'da Terraform ya da Bicep gibi bir araç. Elle tıklanarak kurulmuş bir authorization server'ın ne zaman, kim tarafından, neden değiştiğini bilemezsin. Test, staging ve production'da ayrı realm/tenant kullan; 13. yazıdaki audience kuralı ortamlar arası token taşınmasını da engellemeli.
Taşınabilirliği baştan düşün: kullanıcı kimliklerini uygulamanda iss + sub ile tut, authorization server'a özgü claim'lere (Keycloak'un realm_access'ı, Entra'nın oid'i) tek bir adaptörün arkasında eriş. 13. yazıdaki RequireScope extension method'u ve 16. yazıda göreceğimiz rol okuma adaptörü bu yüzden ayrı yerlerde duruyor. Lisanslı bir ürün seçtiysen lisans süresinin dolması bir kesinti senaryosu olarak runbook'ta olmalı.
Sık Düşülen Tuzaklar
Birincisi, discovery dokümanını ya da bir karşılaştırma tablosunu (bu yazınınki dahil) özellik listesi sanmak. İkincisi, "ücretsiz" kelimesini yalnız lisans maliyeti olarak okumak; OpenIddict'in ve Keycloak'un lisansı ücretsiz, işletmesi ve geliştirmesi değil. Üçüncüsü, Duende'yi lisanssız hâliyle production'a çıkarmak; log'daki uyarı bunun izin verilmediğini söylüyor. Dördüncüsü, yeni bir projeyi Azure AD B2C üzerine kurmaya çalışmak.
Beşincisi, authorization server'ı tek instance çalıştırmak. Altıncısı, kurumsal müşterinin SAML ihtiyacını sözleşme imzalandıktan sonra öğrenmek. Yedincisi, ürün özelliklerini ve lisans koşullarını bir kez okuyup yıllarca o bilgiyle karar vermek; bu yazıdaki bilgiler Kasım 2026'ya ait.
Küçük Bir Deneme
★☆☆ ascheck'e bir satır ekle: token_endpoint_auth_methods_supported içinde client_secret_post var mı? Dört sunucu için sonucu yorumla.
★★☆ Duende kurulumuna private_key_jwt client authentication'ı ekle (Duende dokümanındaki JWT (JSON Web Token) bearer client authentication ayarı) ve matrisin değiştiğini göster. Aynı şeyi OpenIddict'te DPoP için araştır: sürüm 7.8.0'da destekleniyor mu, nasıl açılıyor?
★★★ Bookstore için kendi ekibinin kısıtlarıyla (ekip büyüklüğü, bütçe, kurumsal müşteri sayısı, veri yerleşimi) ağırlıklı bir karar matrisi hazırla; her kritere 1-5 puan ve ağırlık ver, sonucu bu yazıdaki kaba önerilerle karşılaştır.
Kimin giriş yaptığını ve token'ı kimin bastığını konuştuk. Bir sonraki yazıda içeri giren kullanıcının ne yapabileceğine geçiyoruz: RBAC (Role-Based Access Control), ABAC (Attribute-Based Access Control), ReBAC (Relationship-Based Access Control), permission tabanlı tasarım ve multi-tenant senaryolar.