API anahtarları ile OAuth farklı sorunları çözer ve ikisi arasındaki seçim tek bir soruyla başlar: şemada üçüncü bir taraf var mı?

Sunucunuz başkasının API'sini kendi adına çağırıyorsa anahtar gerekir. Başkasının uygulaması sizin API'nizi sizin kullanıcınızın adına çağırıyorsa OAuth gerekir. Üçüncü taraf yoksa OAuth tören ekler, güvenlik eklemez.

Devamında: ikisi gerçekte nerede ayrışıyor, OAuth'ta son yıllarda ne değişti ve API anahtarlarının neredeyse hiç yazılmayan, oysa canlı ortamda onunla nasıl yaşayacağınızı belirleyen bir özelliği.

API anahtarı: "bu programa izin var" diyen tek satır

Anahtar, istek başlığına koyduğunuz uzun ve rastgele bir dizedir:

X-Api-Key: lix_live_9f2c...

Sunucu anahtarı bulur, hangi hesaba ait olduğunu anlar ve isteği geçirir. Mekanizmanın tamamı bu kadar.

Buradan çıkan özellikler:

  • anahtar kendiliğinden sona ermez. Biri onu iptal edene kadar yaşar;
  • anahtar bir programı tanımlar, bir kişiyi değil. Ekipten kimin çağrı yaptığı genelde görünmez;
  • anahtar, hesabın yapabildiği her şeye izin verir, yetkileri ayrıca kısıtlamadıysanız;
  • anahtar tek sırdır. Sızdıysa erişim sızmıştır; arada bir kademe yoktur.

OAuth: rıza üzerine kurulu bir protokol

OAuth 2.0 (RFC 6749) başka bir soruyu yanıtlar. Dört katılımcısı vardır: verinin sahibi, onu isteyen uygulama, bir yetkilendirme sunucusu ve veriyi tutan sunucu.

Akış kabaca şöyle işler. Uygulama kişiyi servisin kendi sayfasına yollar. Kişi kimin ne istediğini görür ve kabul eder. Uygulama bir kod alır, onu erişim belirtecine çevirir ve API'yi onunla çağırır. Belirtecin ömrü kısadır — dakikalar ya da saatler; süresi dolunca uygulama yenileme belirtecini yenisiyle takas eder.

Bunun sağladığı, anahtarın ilkesel olarak sağlayamayacağı şeyler:

  • kullanıcının parolası uygulamaya hiç ulaşmaz. Bütün mesele budur;
  • yetkiler kapsamlara bölünür. "Bağlantıları okumak" ile "bağlantıları silmek" ayrı izinlerdir;
  • rıza görünür ve geri alınabilirdir. Kullanıcı bağlı uygulamaların listesini görür ve diğerlerine dokunmadan birini koparabilir;
  • belirteçler kendiliğinden geçersizleşir. Çalınmış bir erişim belirteci bir saat sonra işe yaramaz.

Bedeli karmaşıklıktır: bir yetkilendirme sunucusu, uygulama kaydı, bir rıza ekranı, yenileme belirteçlerinin saklanması ve döndürülmesi, her çağrıda süre dolumunun ele alınması.

Kararı gerçekten belirleyen eksenlerde karşılaştırma

API anahtarı OAuth 2.0
Kimi doğrular programı programın adına çalıştığı kullanıcıyı
Ömür süresiz erişim belirteci: dakikalar–saatler
Erişim nasıl biter anahtarı iptal ederek rızayı ya da belirteci geri alarak
Yetki genişliği genellikle tüm hesap eylem başına kapsam
Üçüncü taraftaki sır anahtarın kendisi yalnızca belirteçler, parola asla
Entegrasyon eforu tek bir başlık yetkilendirme sunucusu ve tüm döngü
Nereye uyar sunucudan sunucuya, betikler, şirket içi entegrasyon herkese açık uygulamalar, pazar yerleri, "… ile giriş"

Seçim kuralı

Soru soyut olarak hangisinin daha güvenli olduğu değil, kimin kime erişim devrettiğidir.

Sizin sunucunuz → başkasının API'si, hesap sizin
    → API anahtarı

Başkasının uygulaması → sizin API'niz, hesap kullanıcınızın
    → OAuth

Zamanlanmış görev, CI, arka uç entegrasyonu
    → API anahtarı

Kullanıcı erişimi uygulama bazında görüp iptal edebilmeli
    → OAuth

Postback almak, anahtarın ders kitabı örneğidir. Sunucunuz bizimkine "bu sipariş ödendi" dediğinde bu alışverişte hiçbir kullanıcı yoktur, rıza verecek kimse ve rıza ekranı koyacak bir yer de yoktur. Ters yöndeki webhook'lar için de aynısı geçerlidir.

Siz bakmazken OAuth'ta neler değişti

Konuyla ilgili yazıların yarısı 2015 model OAuth'u anlatıyor. O günden bu yana epeyce daraldı.

Ocak 2025'te IETF, RFC 9700, Best Current Practice for OAuth 2.0 Security belgesini yayımladı. Belge gerçek saldırılardan yıllar içinde biriken deneyimi toplar ve eskiden kabul edilebilir sayılan iki yöntemi resmen kullanımdan kaldırır:

  • implicit grant — belirteci doğrudan adres çubuğunda geri döndüren yöntem;
  • resource owner password credentials — uygulamanın kullanıcıdan kullanıcı adı ve parolasını doğrudan istediği yöntem. Tam da OAuth'un ortadan kaldırması gereken şey.

Aynı anda PKCE, eskiden olduğu gibi yalnızca mobil için değil, sunucu tarafı dahil tüm istemci türleri için zorunlu hale geldi.

Ayrıca bilinmesi gereken bir şey var: OAuth 2.1 hâlâ taslak durumunda, yayımlanmış bir RFC değil. Aynı değişiklikleri tek belgede toplar — zorunlu PKCE, yönlendirme adresinin birebir karşılaştırılması, implicit ve password grant'in kaldırılması, sorgu dizesinde belirtece izin verilmemesi. Onu yürürlükteki standart diye anmak için erken.

Pratik sonuç: okuduğunuz OAuth rehberi implicit akışı öneriyorsa, o rehber eskimiş demektir.

Anahtarların az konuşulan zayıf noktası

Anahtar sona ermez. Bu da iptali tek kaldıracınız yapar. İşte burada rahatsız edici kısım çıkar: iptal genellikle anında değildir.

Her istekte anahtarı doğrulamak, her seferinde veritabanına gitmek demektir. Gerçek trafiği olan herhangi bir API'de bu sonuç önbelleğe alınır. Bizde anahtar ile hesap eşleşmesi önbellekte beş dakika durur. Yani "iptal et" düğmesine basmakla erişimin fiilen kesilmesi arasında beş dakikaya varan bir aralık vardır ve bu sürede ele geçirilmiş anahtar çalışmayı sürdürür.

Bu bir ihmal değil, bir takas: önbellek olmadan her istek veritabanını dövmek zorunda kalır. Anahtar tabanlı API'lerin çoğu benzer bir anlaşma yapar, sadece bunu yüksek sesle söylemek âdet değildir. İki sebepten önemlidir. Birincisi, gerçek bir sızıntıda anahtarı iptal etmek son değil ilk harekettir; ardından o dakikalarda ne olduğunu incelemek gerekir. İkincisi, bu tam olarak OAuth'un kısa ömürlü belirteçlerinin öbür uçtan çözdüğü sorundur — onlar veritabanına hiç uğramadan kendiliğinden geçersizleşir.

Anahtarlarla canınız yanmadan yaşamak

Anahtarlar yetiyorsa — ki çoğu entegrasyonda yetiyor — asgari düzey şudur:

  1. Yalnızca özeti saklayın. Sunucu gelen anahtarın özetini saklanmış olanla karşılaştırır; özgün dize kullanıcıya yalnızca oluşturma anında bir kez gösterilir. Biz SHA-256 ile eşleştiriyoruz.
  2. Anahtara bir önek verin. lix_live_... biçimindeki bir dizeyi depolardaki ve günlük hatlarındaki sır tarayıcıları tanır.
  3. Her entegrasyona ayrı anahtar. Böylece birini iptal etmek diğerlerini devirmez ve kayıtlardan tam olarak neyin ele geçtiği görülür.
  4. Anahtarı asla sorgu dizesine koymayın. Adresler web sunucusu günlüklerine, Referer başlığına ve tarayıcı geçmişine yerleşir. Yalnızca başlık.
  5. Olaydan sonra değil, takvime göre döndürün. Bir kez döndürülmüş anahtar hızla döner. Hiç döndürülmemiş olan, sonunda dört ayrı yere gömülü çıkar.
  6. Son kullanım zamanını izleyin. Altı aydır dokunulmamış anahtar bir yedek değil, açık bir kapıdır.

Biz ne kullanıyoruz

Lix.li API'si anahtarla kimlik doğrular: X-Api-Key başlığı, panelden oluşturulup iptal edilen anahtarlar, özet üzerinden eşleştirme, anahtar başına ayrı istek limiti. OAuth yok ve bu bilinçli: API'nin senaryoları sunucu tarafında — bağlantı oluştur, istatistik çek, dönüşüm kabul et — ve hiçbirinde kullanıcının rıza vermesi gereken bir üçüncü taraf bulunmuyor.

Müşterilerimizin hesaplarına başkalarının uygulamalarını sokma ihtiyacı doğsaydı anahtarlar yetmezdi: kullanıcı kime neyi izin verdiğini görebilmeli ve diğerlerini bozmadan tek bir uygulamayı koparabilmeli. OAuth'un tören olmaktan çıkıp tek dürüst seçenek haline geldiği yer işte orasıdır.

Çağrıların kendisi API belgelerinde yazılı; geçersiz anahtarla ve iptal edilmiş anahtarla hangi yanıt kodlarının döndüğü de orada. Komşu bir konu olarak, 301 yönlendirmesinin POST'u neden GET'e çevirdiği postback alımını kuran herkesin okumasına değer: kimliği doğrulanmış bir istek, yola çıktığından farklı bir yöntemle varabilir.