Başlarken
Kimlik Doğrulama

Kimlik Doğrulama

Lunixi API'sinde statik bir API anahtarını doğrudan Authorization başlığına koymazsınız. Uzun ömürlü secret, Ed25519 özel anahtarınızdır ve o hiçbir zaman telde gitmez. Onunla imzalayıp kısa ömürlü bir erişim token'ı basar, çağrılarınızı o token'la yaparsınız.

Ed25519 özel anahtar  ──imzala──▶  POST /api/v1/auth/token  ──▶  at_live_…  (5 dk)
                                                                     │
                                              Authorization: Bearer at_live_…

Neden böyle? Statik bir anahtar sızarsa saldırgan onu süresiz kullanır. Burada sızabilecek olan token'ın ömrü dakikalarla sınırlıdır; özel anahtar ise sunucunuzdan hiç çıkmaz. Para hareketi uçlarında bunun üstüne bir imza katmanı daha vardır (aşağıda Step-Up).

Adım 1 — Token basın

POST /api/v1/auth/token

Bu istek Bearer token istemez; imzalıdır.

BaşlıkDeğer
X-Key-IdKayıtlı Ed25519 public anahtarının kimliği (kid)
X-DateISO 8601 zaman damgası — sunucu saatine göre ±5 dakika içinde olmalı
X-Nonceİstek başına benzersiz değer (UUID) — tek kullanımlık
DigestHam gövdenin SHA-256 özeti (Base64) — gövde varsa zorunlu
X-SignatureKanonik dizenin Base64 Ed25519 imzası

Kanonik dize

İmzaladığınız metin şudur — satırlar \n ile birleşir:

METHOD
URL
X-Date:<değer>
X-Nonce:<değer>
Digest:<değer>        ← YALNIZ gövde varsa

METHOD büyük harfe çevrilir. URL isteğin yolu ve sorgu dizesidir.

🚫

Gövdesiz isteklerde Digest: satırı kanonik dizeye HİÇ EKLENMEZ. Boş değerle eklerseniz (Digest:) imza tutmaz. Token basma çağrısının gövdesi yoktur ⇒ kanonik dize dört satırdır.

⚠️

Sıra ve büyük/küçük harf birebir olmalı. Satırları farklı sıralar veya başlık adlarını farklı yazarsanız imza tutmaz ve 401 alırsınız.

Digest başlığının biçimi

Gövdeli isteklerde başlık SHA-256= önekli olmalıdır:

Digest: SHA-256=<gövdenin sha256 özeti, base64>

Önek yoksa ya da base64 dolgusu (=) kırpılmışsa doğrulama başarısız olur.

İmzalama algoritması

Ed25519'da hash algoritması belirtilmez. Node.js'te:

crypto.sign(null, Buffer.from(canonical), privateKey).toString('base64')

⚠️ İlk argüman null olmalı. 'sha256' yazarsanız imza üretilir ama sunucuda doğrulanmaz.

Hata kodları

KodAnlamı
INVALID_DATEX-Date 5 dakikalık pencerenin dışında
DIGEST_MISSINGGövde var ama Digest başlığı yok
INVALID_DIGESTGövde özeti Digest ile uyuşmuyor
401İmza geçersiz veya zaman damgası eski
403IP izinli listede değil, ya da merchant askıya alınmış

Adım 2 — Yanıt

{
  "access_token": "at_live_5f3e2b1a...",
  "token_type": "Bearer",
  "expires_in": 300,
  "expires_at": 1710000000,
  "refresh_expires_in": 43200,
  "refresh_expires_at": 1710043200,
  "session_id": "authsess_3e46a2f3-1f02-42a9-9c4d-ef12b8f6f2d1"
}
AlanAnlamı
access_tokenOpak token — at_{ortam}_ önekli. İçinde çözülecek bir bilgi yoktur, ayrıştırmaya çalışmayın
expires_inSaniye cinsinden ömür (tipik 300 = 5 dakika)
refresh_expires_inYenileme penceresi (tipik 43200 = 12 saat)
session_idOturum kimliği — destek talebinde ve log korelasyonunda kullanılır

Önek ortamı taşır: at_live_… canlı, at_test_… test. Token'ın hangi ortama ait olduğunu ön ekinden çıkarsamayın — hangi anahtarla bastıysanız o ortamdasınız.

Adım 3 — Çağrılarınızda kullanın

curl "https://api-gateway.lunixi.com/api/v1/payments?page=1&limit=20" \
  -H "Authorization: Bearer at_live_5f3e2b1a..."

Kimliği doğrulanan taraf (merchantId) token'dan okunur, istek gövdesinden asla — gövde başka bir kiracıyı taklit edemez.

⚠️

Token 5 dakikada bir yenilenir. Her çağrıda yeni token basmayın; token'ı süresi dolana kadar önbellekte tutun ve expires_at'e bakarak yenileyin. POST /auth/token her istekte çağrılırsa gereksiz yük ve gecikme üretirsiniz.

Step-Up — para hareketi uçları

Para hareketi yapan uçlar (ödeme intent'i oluşturma, direct çekim, capture, void, refund, marketplace ödemeleri) hem geçerli bir Bearer token hem de o isteğin üzerine ayrı bir Ed25519 imzası ister.

Authorization: Bearer at_live_…        ← token
X-Key-Id / X-Date / X-Nonce / Digest / X-Signature   ← isteğin kendi imzası
🚫

Amaç şudur: token'ınız çalınsa bile saldırgan para hareket ettiremez — özel imza anahtarınız olmadan Step-Up isteğini imzalayamaz. Bu yüzden özel anahtarı token'ı bastığınız yerden ayrı tutmak anlamlıdır.

İmza şeması Adım 1'dekiyle aynıdır: aynı kanonik dize, aynı başlıklar, aynı ±5 dakika penceresi, aynı tek-kullanımlık nonce.

Anahtar yönetimi

Ed25519 anahtar çiftini üretin

Özel anahtar sizin sunucunuzda kalır. Bize yalnız public anahtarı verirsiniz.

Public anahtarı kaydedin

Panelden kaydedersiniz; karşılığında bir kid (key id) alırsınız. X-Key-Id başlığında bu değeri gönderirsiniz.

Döndürme

Yeni bir anahtar çifti üretin, public anahtarı kaydedin, servislerinizi yeni kid ile güncelleyin, sonra eskisini iptal edin. Eski kid iptal edildiği anda o anahtarla imzalanan istekler 401 almaya başlar — yenisini yayına almadan eskisini iptal etmeyin.

⚠️

Özel imza anahtarını tarayıcıya, mobil uygulamaya veya herkese açık bir depoya asla koymayın. Sızarsa panelden kid'i iptal edin ve yeni çift üretin.

IP izin listesi

API anahtarınıza bir IP izin listesi tanımlayabilirsiniz; liste doluysa anahtarla imzalanan istekler yalnız bu adreslerden kabul edilir. Listeye tek tek IP adresleri (IPv4 ya da IPv6) yazılır; adres aralıkları (CIDR) kabul edilmez, en çok 50 adres eklenebilir.

Bazı yetkiler yalnız IP izin listesi olan anahtara verilir. Banka hesabınızdan para transferi ve döviz işlemi yapan bank-connect:transfer yetkisi bunlardandır: liste boşken bu yetkiyi anahtara eklemeye çalışırsanız işlem 400 organization.api_key.scope_requires_ip_allowlist ile reddedilir (details.scopes hangi yetkinin liste istediğini verir). Bu yetkiyle yapılan isteklerde doğrulama kodu olmadığı için onay; anahtar yetkisi, istek imzası ve isteğin geldiği IP adresidir. → Banka Hesapları › IP izin listesi

⚠️

Sunucunuzun dışarıya çıktığı adresi yazın; yük dengeleyici, NAT ya da yeni sunucu bu adresi değiştirebilir. Adres değiştiğinde listeyi güncellemezseniz istekler 403 alır.

Ortam değişkenleri

Saklanacak şey token değil, özel anahtar ve kid'dir:

# .env
LUNIXI_KEY_ID=kid_...
LUNIXI_PRIVATE_KEY_PATH=/secure/lunixi-ed25519.pem

Token'ı uygulamanız çalışırken basar ve bellekte tutar; ortam değişkenine yazılacak bir şey değildir.

Sonraki adımlar