API Anahtarı Nedir, Nasıl Güvenli Kullanılır?
API anahtarı nedir, neden gizli tutulmalı? Tarayıcı kodundaki riskler, sunucu tarafı proxy, ortam değişkeni ve anahtar yenileme adımları örneklerle.
Bir adres API'sine ilk isteği göndermeden önce bir API anahtarı edinmeniz gerekir. API anahtarı nedir, neden bir parola kadar dikkatle saklanmalıdır ve uygulamanızda nasıl güvenli kullanılır? Bu yazıda önce kavram açıklanıyor. Ardından tarayıcı kodundaki riskler, küçük bir sunucu tarafı proxy, ortam değişkenleri ve anahtar yenileme süreci çalışan örneklerle ele alınıyor.
API anahtarı nedir, ne işe yarar?
API anahtarı (İngilizcesiyle API key), bir API'ye istek gönderen uygulamayı tanımlayan gizli bir metindir. "API key nedir" sorusunun kısa cevabı şudur: Sunucu, her istekte gelen bu değere bakar. Böylece isteğin hangi hesaba ait olduğunu, hangi özelliklere erişebileceğini ve kullanımın hangi kotadan düşüleceğini belirler.
API Türkiye'de anahtar, her /v1 isteğinde X-API-Key başlığıyla gönderilir. Aşağıdaki örnekte anahtar komutun içine yazılmaz, bir kabuk değişkeninden okunur. read -rs komutu girdiyi ekranda göstermez ve kabuk geçmişine kaydetmez:
read -rs APITURKIYE_KEY && export APITURKIYE_KEY
curl "https://api.apiturkiye.com/v1/provinces" \
-H "X-API-Key: $APITURKIYE_KEY"
Anahtar eksik ya da geçersizse yanıt 401 invalid_api_key olur. Anahtar geçerli olduğu hâlde paketiniz ilgili özelliği kapsamıyorsa 403 insufficient_scope döner. REST ve başlık kavramlarına yeniyseniz API nedir yazısı iyi bir başlangıç noktasıdır.
Akılda tutulması gereken nokta şudur: Anahtar tek bir kullanıcıyı değil, hesabınızı temsil eder. Anahtarı ele geçiren biri sizin adınıza istek gönderebilir. Hız sınırı anahtar bazında, kullanım kotası ise hesap bazında işler. Bu nedenle başkasının gönderdiği istekler hem anahtarınızın hız sınırını doldurur hem de hesabınızın kotasından düşer.
Tarayıcı kodundaki anahtar neden risklidir?
Frontend kodu kullanıcının cihazında çalışır. Tarayıcıya gönderdiğiniz her şeyi kullanıcı da görebilir:
- Geliştirici araçlarının Ağ sekmesinde her isteğin başlıkları açıkça görünür.
X-API-Keyda bunlara dahildir. - JavaScript paketini küçültmek (minify) ya da karıştırmak anahtarı gizlemez. Anahtar paketin içinde metin olarak durur ve basit bir aramayla bulunur.
- Derleme araçlarının istemciye açtığı ortam değişkenleri derleme sırasında koda gömülür.
NEXT_PUBLIC_veyaVITE_önekli değişkenler buna örnektir. Bunlara "ortam değişkeni" denmesi, onları gizli yapmaz. - Mobil uygulama paketleri de açılıp incelenebilir. Bu nedenle aynı kural mobil uygulamalar için de geçerlidir.
Örnek senaryo: Bir e-ticaret sitesindeki il-ilçe seçimi, istekleri doğrudan tarayıcıdan API'ye gönderiyor. Siteyi inceleyen biri anahtarı kopyalayıp kendi betiğinde kullanmaya başlıyor. Bir süre sonra gerçek müşteriler 429 hatası almaya başlıyor ya da hesap kotası günün erken saatlerinde tükeniyor. Adres formu çalışmadığı için siparişler yarım kalıyor. Sorunun kaynağı koddaki bir hata değil, yanlış yerde duran bir anahtardır.
Kural basittir: Anahtar yalnız sizin kontrolünüzdeki sunucuda bulunur. Tarayıcı ise yalnız kendi sunucunuza istek gönderir.
Basit bir sunucu tarafı proxy
Proxy, tarayıcı ile adres API'si arasında duran küçük bir sunucu katmanıdır. Tarayıcıdan gelen isteği alır, parametreleri kontrol eder, X-API-Key başlığını ekleyip API'ye iletir ve yanıtı geri döndürür. Aşağıdaki örnek ek paket gerektirmez. Node.js 18 ve üzerindeki yerleşik fetch ile çalışır.
// server.js — Node.js 18+; ek paket gerektirmez
const http = require("node:http");
const API_BASE = "https://api.apiturkiye.com";
const API_KEY = process.env.APITURKIYE_KEY;
if (!API_KEY) {
console.error("APITURKIYE_KEY ortam değişkeni tanımlı değil.");
process.exit(1);
}
// Beyaz liste: İstemci yalnız bu rotaları çağırabilir.
// Her rota kendi parametresini doğrular ve API yolunu kendisi kurar.
const routes = {
"/api/provinces": () => "/v1/provinces",
"/api/districts": (p) => {
const code = p.get("province") ?? "";
return /^\d{1,2}$/.test(code) ? `/v1/provinces/${code}/districts` : null;
},
"/api/neighborhoods": (p) => {
const code = p.get("district") ?? "";
return /^\d{1,10}$/.test(code) ? `/v1/districts/${code}/neighborhoods` : null;
},
"/api/search": (p) => {
const q = (p.get("q") ?? "").trim();
if (q.length < 3 || q.length > 100) return null;
return `/v1/autocomplete?${new URLSearchParams({ q, limit: "10" })}`;
},
};
function send(res, status, body, extraHeaders = {}) {
res.writeHead(status, { "Content-Type": "application/json; charset=utf-8", ...extraHeaders });
res.end(typeof body === "string" ? body : JSON.stringify(body));
}
http.createServer(async (req, res) => {
const url = new URL(req.url, "http://localhost");
const route = routes[url.pathname];
if (req.method !== "GET") return send(res, 405, { error: "Yalnız GET desteklenir" });
if (!route) return send(res, 404, { error: "Bulunamadı" });
const path = route(url.searchParams);
if (!path) return send(res, 400, { error: "Geçersiz parametre" });
try {
const upstream = await fetch(API_BASE + path, {
headers: { "X-API-Key": API_KEY },
signal: AbortSignal.timeout(10_000),
});
const text = await upstream.text();
// 401/403 sizin anahtar veya paket yapılandırmanızla ilgilidir.
// Ayrıntıyı sunucuda loglayın, istemciye genel bir hata dönün.
if (upstream.status === 401 || upstream.status === 403) {
let code = "bilinmiyor";
try { code = JSON.parse(text).error?.code ?? code; } catch {}
console.error(`Adres API yetki hatası: ${upstream.status} ${code}`);
return send(res, 502, { error: "Adres servisi şu anda kullanılamıyor" });
}
const retryAfter = upstream.headers.get("retry-after");
return send(res, upstream.status, text, retryAfter ? { "Retry-After": retryAfter } : {});
} catch (err) {
console.error("Adres API isteği başarısız:", err.name);
return send(res, 502, { error: "Adres servisine ulaşılamadı" });
}
}).listen(3000, () => console.log("Proxy http://localhost:3000 adresinde çalışıyor"));
Tarayıcı tarafında anahtar hiç yer almaz. İstek kendi sunucunuza gider:
// Tarayıcıda: Anahtar yok, istek aynı kökendeki proxy'ye gider
const res = await fetch("/api/districts?province=34");
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const { data } = await res.json(); // İstanbul'un ilçe kayıtları
Kodda üç noktaya dikkat edin:
- Beyaz liste: İstemci, API yolunu kendisi belirleyemez. Gelen yolu olduğu gibi API'ye ileten bir proxy, anahtarınızı herkesin kullanabildiği açık bir kapıya dönüşür.
- Parametre doğrulama: İl kodunun sayısal olup olmadığı, arama metninin 3–100 karakter arasında olup olmadığı önceden kontrol edilir. Geçersiz istekler API'ye hiç gitmez.
- Hata ayrımı: Yetki hataları istemciye ayrıntılı biçimde yansıtılmaz, sunucu loglarına yazılır.
429yanıtındakiRetry-Afterbaşlığı ise istemcinin ne kadar bekleyeceğini bilmesi için iletilir.
Canlı ortamda bu iskeleti kendi oturum kontrolünüz, IP ya da oturum bazlı sınırlamanız ve uygun bir önbellekle güçlendirin. İl ve ilçe listelerini her sayfa açılışında yeniden istemek gerekmez. Bu proxy'yi bir adres formuna bağlamak için il, ilçe ve mahalle seçimli adres formu yazısındaki akışı kullanabilirsiniz.
Anahtarı ortam değişkeninde tutun
Anahtarı kaynak koda sabit olarak yazmak, onu deponun geçmişine kalıcı olarak eklemek demektir. Bunun yerine anahtarı ortam değişkeninden okuyun. Yerel geliştirmede bir .env dosyası kullanabilirsiniz. Yalnız bu dosyanın depoya girmemesi gerekir:
# .env — Git'e eklenmez
APITURKIYE_KEY=apt_live_...
# .gitignore
.env
Node.js 20.6 ve üzerinde dosyayı ek paket kullanmadan yükleyebilirsiniz:
node --env-file=.env server.js
Python tarafında da aynı yaklaşım geçerlidir. Değişken tanımlı değilse uygulamanın hemen ve açık bir hatayla durması, anahtarsız isteklerin sessizce 401 almasından daha kolay teşhis edilir:
import os
import requests
API_KEY = os.environ.get("APITURKIYE_KEY")
if not API_KEY:
raise RuntimeError("APITURKIYE_KEY ortam değişkeni tanımlı değil.")
res = requests.get(
"https://api.apiturkiye.com/v1/provinces/34/districts",
headers={"X-API-Key": API_KEY},
timeout=10,
)
res.raise_for_status()
districts = res.json()["data"]
Sunucuda ise değeri barındırma platformunuzun gizli değer (secret) yönetimiyle, konteyner yapılandırmasıyla ya da süreç yöneticinizle sağlayın. Ortam değişkenine taşımak tek başına yeterli değildir. Ayrıca şunlara da dikkat edin:
- İstek başlıklarını olduğu gibi loglamayın. Hata ayıklama çıktılarında anahtarı maskeleyin.
- Anahtarı URL sorgu parametresine koymayın. URL'ler erişim loglarına ve izleme araçlarına düşer.
- Ekran görüntülerinde, destek taleplerinde ve sohbet mesajlarında anahtarın tam hâlini paylaşmayın.
Anahtarı portaldan iptal etme ve yenileme
API anahtarı güvenliği yalnız saklamaktan ibaret değildir. Anahtarı değiştirmeyi de kolay ve tekrarlanabilir bir işlem hâline getirmeniz gerekir. Anahtarı müşteri portalından alırsınız. İptal ve yenileme işlemleri de aynı yerden yürütülür. İki farklı durum vardır.
Planlı yenileme. Ekipten ayrılan biri, düzenli bir güvenlik takvimi ya da altyapı değişikliği nedeniyle yapılır. Kesintisiz geçiş için sıralama önemlidir:
- Portalda yeni bir anahtar oluşturun.
- Sunucudaki gizli değeri yeni anahtarla güncelleyin ve uygulamayı yeniden başlatın.
- Yeni anahtarın çalıştığını doğrulayın: ``
bash curl "https://api.apiturkiye.com/v1/meta" -H "X-API-Key: $APITURKIYE_KEY"`` - Tüm sunucular yeni anahtara geçtikten sonra eski anahtarı portaldan iptal edin.
- Loglarda
401 invalid_api_keyhatası olup olmadığını izleyin. Bu hata, eski anahtarı kullanmaya devam eden unutulmuş bir servis olduğuna işaret eder.
Sızıntı şüphesi. Bu durumda sıralama tersine döner: Önce eski anahtarı iptal edin, sonra yenisini dağıtın. Kısa bir hizmet kesintisi, kötüye kullanımın sürmesinden daha az zarar verir. Anahtar herkese açık bir depoya gönderildiyse commit'i silmek ya da geçmişi yeniden yazmak yeterli değildir. Anahtarı ele geçirilmiş saymalısınız.
Beklenmedik bir kota tüketimi sızıntının ilk işareti olabilir. Kota uygulanan yanıtlarda X-Quota-Remaining başlığını izleyebilirsiniz. İptal edilmiş bir anahtarla gelen 401 yanıtlarını otomatik olarak yeniden denemeyin. Anahtar düzeltilmeden tekrar gönderilen istekler yalnız gürültü üretir.
API anahtarı güvenliği için kontrol listesi
- Anahtar tarayıcı kodunda, mobil uygulama paketinde veya istemciye açılan ortam değişkenlerinde yer almıyor.
- Tüm adres istekleri, beyaz listeli rotalar kullanan bir sunucu tarafı proxy üzerinden gidiyor.
- Proxy parametreleri doğruluyor ve gelen yolu API'ye olduğu gibi iletmiyor.
- Anahtar ortam değişkeninden okunuyor.
.envdosyası.gitignoreiçinde yer alıyor. - Loglar, URL'ler ve hata çıktıları anahtarı içermiyor.
- Yenileme adımları yazılı ve her çalışan servisin hangi anahtarı kullandığı biliniyor.
401ve403hataları izleniyor ve otomatik olarak yeniden denenmiyor.
Sonraki adım
Kendi anahtarınızı oluşturmak için ücretsiz kayıt sayfasından başlayabilirsiniz. Uçların ve hata kodlarının ayrıntıları API dokümantasyonunda yer alıyor. Paketler arasındaki farkları paket karşılaştırması bölümünde inceleyebilirsiniz.