Kimlik Doğrulama
PF Gateway API'ye yapılan isteklerde HMAC tabanlı kimlik doğrulama ve imza oluşturma rehberi.
PF Gateway API, her istekte HMAC-SHA256 tabanlı kimlik doğrulama kullanır. Bu sayede isteklerin yetkili bir kaynaktan geldiği ve iletim sırasında değiştirilmediği doğrulanır.
Gerekli Bilgiler
Entegrasyona başlamadan önce aşağıdaki bilgilere sahip olmanız gerekir:
PublicKey (API Key)
Üye işyerine ait açık anahtar. Her istekte header veya form field olarak gönderilir.
SecretKey (API Secret)
Üye işyerine ait gizli anahtar (Base64 encoded). Yalnızca imza oluşturmada kullanılır, asla istekte gönderilmez.
MerchantNumber
Üye işyeri numarası. Her istekte header veya form field olarak gönderilir.
İmza Oluşturma Algoritması
İmza 2 aşamalı HMAC-SHA256 ile oluşturulur. Her iki aşamada da key olarak SecretKey Base64 decode edilerek kullanılır.
SecretKey size Base64 encoded olarak verilir. HMAC hesaplamalarında bu değeri önce Base64 decode edip byte dizisine çevirmeniz gerekir. Direkt string olarak kullanmayın.
Algoritma Özeti
Adım 1 — SecurityData hesapla:
message = PublicKey + Nonce
securityData = HMAC-SHA256(message, Base64Decode(SecretKey)) → Base64
Adım 2 — Signature hesapla:
payload = SecretKey + ConversationId + Nonce + SecurityData
signature = HMAC-SHA256(payload, Base64Decode(SecretKey)) → Base64Adım Adım İmza Oluşturma
1. Nonce ve ConversationId Oluşturun
Her istek için benzersiz bir Nonce (milisaniye cinsinden zaman damgası) ve ConversationId oluşturun.
string nonce = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString();
string conversationId = Guid.NewGuid().ToString("N")[..8];const nonce = Date.now().toString();
const conversationId = crypto.randomUUID().slice(0, 8);import time
import uuid
nonce = str(int(time.time() * 1000))
conversation_id = uuid.uuid4().hex[:8]$nonce = (string) round(microtime(true) * 1000);
$conversationId = substr(str_replace('-', '', (string) \Ramsey\Uuid\Uuid::uuid4()), 0, 8);
// veya UUID kütüphanesi kullanmadan:
// $conversationId = substr(bin2hex(random_bytes(4)), 0, 8);2. SecurityData Hesaplayın (1. HMAC)
PublicKey ve Nonce değerlerini birleştirip HMAC-SHA256 ile hash'leyin.
message = PublicKey + Nonce
securityData = HMAC-SHA256(message, key: Base64Decode(SecretKey)) → Base64byte[] secretKeyBytes = Convert.FromBase64String(secretKey);
string message = publicKey + nonce;
using var hmac = new HMACSHA256(secretKeyBytes);
string securityData = Convert.ToBase64String(
hmac.ComputeHash(Encoding.UTF8.GetBytes(message))
);const secretKeyBytes = Buffer.from(secretKey, 'base64');
const message = publicKey + nonce;
const securityData = createHmac('sha256', secretKeyBytes)
.update(message, 'utf8')
.digest('base64');secret_key_bytes = base64.b64decode(secret_key)
message = public_key + nonce
security_data = base64.b64encode(
hmac.new(secret_key_bytes, message.encode('utf-8'), hashlib.sha256).digest()
).decode('utf-8')$secretKeyBytes = base64_decode($secretKey);
$message = $publicKey . $nonce;
$securityData = base64_encode(
hash_hmac('sha256', $message, $secretKeyBytes, true)
);3. Signature Hesaplayın (2. HMAC)
SecretKey, ConversationId, Nonce ve bir önceki adımda hesapladığınız SecurityData değerlerini birleştirip tekrar HMAC-SHA256 ile hash'leyin.
payload = SecretKey + ConversationId + Nonce + SecurityData
signature = HMAC-SHA256(payload, key: Base64Decode(SecretKey)) → Base64string payload = secretKey + conversationId + nonce + securityData;
using var hmac = new HMACSHA256(secretKeyBytes);
string signature = Convert.ToBase64String(
hmac.ComputeHash(Encoding.UTF8.GetBytes(payload))
);const payload = secretKey + conversationId + nonce + securityData;
const signature = createHmac('sha256', secretKeyBytes)
.update(payload, 'utf8')
.digest('base64');payload = secret_key + conversation_id + nonce + security_data
signature = base64.b64encode(
hmac.new(secret_key_bytes, payload.encode('utf-8'), hashlib.sha256).digest()
).decode('utf-8')$payload = $secretKey . $conversationId . $nonce . $securityData;
$signature = base64_encode(
hash_hmac('sha256', $payload, $secretKeyBytes, true)
);Tam Kod Örneği
Yukarıdaki adımların hepsini birleştiren, kopyala-yapıştır kullanıma hazır fonksiyonlar:
using System;
using System.Security.Cryptography;
using System.Text;
public sealed class PfSignatureService
{
private readonly byte[] _secretKeyBytes;
private readonly string _publicKey;
private readonly string _secretKey;
public PfSignatureService(string publicKey, string secretKey)
{
_publicKey = publicKey;
_secretKey = secretKey;
_secretKeyBytes = Convert.FromBase64String(secretKey);
}
public SignatureResult CreateSignature(string? conversationId = null)
{
string nonce = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString();
conversationId ??= Guid.NewGuid().ToString("N")[..8];
// 1. SecurityData
string securityData = ComputeHmac(_publicKey + nonce);
// 2. Signature
string signature = ComputeHmac(_secretKey + conversationId + nonce + securityData);
return new SignatureResult(nonce, signature, conversationId);
}
private string ComputeHmac(string data)
{
using var hmac = new HMACSHA256(_secretKeyBytes);
return Convert.ToBase64String(
hmac.ComputeHash(Encoding.UTF8.GetBytes(data))
);
}
}
public record SignatureResult(string Nonce, string Signature, string ConversationId);
// Kullanım:
// var service = new PfSignatureService("YOUR_PUBLIC_KEY", "YOUR_SECRET_KEY");
// var result = service.CreateSignature();
// Console.WriteLine(result.Signature);import { createHmac } from 'node:crypto';
class PfSignatureService {
#secretKeyBytes;
#publicKey;
#secretKey;
constructor(publicKey, secretKey) {
this.#publicKey = publicKey;
this.#secretKey = secretKey;
this.#secretKeyBytes = Buffer.from(secretKey, 'base64');
}
createSignature(conversationId) {
const nonce = Date.now().toString();
conversationId ??= crypto.randomUUID().slice(0, 8);
// 1. SecurityData
const securityData = this.#computeHmac(this.#publicKey + nonce);
// 2. Signature
const signature = this.#computeHmac(
this.#secretKey + conversationId + nonce + securityData
);
return { nonce, signature, conversationId };
}
#computeHmac(data) {
return createHmac('sha256', this.#secretKeyBytes)
.update(data, 'utf8')
.digest('base64');
}
}
// Kullanım:
// const service = new PfSignatureService('YOUR_PUBLIC_KEY', 'YOUR_SECRET_KEY');
// const { nonce, signature, conversationId } = service.createSignature();import hmac
import hashlib
import base64
import time
import uuid
from dataclasses import dataclass
@dataclass(frozen=True)
class SignatureResult:
nonce: str
signature: str
conversation_id: str
class PfSignatureService:
def __init__(self, public_key: str, secret_key: str):
self._public_key = public_key
self._secret_key = secret_key
self._secret_key_bytes = base64.b64decode(secret_key)
def create_signature(self, conversation_id: str | None = None) -> SignatureResult:
nonce = str(int(time.time() * 1000))
conversation_id = conversation_id or uuid.uuid4().hex[:8]
# 1. SecurityData
security_data = self._compute_hmac(self._public_key + nonce)
# 2. Signature
signature = self._compute_hmac(
self._secret_key + conversation_id + nonce + security_data
)
return SignatureResult(nonce, signature, conversation_id)
def _compute_hmac(self, data: str) -> str:
return base64.b64encode(
hmac.new(self._secret_key_bytes, data.encode('utf-8'), hashlib.sha256).digest()
).decode('utf-8')
# Kullanım:
# service = PfSignatureService('YOUR_PUBLIC_KEY', 'YOUR_SECRET_KEY')
# result = service.create_signature()
# print(result.signature)<?php
class PfSignatureService
{
private string $publicKey;
private string $secretKey;
private string $secretKeyBytes;
public function __construct(string $publicKey, string $secretKey)
{
$this->publicKey = $publicKey;
$this->secretKey = $secretKey;
$this->secretKeyBytes = base64_decode($secretKey);
}
public function createSignature(?string $conversationId = null): array
{
$nonce = (string) round(microtime(true) * 1000);
$conversationId = $conversationId ?? substr(bin2hex(random_bytes(4)), 0, 8);
// 1. SecurityData
$securityData = $this->computeHmac($this->publicKey . $nonce);
// 2. Signature
$signature = $this->computeHmac(
$this->secretKey . $conversationId . $nonce . $securityData
);
return [
'nonce' => $nonce,
'signature' => $signature,
'conversationId' => $conversationId,
];
}
private function computeHmac(string $data): string
{
return base64_encode(
hash_hmac('sha256', $data, $this->secretKeyBytes, true)
);
}
}
// Kullanım:
// $service = new PfSignatureService('YOUR_PUBLIC_KEY', 'YOUR_SECRET_KEY');
// $result = $service->createSignature();
// echo $result['signature'];İstek Header'ları
Oluşturduğunuz değerleri HTTP header'larına ekleyin:
| Header | Açıklama |
|---|---|
PublicKey | Üye işyerine ait açık anahtar |
Nonce | Her istek için benzersiz zaman damgası (milisaniye) |
Signature | 2 aşamalı HMAC-SHA256 ile oluşturulan imza (Base64) |
ConversationId | İstek takip numarası |
MerchantNumber | Üye işyeri numarası |
ClientIpAddress | İşlem yapan kullanıcının IP adresi |
POST /v1/Payments/provision HTTP/1.1
Content-Type: application/json
PublicKey: your-public-key
Nonce: 1770882490683
Signature: cQli2lp3XcVgcamhxw793sFbPwsnPZ8JJOTH...
ConversationId: conv-123456
MerchantNumber: 000001
ClientIpAddress: 192.168.1.1Base URL: https://testpfapi.rubikpara.com
Bazı endpoint'lerde (ör. /v1/Tokens, /v1/ThreeDS/init3ds) bu değerler header yerine form field olarak gönderilir. Her endpoint'in dokümantasyonunu kontrol edin.
Test Ortamı
Geliştirme sırasında imza oluşturmayı kendi sunucunuzda yapmak yerine, Test İmzası Oluştur endpoint'ini kullanabilirsiniz.
Bu endpoint yalnızca test ortamında kullanılabilir. Prodüksiyon ortamında imzayı yukarıdaki algoritma ile kendi sunucunuzda oluşturmalısınız.
Test İmzası Oluşturma
POST /v1/Signatures/generate-test-signature
Content-Type: application/json
{
"publicKey": "your-public-key",
"merchantNumber": "000001",
"conversationId": "conv-123456"
}{
"publicKey": "your-public-key",
"nonce": "1770629965755",
"signature": "dZspDJX18zdC1MnX4d0mhIX0F3IitK0+DQb5ZyxqR3U=",
"conversationId": "conv-123456",
"merchantId": "e7051f0d-0e16-406f-a518-310a4b92dae4"
}Dönen Değerleri Kullanma
Yanıttaki değerleri doğrudan hedef API isteğine aktarın:
| Yanıt Alanı | Hedef Parametre | Açıklama |
|---|---|---|
publicKey | PublicKey | Açık anahtar |
nonce | Nonce | Benzersiz istek kimliği |
signature | Signature | Hesaplanmış HMAC imzası |
conversationId | ConversationId | İstek takip numarası |
Her API isteği için yeni bir imza oluşturmanız gerekir. Aynı Nonce ve Signature değerleri tekrar kullanılamaz.