Signature Failed di Payment Gateway DOKU: Windows Adalah Maut!
Pernah ngalamin masalah seperti ini? 👇
Signature Failed di Payment Gateway DOKU: Windows Adalah Maut!
Photo by Markus Spiske on Unsplash
Pernah ngalamin masalah seperti ini? 👇
Invalid Signature DOKU Notification.
{
"Request Signature": "HMACSHA256=4Sh+EIRwnC43DEcTPmXuf+1NZl1JjN24y5lZXhmLO0A=",
"Response Signature": "HMACSHA256=X9MGQgSAhluTtZ7/kVIgV5iL4otu8hoKh699e/O+czo="
}
Inti Tulisan
- Ini adalah pengalaman pribadi saya, bisa dialami oleh orang lain bisa juga tidak, namun tulisan ini bisa dijadikan bahan referensi serta dokumentasi saya pribadi utamannya.
- Request Signature: Ini adalah HMAC-SHA256 base64 dari semua component DOKU menggunakan Secret Key. Lebih detail bisa cek dokumentasi DOKU.
- Response Signature: Ini adalah hasil yang sama seperti request tetapi didapatkan dari hasil response dari DOKU sebagai header ketika status transaksi berubah (sebagai HTTP Notification).
- Request dan Response harus sama, ini sebagai pengecekan dari kedua sisi dengan Secret Key yang dimiliki maka menghasilkan HMAC-SHA256 base64 yang sama (Karena perbedaan 1 karakter saja mempengaruhinya).
- Explorasi ini dilakukan menggunakan Framework Laravel.
Contoh Code
Ini adalah contoh sederhana penggunaan DOKU 👇
// Initial component header
$requestBody = $request->getContent();
$clientId = $request->header('Client-Id');
$requestId = $request->header('Request-Id');
$requestTimestamp = $request->header('Request-Timestamp');
$targetUrl = '/ini/url/webhook';
$digest = $this->generateDigest($requestBody);
// Generate request signature
$reqSignature = $this->generateSignature(
$clientId,
$requestId,
$requestTimestamp,
$targetUrl,
$digest
);
// Response signature
$resSignature = $request->header('Signature');
// Check req and res is match
$isMatchSignature = $reqSignature === $resSignature
public function generateSignature($clientId, $requestId, $requestTimestamp, $requestTarget, $digest)
{
$componentSignature = "Client-Id:" . $clientId . "\n";
$componentSignature .= "Request-Id:" . $requestId . "\n";
$componentSignature .= "Request-Timestamp:" . $requestTimestamp . "\n";
$componentSignature .= "Request-Target:" . $requestTarget . "\n";
$componentSignature .= "Digest:" . $digest;
$signature = base64_encode(hash_hmac('sha256', $componentSignature, $this->secretKey, true));
return 'HMACSHA256=' . $signature;
}
public function generateDigest($jsonBody)
{
return base64_encode(hash('sha256', $jsonBody, true));
}
Penjelasan Singkat:
- Code di atas adalah cara untuk mencocok an signature berdasarkan dokumentasi DOKU, dimana ada Client-Id, Request-Id, Request-Timestamp, Request-Target, dan Digest.
- Digest adalah body response yang kemudian di hash.
- Lebih lengkap bisa cek dokumentasi DOKU.
Lalu Dimana Masalahnya?
Masalah yang saya alami adalah signature tidak pernah sama walaupun dengan intruksi yang ada di dokumentasi DOKU.
Penelusuran
Setelah mengalami keanehan ini, saya coba dari berbagai referensi, berdiskusi juga dengan rekan kerja, sampai bertanya di forum, namun hasilnya belum solve pada saat itu.
Sampai pada titik benar benar eksplorasi bareng lebih dalam bersama rekan kerja yang kebetulan pada saat itu saya menggunakan Windows dan rekan kerja saya menggunakan Linux.
Mulai lah dicoba pada simple project yang ada di device rekan kerja saya, dengan code yang serupa, sama sama base on documentation dan ANEHNYA BERHASIL. Seketika saya merasa SKILL ISSUE haha. Yaa walaupun memang masih pemula sebenernya, bu’t it’s ok!
Tapi Tunggu Sebentar!
Setelah rekan saya berhasil mendapatkan signature yang serasi antara request signature dan response signature yang sama, bahkan dengan payload yang sama dengan yang saya gunakan, mulailah penasaran dengan mengirimkan code pembuatan signature nya lalu di jalankan di device saya. Hasilnya? Ya, GAGAL!
Aneh tapi memang itu yang terjadi, dan mulailah dengan mengirimkan PROJECTNYA 😆. Hasilnya? Ya, GAGAL!
Bahkan “seingat saya tahap ini dicoba” dengan mencoba mengirimkan code yang saya buat, dan di jalankan di device sana Ternyata Berhasil, artinya masalah bukan pada code yang dibuat, tapi mungkin saja dari OS yang digunakan.
Ini diperkuat dengan rekan kerja saya membuka projectnya sendiri tersebut tapi dengan windows nya, ini case dual boot jadi bisa dicoba dengan windows yang ada di device tersebut.
Aneh sih, tapi itulah yang terjadi.
Oh iya, saya melakukan eksplorasi ini bersama rekan kerja saya yaitu mas Harithya.
Lalu Solusinya Gimana?
Setelah mengetahui keanehan itu, akhirnya saya minta dikirim hasil dari request body yang dia dapat dan harusnya sama karena menggunakan payload yang sama persis.
Request body yang didapat oleh rekan kerja saya nampak normal dan tidak ditemukan keanehan.
Lalu saya cek juga request body yang saya dapat dan benar saja hasilnya beda. Beda disini antara request body saya dan rekan saya ya, padahal dengan payload yang sama (body yang disimpan di postman adalah body yang sama).
Hal yang terlihat menjadi berbeda:
- Pertama adalah dari panjang karakter, hasil print_r dari $requestBody di atas antara yang saya coba dan rekan saya coba itu berbeda cukup jauh, bukan sekedar 1 atau 2 karakter saja. Dan inilah yang menjadi pengaruh kenapa saya tidak bisa mendapatkan signature yang sama.
- Kedua adalah dari hasil dd, ternyata di divice saya terlihat jelas pada setiap new line $requestBody tersebut selain ada \n ternyata ada tambahan lain yaitu \r. Dan itulah sumber masalah yang saya alami.
Ini tampak normal 👇
"""
{\n
"service": {\n
"id": "VIRTUAL_ACCOUNT"\n
},\n
"acquirer": {\n
"id": "BANK_SYARIAH_MANDIRI"\n
},\n
.................
Dan ini tampak kurang normal 👇
"""
{\r\n
"service": {\r\n
"id": "VIRTUAL_ACCOUNT"\r\n
},\r\n
"acquirer": {\r\n
"id": "BANK_SYARIAH_MANDIRI"\r\n
},\r\n
.................
Puncak Solusi
Akhirnya yang saya lakukan adalah dengan mereplace /r tersebut dengan string kosong pada saat pembuatan atau generate Digest nya.
Nampak seperti ini 👇
public function generateDigest($jsonBody)
{
$cleanBody = str_replace("\r", "", $jsonBody);
return base64_encode(hash('sha256', $cleanBody, true));
}
Kesimpulan
Itulah keanehan yang saya alami dan perlu saya garis bawahi, saya tidak tau ini pasti kejadian di semua windows atau tidak, yang pasti sudah dicoba dengan dua device dan dicoba dengan satu device dengan dua OS yang berbeda dan kesimpulannya seperti itu.
Windows menghasilkan /r bersamaan dengan /n.
Semoga pengalaman ini bisa membantu pembaca yang mungkin mengalami masalah yang sama.
Titip LikedIn:
메타데이터
- post_id
- ddec3cd990c3
- slug
- signature-failed-di-payment-gateway-doku-windows-adalah-maut-ddec3cd990c3
- url
- https://medium.com/@fikriwado/signature-failed-di-payment-gateway-doku-windows-adalah-maut-ddec3cd990c3
- canonical_url
- https://medium.com/@fikriwado/signature-failed-di-payment-gateway-doku-windows-adalah-maut-ddec3cd990c3
- author_url
- https://medium.com/@fikriwado
- status
- ok
- fetched_at
- 2026-07-23 00:52:37