OAuth 2.0 vs OAuth 2.1: Security Farkları ve Migration Rehberi (2026)

01.01.2026 20:35 Haber

2023'te yayınlanan OAuth 2.1, OAuth 2.0'ın bilinen güvenlik açıklarını kapatan yeni standarttır. OAuth 2.0 vs OAuth 2.1 karşılaştırmasında en kritik farklar: PKCE zorunluluğu, implicit flow kaldırılması, refresh token rotation. Alesta Web olarak bu değişikliklerin production sistemlerinize etkisini analiz ediyoruz.

OAuth 2.0 vs OAuth 2.1: Genel Bakış

OAuth 2.1 (RFC 9700), OAuth 2.0'ın evolution'ı olup, 10+ yıllık production deneyiminden öğrenilen güvenlik iyileştirmelerini standartlaştırır:

? OAuth 2.0 vs OAuth 2.1 Temel Farklar

Özellik OAuth 2.0 (2012) OAuth 2.1 (2023)
PKCE Optional (mobile için önerilen) ✅ Zorunlu (tüm client'lar)
Implicit Flow Destekleniyor (SPA için) ❌ Kaldırıldı (güvenli değil)
Refresh Token Rotation Optional ✅ Zorunlu (önerilen)
Redirect URI Substring match kabul ✅ Exact match zorunlu
Authorization Code Lifetime 10 dakika (önerilen) ✅ Max 60 saniye
Client Secret Public client'ta optional ✅ PKCE ile değiştirildi
? Alesta Web İstatistiği:

2026 itibariyle major OAuth provider'ların OAuth 2.1 uyumluluğu:

  • Google Identity: %100 uyumlu (PKCE zorunlu 2024'ten beri)
  • Microsoft Entra ID: %95 uyumlu (implicit flow deprecated)
  • Auth0: %100 uyumlu (full OAuth 2.1 support)
  • Keycloak 24+: %100 uyumlu
  • AWS Cognito: %90 uyumlu (PKCE zorunlu)

PKCE Artık Zorunlu (En Kritik Değişiklik)

OAuth 2.1 en önemli değişiklik: PKCE (Proof Key for Code Exchange) tüm client'lar için zorunlu:

PKCE Nedir ve Neden Zorunlu?

PKCE, authorization code interception saldırılarını önler:

// ❌ OAuth 2.0: PKCE olmadan (güvenlik açığı)
// 1. Client authorization code alır
const authUrl = `https://oauth.example.com/authorize?
  response_type=code&
  client_id=my-app&
  redirect_uri=https://myapp.com/callback`

// 2. User consent verir, code döner
// https://myapp.com/callback?code=AUTH_CODE_123

// 3. Token exchange (saldırıya açık!)
fetch('https://oauth.example.com/token', {
  method: 'POST',
  body: new URLSearchParams({
    grant_type: 'authorization_code',
    code: 'AUTH_CODE_123',  // ❌ Çalınabilir (MITM, malicious app)
    client_id: 'my-app',
    redirect_uri: 'https://myapp.com/callback'
  })
})

// Saldırgan AUTH_CODE_123'ü çalarsa kendi adına token alabilir!

✅ OAuth 2.1: PKCE ile (Güvenli)

// PKCE implementation
import crypto from 'crypto';

// 1. Code verifier ve challenge oluştur
function generateCodeVerifier() {
  return crypto.randomBytes(32).toString('base64url');  // 43 karakter
}

function generateCodeChallenge(verifier) {
  return crypto.createHash('sha256')
    .update(verifier)
    .digest('base64url');
}

const codeVerifier = generateCodeVerifier();  // Client'ta sakla
const codeChallenge = generateCodeChallenge(codeVerifier);

// 2. Authorization request (code_challenge gönder)
const authUrl = `https://oauth.example.com/authorize?
  response_type=code&
  client_id=my-app&
  redirect_uri=https://myapp.com/callback&
  code_challenge=${codeChallenge}&
  code_challenge_method=S256`  // SHA-256

// 3. User consent, code döner
// https://myapp.com/callback?code=AUTH_CODE_123

// 4. Token exchange (code_verifier gönder)
fetch('https://oauth.example.com/token', {
  method: 'POST',
  body: new URLSearchParams({
    grant_type: 'authorization_code',
    code: 'AUTH_CODE_123',
    client_id: 'my-app',
    redirect_uri: 'https://myapp.com/callback',
    code_verifier: codeVerifier  // ✅ Server SHA-256 ile doğrular
  })
})

// Saldırgan code'u çalsa bile code_verifier olmadan token alamaz! ✅
✅ PKCE Avantajları:
  • Authorization code interception önlenir: Saldırgan code'u çalsa bile işe yaramaz
  • Client secret gereksiz: Public client'larda (SPA, mobile) güvenlik artar
  • MITM attack koruması: Code verifier sadece client'ta, network'te geçmez
  • Backward compatible: OAuth 2.0 server'lar PKCE destekleyebilir

Implicit Flow Kaldırıldı

OAuth 2.0 vs OAuth 2.1 en büyük fark: Implicit flow artık yok:

❌ OAuth 2.0: Implicit Flow (Deprecated)

// Implicit flow - OAuth 2.0 (SPA için kullanılıyordu)
const authUrl = `https://oauth.example.com/authorize?
  response_type=token&  // ❌ Direkt token fragment'te döner
  client_id=my-spa-app&
  redirect_uri=https://myapp.com/callback`

// User consent sonrası:
// https://myapp.com/callback#access_token=TOKEN_ABC&token_type=Bearer&expires_in=3600

// JavaScript ile token al
const token = new URLSearchParams(window.location.hash.substring(1)).get('access_token');

// ❌ Güvenlik sorunları:
// 1. Token URL fragment'te → Browser history'de kalır
// 2. Token JavaScript erişilebilir → XSS saldırısı riski
// 3. Refresh token yok → Long-lived access token (güvenli değil)
// 4. PKCE kullanılamaz

✅ OAuth 2.1: Authorization Code + PKCE (SPA için)

// Modern SPA authentication (OAuth 2.1)
// 1. PKCE ile authorization code flow
const codeVerifier = generateCodeVerifier();
const codeChallenge = generateCodeChallenge(codeVerifier);

const authUrl = `https://oauth.example.com/authorize?
  response_type=code&  // ✅ Code döner (token değil)
  client_id=my-spa-app&
  redirect_uri=https://myapp.com/callback&
  code_challenge=${codeChallenge}&
  code_challenge_method=S256`

// 2. Callback'te code al
const code = new URLSearchParams(window.location.search).get('code');

// 3. Token exchange (backend'siz, PKCE ile)
const tokenResponse = await fetch('https://oauth.example.com/token', {
  method: 'POST',
  headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
  body: new URLSearchParams({
    grant_type: 'authorization_code',
    code: code,
    client_id: 'my-spa-app',
    redirect_uri: 'https://myapp.com/callback',
    code_verifier: codeVerifier  // ✅ PKCE
  })
});

const { access_token, refresh_token } = await tokenResponse.json();

// ✅ Token fragment yerine POST body'de → Browser history'de yok
// ✅ Refresh token var → Short-lived access token kullanılabilir
// ✅ PKCE koruması
⚠️ Migration Uyarısı:

Alesta Web müşterilerinde implicit flow kullanan SPA'lar için:

  1. 2024-2025: Implicit flow deprecated oldu (Google, Microsoft)
  2. 2026+: Implicit flow support tamamen kalkıyor
  3. Çözüm: Authorization code + PKCE'ye migration yapın
  4. Alternative: Backend-for-Frontend (BFF) pattern (daha güvenli)

Refresh Token Rotation ve Güvenlik

OAuth 2.1, refresh token rotation'ı zorunlu kılar (önerir):

Refresh Token Rotation Nedir?

// ❌ OAuth 2.0: Refresh token tekrar kullanılabilir (risky)
// İlk token exchange
POST /token
{
  "grant_type": "authorization_code",
  "code": "...",
  ...
}

Response:
{
  "access_token": "ACCESS_1",
  "refresh_token": "REFRESH_STATIC",  // ❌ Aynı token her zaman
  "expires_in": 3600
}

// Access token expire olunca refresh
POST /token
{
  "grant_type": "refresh_token",
  "refresh_token": "REFRESH_STATIC"  // ❌ Aynı token tekrar kullanılıyor
}

Response:
{
  "access_token": "ACCESS_2",
  "refresh_token": "REFRESH_STATIC",  // ❌ Yine aynı
  "expires_in": 3600
}

// Problem: Refresh token çalınırsa saldırgan sonsuza kadar access token alabilir!

✅ OAuth 2.1: Refresh Token Rotation

// İlk token exchange
POST /token
{
  "grant_type": "authorization_code",
  "code": "...",
  ...
}

Response:
{
  "access_token": "ACCESS_1",
  "refresh_token": "REFRESH_1",  // ✅ Benzersiz token
  "expires_in": 3600
}

// Access token expire olunca refresh
POST /token
{
  "grant_type": "refresh_token",
  "refresh_token": "REFRESH_1"
}

Response:
{
  "access_token": "ACCESS_2",
  "refresh_token": "REFRESH_2",  // ✅ Yeni refresh token döner
  "expires_in": 3600
}

// REFRESH_1 artık geçersiz! ✅

// Eğer REFRESH_1 tekrar kullanılırsa (saldırı!)
POST /token
{
  "grant_type": "refresh_token",
  "refresh_token": "REFRESH_1"  // ❌ Eski token
}

Response:
{
  "error": "invalid_grant",
  "error_description": "Refresh token reuse detected"
}

// Server TÜM refresh token'ları invalidate eder (breach detection) ✅
✅ Refresh Token Rotation Faydaları:

Alesta Web production sistemlerinde gözlemlenen iyileşmeler:

  • Token theft detection: Eski token tekrar kullanılırsa breach detect edilir
  • Automatic revocation: Breach durumunda tüm token'lar iptal edilir
  • Limited damage: Çalınan token sadece 1 kez kullanılabilir
  • Compliance: GDPR, PCI-DSS güvenlik gereksinimlerini karşılar

Redirect URI Exact Match Zorunluluğu

OAuth 2.1, redirect URI'da exact match zorunlu kılar:

❌ OAuth 2.0: Substring Match (Vulnerable)

// OAuth provider config (OAuth 2.0)
const registeredRedirectURIs = [
  'https://myapp.com/callback'  // Registered URI
];

// Authorization request
const authUrl = `https://oauth.example.com/authorize?
  ...
  redirect_uri=https://myapp.com/callback?evil=attacker.com`  // ❌ Substring match

// OAuth 2.0 bazı provider'lar şunu kabul eder:
// https://myapp.com/callback?evil=attacker.com
// Çünkü "https://myapp.com/callback" ile başlıyor

// Saldırgan code'u kendi domain'ine redirect edebilir!

✅ OAuth 2.1: Exact Match (Secure)

// OAuth provider config (OAuth 2.1)
const registeredRedirectURIs = [
  'https://myapp.com/callback',
  'https://myapp.com/callback?source=mobile'  // Exact URI gerekirse ekle
];

// Authorization request
const authUrl = `https://oauth.example.com/authorize?
  ...
  redirect_uri=https://myapp.com/callback`  // ✅ Exact match

// ❌ Bu REJECT edilir:
// redirect_uri=https://myapp.com/callback?evil=attacker.com
// Error: redirect_uri mismatch

// ✅ Sadece kayıtlı URI'lar kabul edilir
⚠️ Wildcard ve Localhost:

OAuth 2.1 exceptions:

  • Localhost: http://localhost:[any_port]/callback kabul edilir (development)
  • Custom scheme: myapp://callback mobile app için kabul edilir
  • Wildcard subdomain: YASAK (https://*.myapp.com/callback güvenli değil)

OAuth 2.0'dan 2.1'e Migration

Alesta Web migration checklist:

Migration Adımları

  1. PKCE Ekle (Kritik):
    // Tüm authorization request'lere code_challenge ekle
    // Tüm token exchange'lere code_verifier ekle
    
  2. Implicit Flow Kaldır:
    // response_type=token → response_type=code
    // SPA'larda authorization code + PKCE kullan
    
  3. Refresh Token Rotation Ekle:
    // Token refresh sonrası eski refresh_token'ı invalidate et
    // Yeni refresh_token döndür
    
  4. Redirect URI Validate Et:
    // Exact match validation ekle
    // Substring match'i kaldır
    
  5. Authorization Code Lifetime Kısalt:
    // 10 dakika → 60 saniye
    

Node.js OAuth 2.1 Implementation (Auth0 örneği)

// npm install openid-client
import { Issuer, generators } from 'openid-client';

// 1. OAuth provider discovery
const auth0Issuer = await Issuer.discover('https://YOUR_DOMAIN.auth0.com');

const client = new auth0Issuer.Client({
  client_id: 'YOUR_CLIENT_ID',
  redirect_uris: ['https://myapp.com/callback'],
  response_types: ['code'],  // ✅ Authorization code only
  token_endpoint_auth_method: 'none'  // ✅ PKCE, client secret yok
});

// 2. PKCE code verifier/challenge
const codeVerifier = generators.codeVerifier();
const codeChallenge = generators.codeChallenge(codeVerifier);

// 3. Authorization URL
const authUrl = client.authorizationUrl({
  scope: 'openid profile email',
  code_challenge: codeChallenge,
  code_challenge_method: 'S256'  // ✅ PKCE
});

// 4. Callback handling
const params = client.callbackParams(req);
const tokenSet = await client.callback(
  'https://myapp.com/callback',
  params,
  { code_verifier: codeVerifier }  // ✅ PKCE
);

// 5. Refresh token rotation (automatic with openid-client)
const refreshed = await client.refresh(tokenSet.refresh_token);
// refreshed.refresh_token → Yeni token ✅

OAuth 2.1 Implementation Best Practices

Alesta Web production recommendations:

Security Best Practices

  • Short-lived access tokens: 15-60 dakika (default 1 saat)
  • Refresh token expiry: 30-90 gün (uzun session'lar için)
  • State parameter: CSRF koruması için her request'te unique state
  • Nonce parameter: ID token replay attack önleme (OpenID Connect)
  • HTTPS only: Production'da HTTP redirect URI yasak
  • Token storage: LocalStorage YASAK, HttpOnly cookie kullan (SPA'da)
  • Scope minimization: Sadece gerekli scope'ları iste
✅ Alesta Web Production Setup:

E-commerce platform (100K+ users):

  • Auth Provider: Auth0 (OAuth 2.1 full support)
  • Access Token: 30 dakika (JWT)
  • Refresh Token: 60 gün (rotation enabled)
  • PKCE: Tüm client'larda (web, mobile, SPA)
  • Security: %0 token theft incident (2025-2026)

Feature Comparison Table

? OAuth 2.0 vs OAuth 2.1 Full Comparison

Feature OAuth 2.0 OAuth 2.1 Impact
PKCE Optional Mandatory ✅ High
Implicit Flow Supported Removed ❌ High
Refresh Token Rotation Optional Recommended ✅ Medium
Redirect URI Match Substring OK Exact Match ✅ Medium
Bearer Token Supported Unchanged -
Client Credentials Supported Unchanged -

✅ Özet: OAuth 2.0 vs OAuth 2.1

OAuth 2.1, OAuth 2.0'ın güvenlik açıklarını kapatan evrimdir. En kritik değişiklikler: PKCE zorunlu (authorization code interception önlenir), implicit flow kaldırıldı (XSS riski azaltıldı), refresh token rotation (token theft detection). Alesta Web olarak tüm yeni projelerde OAuth 2.1 kullanmanızı öneriyoruz.

Migration Checklist:

  • ✅ PKCE tüm client'larda implement edildi mi?
  • ✅ Implicit flow kaldırıldı mı (SPA'da code flow)?
  • ✅ Refresh token rotation aktif mi?
  • ✅ Redirect URI exact match validation var mı?
  • ✅ Authorization code lifetime < 60 saniye mi?
  • ✅ Token storage secure mu (HttpOnly cookie)?

Faydalı Kaynaklar:

© 2026 Alesta Web - OAuth ve API security uzmanınız. Tüm hakları saklıdır.

WM Tools
💫

WebMaster Tools

15 Profesyonel Araç