Skip to main content
PKCE (Proof Key for Code Exchange, RFC 7636), Authorization Code akışını client_secret saklayamayan istemciler için güvenli hale getiren bir uzantıdır. Flextell, PKCE’yi tüm OAuth istemcileri için destekler ve SPA / native mobil uygulamalar için zorunlu kılmanızı öneririz.

Neden PKCE?

Tarayıcıda çalışan bir SPA veya native bir mobil uygulamanın kaynak kodu son kullanıcının cihazında çalışır. Bu ortama gömdüğünüz client_secret’ı tersine mühendislik ile çıkarmak önemsiz kolaydır. PKCE, secret yerine tek seferlik dinamik bir secret (code_verifier) üreterek bu riski ortadan kaldırır.

Karşıladığı tehdit

Authorization Code interception: Kötü niyetli bir uygulama, hedef uygulamanın redirect_uri şemasını ele geçirirse (özellikle mobilde myapp://callback gibi custom URI’ler), kullanıcının yetkilendirme dönüşünde gelen code’u yakalayıp access token’a değişebilir. PKCE, sadece doğru code_verifier’a sahip istemcinin code’u token’a çevirebilmesini sağlar.

Akış

Adım 1 — code_verifier ve code_challenge üret

code_verifier, 43–128 karakter uzunluğunda kriptografik olarak rastgele üretilmiş bir string’tir. Her yetkilendirme akışı için yeni bir tane üretilmelidir. code_challenge, code_verifier’ın SHA-256 özetinin base64url (padding’siz) kodlanmış halidir.

JavaScript örneği

function base64UrlEncode(arrayBuffer) {
  return btoa(String.fromCharCode(...new Uint8Array(arrayBuffer)))
    .replace(/\+/g, "-")
    .replace(/\//g, "_")
    .replace(/=+$/, "");
}

async function generatePkcePair() {
  const verifierBytes = crypto.getRandomValues(new Uint8Array(32));
  const verifier = base64UrlEncode(verifierBytes);

  const digest = await crypto.subtle.digest(
    "SHA-256",
    new TextEncoder().encode(verifier),
  );
  const challenge = base64UrlEncode(digest);

  return { verifier, challenge };
}

Python örneği

import hashlib, secrets, base64

def generate_pkce_pair():
    verifier = secrets.token_urlsafe(64)[:64]
    digest = hashlib.sha256(verifier.encode("ascii")).digest()
    challenge = base64.urlsafe_b64encode(digest).rstrip(b"=").decode("ascii")
    return verifier, challenge
code_verifier’ı kullanıcı tarafında güvenli bir yerde saklayın: SPA için sessionStorage (tek sekme), iOS için Keychain, Android için EncryptedSharedPreferences. Asla log’lamayın.

Adım 2 — Yetkilendirmeye yönlendir

Standart authorize URL’ine code_challenge ve code_challenge_method=S256 parametrelerini ekleyin:
https://dev.flextell.ai/oauth/authorize
  ?response_type=code
  &client_id=SIZIN_CLIENT_ID
  &redirect_uri=myapp%3A%2F%2Fcallback
  &scope=openid%20profile%20email%20appointments%3Aread
  &state=RASTGELE_STRING
  &code_challenge=HESAPLANAN_CHALLENGE
  &code_challenge_method=S256

Ek parametreler

code_challenge
string
required
code_verifier’ın SHA-256 özeti, base64url (padding’siz).
code_challenge_method
string
required
Her zaman S256 kullanın. plain metodu destekleniyor olsa da zayıftır — production’da kullanmayın.

Adım 3 — Token değişimi (verifier ile)

code’u aldıktan sonra /oauth/token endpoint’ine code_verifier parametresi ile istek atın. client_secret göndermeyin — zaten saklamıyorsunuz:
curl --request POST \
  --url https://dev.flextell.ai/oauth/token \
  --header "Content-Type: application/x-www-form-urlencoded" \
  --data "grant_type=authorization_code" \
  --data "code=AUTHORIZATION_CODE" \
  --data "client_id=SIZIN_CLIENT_ID" \
  --data "redirect_uri=myapp://callback" \
  --data "code_verifier=ADIM_1_DE_URETTIGIN_VERIFIER"

Başarılı yanıt

{
  "token_type": "Bearer",
  "expires_in": 1296000,
  "access_token": "eyJ0eXAi...",
  "refresh_token": "def502...",
  "id_token": "eyJhbGci..."
}
openid scope’u talep ettiyseniz id_token da döner. Detay: OpenID Connect.

Hata yanıtları

HTTPerrorSebep
400invalid_requestcode_challenge gönderildi ama code_challenge_method eksik (veya tersi).
400invalid_grantcode_verifier → SHA-256 → base64url sonucu, saklanan code_challenge ile eşleşmiyor.
400invalid_grantcode başka bir istemci için üretilmiş (client_id uyuşmuyor).

Güvenlik kontrol listesi

  • Her akış için yeni code_verifier üretin. Verifier’ı yeniden kullanmayın.
  • S256 kullanın; plain production’da kabul edilemez.
  • code_verifier’ı logging sistemine yazmayın — kısa ömürlü olsa bile.
  • SPA’da state ve code_verifier’ı sessionStorage’da, callback sayfasında tek seferlik okuyup hemen silin.
  • Native mobilde güvenli depolama (Keychain / EncryptedSharedPreferences) kullanın.
  • state parametresini her akışta doğrulayın — PKCE, state kontrolünü ikame etmez.

Confidential client’larda PKCE

Sunucu tabanlı (confidential) istemciler için PKCE zorunlu değildir ama ek katman olarak kullanmakta sakınca yoktur. Hem client_secret hem code_verifier göndermek kabul edilir.

Hangi kütüphaneler bu akışı hazır yapar?

Çoğu OAuth / OIDC kütüphanesi PKCE’yi otomatik yürütür: Flextell’in discovery URL’ini (https://dev.flextell.ai/.well-known/openid-configuration) verip code_challenge_method=S256 ayarını açmanız çoğunlukla yeterlidir.

Sonraki adımlar

OpenID Connect

id_token doğrulama, discovery, userinfo.

Authorization Code

Akışın standart (confidential client) hali.