01 · Kimlik Doğrulama (HMAC İmzalama)
Partner API, HMAC-SHA256 imzalı request'ler kullanır (AWS SigV4 ve Stripe Webhooks ile aynı yaklaşım). Secret asla ağda gitmez; her istek için yeniden hesaplanan bir imza taşınır. Timestamp ve nonce zorunluluğu replay saldırılarını engeller.
Gereksinimler
Her isteğe aşağıdaki 4 header zorunludur:
| Header | Format | Açıklama |
|---|---|---|
X-Trameks-Key-Id | tmk_live_… / tmk_test_… | Public key ID (log'larda görünebilir) |
X-Trameks-Timestamp | 1715900400 | UNIX saniye (UTC). ±5 dakika tolerans |
X-Trameks-Nonce | 16+ karakter hex/base32 | İstek başına benzersiz, replay koruması için |
X-Trameks-Signature | sha256=<64 hex> | Aşağıdaki kanonik string'in HMAC'i |
Opsiyonel:
X-Request-Id— istek başına UUID; bizim log'larımız da bu ID ile eşlenir.
Kanonik string
Tüm parçalar \n (line feed, 0x0A) ile birleştirilir:
METHOD\n
PATH\n
CANONICAL_QUERY\n
TIMESTAMP\n
NONCE\n
BODY_SHA256
METHOD
HTTP metodu, büyük harf: GET, POST, PUT, DELETE.
PATH
URL'in path kısmı (/api/v1/partner/...). Host yok, query yok. Trailing slash route'ta varsa korunur.
CANONICAL_QUERY
Query string'in kanonik hali:
?prefix'i atılır.- Param'lar
&ile parçalanır, her birikey=value. - Aynı key birden fazla kez varsa, aynı key içinde value'lara göre de alfabetik sıralanır.
- Tüm key'ler ve value'lar RFC 3986 ile encode edilir (
%XX, büyük harf hex). - Sonuçlar
&ile birleştirilir. - Boş query için bu satır boş string olur.
Örnek:
input: ?limit=20&cursor=eyJ0…&status=published
output: cursor=eyJ0%E2%80%A6&limit=20&status=published
TIMESTAMP
Header'daki X-Trameks-Timestamp ile tıpa tıp aynı string (entegrasyon farkı olmasın diye).
NONCE
Header'daki X-Trameks-Nonce ile tıpa tıp aynı string.
BODY_SHA256
İstek body byte'larının lowercase hex SHA-256 hash'i.
- Body yoksa veya boşsa:
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 - JSON gönderiyorsanız: tam olarak gönderdiğiniz byte'ları hash'leyin (yeniden serialize etmeyin).
İmza üretimi
signature_hex = hex(HMAC_SHA256(secret_bytes, canonical_string_utf8))
header_value = "sha256=" + signature_hex
sha256= prefix'i ileride farklı algoritma desteği için ayrılmıştır. sha256= olmadan da kabul edilir ama önerilen formatla gönderin.
Sunucu tarafı doğrulama akışı
- 4 header'dan biri eksikse →
401 missing_signature_headers. |now - timestamp| > 300s→401 expired_timestamp.- Key DB'de bulunamadı / REVOKED / EXPIRED / partner SUSPENDED →
401 invalid_key. - (Eğer ipAllowlist boş değilse) kaynak IP listede yoksa →
403 ip_not_allowed. - Kanonik string yeniden hesaplanır, secret AES-GCM ile decrypt edilir, HMAC karşılaştırılır → eşleşmiyorsa
401 invalid_signature. nonceRedis'te zaten varsa →401 replay_detected(TTL: 10 dk).- İstek başarılı → handler çalışır,
X-RateLimit-*header'ları eklenir.
Güvenlik prensipleri
- Secret asla ağda gitmez. Sadece imza gider.
- Timestamp + nonce zorunlu — sızdırılan tek bir istek bile replay edilemez.
- Sabit zamanlı karşılaştırma — server-side
crypto.timingSafeEqual. - Saat senkronu — sunucunuzun NTP ile senkronize olduğundan emin olun (5 dk pencere).
- Secret'ı git'e koymayın — env veya secret manager kullanın.
- Production ≠ test —
tmk_live_…üretim datası,tmk_test_…sandbox.
Sonraki: 02 · İmza örnekleri.