Epinpark

HMAC Kimlik Doğrulama

Tüm Epinpark Integration API istekleri HMAC-SHA256 ile imzalanır. Bu yöntem replay saldırılarına karşı zaman damgası ve nonce ile korunur, body değişiklik tespiti için body hash'i imzaya dahildir.

Zorunlu header'lar

Her istekte dört header olmak zorunda:

HeaderAçıklama
X-Api-KeySatıcının açık (public) API key'i
X-Timestampİstek anının Unix saniye değeri (UTC). 300 saniyelik tolerans penceresi
X-Nonceİsteğe özgü rastgele string (önerilen: 16 byte hex). Replay korumasıdır
X-SignatureAşağıdaki canonical string'in HMAC-SHA256 imzasının base64 encode hâli

Canonical message formatı

İmza, aşağıdaki kanonik mesajdan üretilir:

METHOD\nPATH\nSHA256(body)\ntimestamp\nnonce

Her alanın açıklaması:

  • METHOD: HTTP metodu, uppercase (GET, POST, PATCH, DELETE, HEAD)
  • PATH: Path + query string. Örn: /v1/orders?page=1&pageSize=10
  • SHA256(body): Request body'nin hex-encoded SHA-256 hash'i. Body yoksa boş string'in SHA-256'sı: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
  • timestamp: X-Timestamp header'ı ile birebir aynı değer
  • nonce: X-Nonce header'ı ile birebir aynı değer

Alanlar \n (LF, 0x0A) ile ayrılır. CRLF kullanmayın.

Doğru body hash'i kritik

Body'yi göndermeden önce aynen hash'leyin. JSON.stringify çağrısının ardından whitespace eklemeyin, alan sırasını değiştirmeyin, transit'te trim olmasın. Aksi takdirde server-side hash farklı çıkar ve imza doğrulanmaz.

İmza üretme örneği

Sunucu tarafı doğrulama akışı

Server, aldığı isteği şu adımlarla doğrular:

  1. Dört header'ın varlığı kontrol edilir → eksikse 401 Required HMAC headers are missing
  2. X-Timestamp parse edilir, 300 saniyelik pencere dışındaysa → 401 Timestamp is outside of acceptable window
  3. Request body buffer'lanır, SHA256(body) hesaplanır
  4. Canonical message yeniden oluşturulur
  5. X-Api-Key ile satıcı bulunur, secret decrypt edilir
  6. HMAC-SHA256(secret, canonical) ile imza yeniden hesaplanır
  7. Gönderilen imza ile karşılaştırılır (timing-safe karşılaştırma)
  8. Başarılıysa sellerId, apiKeyId, scopes claim olarak yüklenir

Yaygın hatalar

SorunÇözüm
Saatim 300 sn dışındaSunucunuzu NTP ile senkronize edin
Body hash farklı çıkıyorJSON.stringify ile imzaladığınız aynı string'i gönderin
Path yanlışQuery string dahil olmalı, fragment (#...) olmamalı
CRLF kullanıyorumSadece \n (LF, 0x0A) kullanın
URL encodingPath'i encode etmeyin, URL'de göründüğü gibi imzalayın
Nonce tekrar kullanılıyorHer istek için yeni nonce üretin

Replay koruması

Aynı nonce aynı timestamp ile kısa bir süre içinde tekrar gönderilse bile, 300 saniyelik pencere geçtikten sonra istek otomatik olarak reddedilir. Yine de en iyi pratiğe her istekte yeni bir nonce üretmektir.

Secret'ı korumak

  • Asla git repo'ya commit etmeyin (env değişkeni veya secret manager kullanın)
  • Log'larda asla yazdırmayın
    1. parti monitoring araçlarına göndermeyin
  • Frontend kodunda kesinlikle kullanmayın — bu API server-to-server'dır
  • Düzenli aralıklarla rotate edin