OAuth 2.0 ve OpenID Connect: Kavramlar, Akışlar ve Güvenli Uygulama
OAuth 2.0 bir yetkilendirme çerçevesidir; bir uygulamanın kullanıcı adına başka bir servisteki kaynaklara sınırlı erişim almasını sağlar. OpenID Connect (OIDC) ise OAuth 2.0 üzerine kurulu bir kimlik doğrulama katmanıdır ve "bu kullanıcı kim?" sorusunu standart bir şekilde yanıtlar. İkisini karıştırmak, sahada en sık yapılan mimari hatanın kaynağıdır: OAuth 2.0 tek başına kullanıcıyı tanımlamaz, yalnızca erişim yetkisi verir.
Bu rehberde terimleri netleştirip, akışları adım adım ele alacak, kod örneklerinde yalnızca doğruluğundan emin olduğum yapıları kullanacağım. Sürüme bağlı ayrıntılarda (örneğin kütüphane API'leri) güncel sürüm numarası uydurmak yerine, kavramsal ve protokol düzeyinde kalacağım.
Temel Terimler
- Resource Owner: Kaynağın sahibi, genellikle son kullanıcı.
- Client: Kaynağa erişmek isteyen uygulama (web, mobil, SPA, CLI).
- Authorization Server: Kullanıcıyı doğrulayan ve token üreten sunucu.
- Resource Server: Korumalı kaynakları barındıran API.
- Access Token: Kaynağa erişim için kullanılan, süreli kimlik bilgisi.
- Refresh Token: Access token süresi dolduğunda yenisini almak için kullanılır.
- Scope: İstenen yetkinin kapsamı (örneğin
read:profile). - ID Token (OIDC): Kullanıcı kimliğini taşıyan, imzalı JWT.
OAuth 2.0 Akışları
OAuth 2.0 birden fazla "grant type" tanımlar. Doğru akışı seçmek, güvenliğin ilk adımıdır.
Authorization Code + PKCE
Kullanıcı etkileşimi olan web, mobil ve SPA uygulamaları için önerilen akıştır. PKCE (Proof Key for Code Exchange), yetkilendirme kodunun ele geçirilmesi durumunda saldırganın token alamamasını sağlar.
Adımlar:
- Client, rastgele bir
code_verifierüretir ve bundancode_challengetüretir (genellikle SHA-256 + Base64URL). - Kullanıcı, authorization endpoint'ine yönlendirilir;
code_challengevecode_challenge_method=S256gönderilir. - Kullanıcı giriş yapıp onay verir; authorization server bir
codeile geri yönlendirir. - Client,
codeile birliktecode_verifier'ı token endpoint'ine gönderir. - Server,
code_challengeilecode_verifier'ı doğrular ve token'ları döner.
PKCE'nin plain yerine S256 yöntemiyle kullanılması tercih edilmelidir.
Client Credentials
Kullanıcı yoktur; servisler arası (machine-to-machine) erişim içindir. Client, kendi kimlik bilgileriyle doğrudan token alır.
Device Code
Tarayıcısı veya klavyesi kısıtlı cihazlar (TV, CLI) içindir. Cihaz bir kod gösterir, kullanıcı başka bir cihazdan bu kodu onaylar.
Kullanımdan Kaçınılması Gerekenler
- Implicit Flow: Token'lar URL fragment'ında taşınır; SPA'lar için artık Authorization Code + PKCE tercih edilmelidir.
- Resource Owner Password Credentials: Kullanıcı parolasının client'a verilmesini gerektirir; güven modelini bozar.
OpenID Connect Katmanı
OIDC, OAuth 2.0'a şu eklemeleri yapar:
- ID Token: İmzalı JWT;
iss,sub,aud,exp,iatgibi standart claim'ler taşır. - UserInfo Endpoint: Access token ile çağrılan, kullanıcı bilgisi dönen endpoint.
- Discovery:
/.well-known/openid-configurationüzerinden endpoint'ler ve anahtarlar keşfedilir. - JWKS: ID token imzasını doğrulamak için kullanılan açık anahtarlar.
Kimlik doğrulama gerekiyorsa scope içine mutlaka openid eklenir. openid olmadan dönen yanıt bir OIDC yanıtı değildir.
Token Doğrulama: Neye Dikkat Edilmeli
ID token bir JWT ise, doğrulama sırasında şu kontroller atlanmamalıdır:
- İmza, sağlayıcının JWKS'inden alınan anahtarla doğrulanmalı.
issbeklenen sağlayıcıyla eşleşmeli.audkendi client ID'nizle eşleşmeli.expveiatzaman penceresi kontrol edilmeli.- Algoritma, token başlığındaki
alg'a körü körüne güvenilmeden sabitlenmeli.
alg: none kabul eden bir doğrulayıcı, imza kontrolünü tamamen devre dışı bırakır. Kütüphanelerin varsayılanlarına güvenmek yerine, izin verilen algoritmalar açıkça belirtilmelidir.
Kod Örneği: Authorization Code + PKCE (Node.js)
Aşağıdaki örnek, PKCE için code_verifier ve code_challenge üretimini ve token değişimini gösterir. Node.js'in yerleşik crypto ve fetch API'lerini kullanır.
const crypto = require('crypto');
function base64url(buffer) {
return buffer
.toString('base64')
.replace(/\+/g, '-')
.replace(/\//g, '_')
.replace(/=+$/, '');
}
function createPkcePair() {
const verifier = base64url(crypto.randomBytes(32));
const challenge = base64url(
crypto.createHash('sha256').update(verifier).digest()
);
return { verifier, challenge };
}
async function exchangeCodeForTokens({ tokenEndpoint, code, verifier, clientId, redirectUri }) {
const body = new URLSearchParams({
grant_type: 'authorization_code',
code,
code_verifier: verifier,
client_id: clientId,
redirect_uri: redirectUri,
});
const res = await fetch(tokenEndpoint, {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body,
});
if (!res.ok) {
const text = await res.text();
throw new Error(`Token endpoint hatası: ${res.status} ${text}`);
}
return res.json();
}
Beklenen davranış: exchangeCodeForTokens, geçerli bir kod ve eşleşen code_verifier ile çağrıldığında access_token, genellikle refresh_token ve (OIDC ise) id_token içeren bir JSON döner. Kod veya verifier uyuşmazsa token endpoint'i hata döner.
Bu örnek, protokol düzeyindeki adımları göstermek için yazılmıştır; üretimde kütüphane kullanmak daha güvenlidir çünkü state yönetimi, nonce ve hata durumları elle yönetilmesi kolay olmayan ayrıntılardır.
Güvenlik Kontrol Listesi
- PKCE kullanın: Authorization Code akışında
S256zorunlu kabul edilmeli. stateparametresi: CSRF'e karşı, istemcide saklanan rastgele bir değerle karşılaştırılmalı.nonce(OIDC): ID token'ın tekrar oynatılmasını engellemek için kullanılmalı.- Redirect URI: Tam eşleşme ile doğrulanmalı; joker karakterlerden kaçınılmalı.
- Token saklama: Tarayıcıda
localStorageyerine, mümkünseHttpOnly+Secureçerezler veya bellek içi saklama tercih edilmeli. - Scope minimizasyonu: Yalnızca gereken scope'lar istenmeli.
- Token ömrü: Access token kısa, refresh token rotasyonlu tutulmalı.
- HTTPS: Tüm uç noktalar TLS üzerinden çalışmalı.
Yaygın Hatalar
- OAuth'u kimlik doğrulama sanmak: Access token "kim" sorusunu yanıtlamaz; kimlik için OIDC'nin ID token'ı gerekir.
- Implicit flow'u SPA'da kullanmak: Token'lar URL'de görünür; PKCE'li Authorization Code tercih edilmelidir.
- ID token'ı doğrulamadan kullanmak: İmza ve claim kontrolleri atlanırsa sahte token kabul edilebilir.
statevenonceüretmemek: CSRF ve replay saldırılarına açık hale gelir.- Refresh token'ı istemciye açık şekilde bırakmak: Çalınması durumunda uzun süreli erişim sağlar; rotasyon uygulanmalıdır.
- Kapsamı çok geniş tutmak: Gereksiz yetkiler, ihlal durumunda etki alanını büyütür.
Sonuç
OAuth 2.0 yetki, OIDC kimlik içindir. Kullanıcı etkileşimi olan uygulamalarda PKCE'li Authorization Code akışı, servisler arası erişimde Client Credentials, kısıtlı cihazlarda Device Code tercih edilmelidir. Token doğrulamasında imza, iss, aud, exp ve algoritma sabitlemesi pazarlık konusu değildir. state, nonce, dar scope ve kısa ömürlü token'lar, çerçevenin sağladığı güvenliğin uygulamada da korunmasını sağlar. Kütüphane seçerken protokol ayrıntılarını doğru uyguladığını belgeleyen, aktif bakımda olan seçenekler değerlendirilmelidir.