# Sample Code

Here is the sample code to generate the `Signature`:

{% hint style="info" %}
**SAMPLE ONLY!**

This is just a sample code to demonstrate how to generate the Signature on different programming language. Kindly adjust the code to suited your project's structure.
{% endhint %}

{% tabs %}
{% tab title="Java" %}

<pre class="language-java"><code class="lang-java"><strong>import javax.crypto.Mac;
</strong>import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
 
public class Signature {
 
    public static final String CLIENT_ID = "Client-Id";
    public static final String REQUEST_ID = "Request-Id";
    public static final String REQUEST_TIMESTAMP = "Request-Timestamp";
    public static final String REQUEST_TARGET = "Request-Target";
    public static final String DIGEST = "Digest";
    public static final String COLON_SYMBOL = ":";
    public static final String NEW_LINE = "\n";
    
    // Generate Digest
    public static String generateDigest(String requestBody) throws NoSuchAlgorithmException {
        MessageDigest md = MessageDigest.getInstance("SHA-256");
        md.update(requestBody.getBytes(StandardCharsets.UTF_8));
        byte[] digest = md.digest();
        return Base64.getEncoder().encodeToString(digest);
    }
    
    private static String generateSignature(String clientId, String requestId, String requestTimestamp, String requestTarget, String digest, String secret) throws InvalidKeyException, NoSuchAlgorithmException {
        // Prepare Signature Component
        System.out.println("----- Component Signature -----");
        StringBuilder component = new StringBuilder();
        component.append(CLIENT_ID).append(COLON_SYMBOL).append(clientId);
        component.append(NEW_LINE);
        component.append(REQUEST_ID).append(COLON_SYMBOL).append(requestId);
        component.append(NEW_LINE);
        component.append(REQUEST_TIMESTAMP).append(COLON_SYMBOL).append(requestTimestamp);
        component.append(NEW_LINE);
        component.append(REQUEST_TARGET).append(COLON_SYMBOL).append(requestTarget);
        // If body not send when access API with HTTP method GET/DELETE
        if(digest != null &#x26;&#x26; !digest.isEmpty()) {
            component.append(NEW_LINE);
            component.append(DIGEST).append(COLON_SYMBOL).append(digest);
        }

        System.out.println(component.toString());
        System.out.println();
 
        // Calculate HMAC-SHA256 base64 from all the components above
        byte[] decodedKey = secret.getBytes();
        SecretKey originalKey = new SecretKeySpec(decodedKey, 0, decodedKey.length, "HmacSHA256");
        Mac hmacSha256 = Mac.getInstance("HmacSHA256");
        hmacSha256.init(originalKey);
        hmacSha256.update(component.toString().getBytes());
        byte[] HmacSha256DigestBytes = hmacSha256.doFinal();
        String signature = Base64.getEncoder().encodeToString(HmacSha256DigestBytes);
        // Prepend encoded result with algorithm info HMACSHA256=
        return "HMACSHA256="+signature;
    }
    
    // Sample of Usage
    public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeyException {
         String jsonBody = new JSONObject()
                          .put("order", new JSONObject()
                            .put("invoice_number", "INV-20210124-0001")
                            .put("amount", 15000)
                          )
                          .put("virtual_account_info", new JSONObject()
                            .put("expired_time", 60)
                            .put("amount", 15000)
                          )
                          .toString();
 
        // Generate Digest from JSON Body, For HTTP Method GET/DELETE don't need generate Digest
        System.out.println("----- Digest -----");
        String digest = generateDigest(jsonBody);
        System.out.println(digest);
        System.out.println();
 
        // Generate Signature
        String headerSignature = generateSignature(
                "yourClientId",
                "yourRequestId",
                "2020-10-21T03:38:28Z",
                "/request-target/goes-here", // For merchant request to DOKU, use DOKU path here. For HTTP Notification, use merchant path here
                digest, // Set empty string for this argumentes if HTTP Method is GET/DELETE
                "secret-key-from-DOKU-back-office");
 
        System.out.println("----- Header Signature -----");
        System.out.println(headerSignature);
    }
}
</code></pre>

{% endtab %}

{% tab title="PHP" %}

```php
<?php

$clientId = "yourClientId";
$requestId = "yourRequestId";
$requestDate = "2020-10-21T03:38:28Z";
$targetPath = "/request-target/goes-here"; // For merchant request to Jokul, use Jokul path here. For HTTP Notification, use merchant path here
$secretKey = "secret-key-from-jokul-back-office";
$requestBody = array (
    'order' => array (
        'amount' => 15000,
        'invoice_number' => 'INV-20210124-0001',
    ),
    'virtual_account_info' => array (
        'expired_time' => 60,
        'reusable_status' => false,
        'info1' => 'Merchant Demo Store',
    ),
    'customer' => array (
        'name' => 'Taufik Ismail',
        'email' => 'taufik@example.com',
    ),
);

// Generate Digest
$digestValue = base64_encode(hash('sha256', json_encode($requestBody), true));
echo "Digest: " . $digestValue;
echo "\r\n\n";

// Prepare Signature Component
$componentSignature = "Client-Id:" . $clientId . "\n" . 
                      "Request-Id:" . $requestId . "\n" .
                      "Request-Timestamp:" . $requestDate . "\n" . 
                      "Request-Target:" . $targetPath . "\n" .
                      "Digest:" . $digestValue;
echo "Component Signature: \n" . $componentSignature;
echo "\r\n\n";
 
// Calculate HMAC-SHA256 base64 from all the components above
$signature = base64_encode(hash_hmac('sha256', $componentSignature, $secretKey, true));
echo "Signature: " . $signature;
echo "\r\n\n";

// Sample of Usage
$headerSignature =  "Client-Id:" . $clientId ."\n". 
                    "Request-Id:" . $requestId . "\n".
                    "Request-Timestamp:" . $requestDate ."\n".
                    // Prepend encoded result with algorithm info HMACSHA256=
                    "Signature:" . "HMACSHA256=" . $signature;
echo "your header request look like: \n".$headerSignature;
echo "\r\n\n";

```

{% endtab %}

{% tab title="Python" %}

```python
import hashlib
import hmac
import base64

# Generate Digest
def generateDigest(jsonBody):  
    return base64.b64encode(hashlib.sha256(jsonBody.encode('utf-8')).digest()).decode("utf-8")

def generateSignature(clientId, requestId, requestTimestamp, requestTarget, digest, secret):
    # Prepare Signature Component
    print("----- Signature Component -----")
    componentSignature = "Client-Id:" + clientId
    componentSignature += "\n"
    componentSignature += "Request-Id:" + requestId
    componentSignature += "\n"
    componentSignature += "Request-Timestamp:" + requestTimestamp
    componentSignature += "\n"
    componentSignature += "Request-Target:" + requestTarget
    # If body not send when access API with HTTP method GET/DELETE
    if digest:
        componentSignature += "\n"
        componentSignature += "Digest:" + digest
     
    print(componentSignature)
    message = bytes(componentSignature, 'utf-8')
    secret = bytes(secret, 'utf-8')
 
    # Calculate HMAC-SHA256 base64 from all the components above
    signature = base64.b64encode(hmac.new(secret, message, digestmod=hashlib.sha256).digest()).decode("utf-8")

    # Prepend encoded result with algorithm info HMACSHA256=
    return "HMACSHA256="+signature 

# Sample of usage

# Generate Digest from JSON Body, For HTTP Method GET/DELETE don't need generate Digest
print("----- Digest -----")
jsonBody = '{\"order\":{\"invoice_number\":\"INV-20210124-0001\",\"amount\":150000},\"virtual_account_info\":{\"expired_time\":60,\"reusable_status\":false,\"info1\":\"Merchant Demo Store\"},\"customer\":{\"name\":\"Taufik Ismail\",\"email\":\"taufik@example.com\"}}'
digest = generateDigest(jsonBody)
print(digest)
print("")

# Generate Signature
headerSignature = generateSignature(
        "yourClientId",
        "yourRequestId",
        "2020-10-21T03:38:28Z",
        "/request-target/goes-here", # For merchant request to Jokul, use Jokul path here. For HTTP Notification, use merchant path here
        digest, # Set empty string for this argumentes if HTTP Method is GET/DELETE
        "secret-key-from-jokul-back-office")
print("----- Header Signature -----")
print(headerSignature)

```

{% endtab %}

{% tab title="Node.js" %}

```javascript
const crypto = require('crypto');
  
// Generate Digest
function generateDigest(jsonBody) {
    let jsonStringHash256 = crypto.createHash('sha256').update(jsonBody,"utf-8").digest();
    
    let bufferFromJsonStringHash256 = Buffer.from(jsonStringHash256);
    return bufferFromJsonStringHash256.toString('base64'); 
}
 
function generateSignature(clientId, requestId, requestTimestamp, requestTarget, digest, secret) {
    // Prepare Signature Component
    console.log("----- Component Signature -----")
    let componentSignature = "Client-Id:" + clientId;
    componentSignature += "\n";
    componentSignature += "Request-Id:" + requestId;
    componentSignature += "\n";
    componentSignature += "Request-Timestamp:" + requestTimestamp;
    componentSignature += "\n";
    componentSignature += "Request-Target:" + requestTarget;
    // If body not send when access API with HTTP method GET/DELETE
    if (digest) {
        componentSignature += "\n";
        componentSignature += "Digest:" + digest;
    }
 
    console.log(componentSignature.toString());
    console.log();

    // Calculate HMAC-SHA256 base64 from all the components above
    let hmac256Value = crypto.createHmac('sha256', secret)
                   .update(componentSignature.toString())
                   .digest();  
      
    let bufferFromHmac256Value = Buffer.from(hmac256Value);
    let signature = bufferFromHmac256Value.toString('base64');
    // Prepend encoded result with algorithm info HMACSHA256=
    return "HMACSHA256="+signature 
}
 
// Sample of Usage

// Generate Digest from JSON Body, For HTTP Method GET/DELETE don't need generate Digest
console.log("----- Digest -----");
let jsonBody = '{\"order\":{\"invoice_number\":\"INV-20210124-0001\",\"amount\":150000},\"virtual_account_info\":{\"expired_time\":60,\"reusable_status\":false,\"info1\":\"Merchant Demo Store\"},\"customer\":{\"name\":\"Taufik Ismail\",\"email\":\"taufik@example.com\"}}';
let digest = generateDigest(jsonBody);
console.log(digest);
console.log();
  
// Generate Header Signature
let headerSignature = generateSignature(
        "yourClientId",
        "yourRequestId",
        "2020-10-21T03:38:28Z",
        "/request-target/goes-here", // For merchant request to Jokul, use Jokul path here. For HTTP Notification, use merchant path here
        digest, // Set empty string for this argumentes if HTTP Method is GET/DELETE
        "secret-key-from-jokul-back-office")
console.log("----- Header Signature -----")
console.log(headerSignature)

```

{% endtab %}

{% tab title="Ruby" %}

<pre class="language-ruby"><code class="lang-ruby"><strong>require 'openssl'
</strong>require 'base64'
require 'digest'
 
# Generate Digest
def generateDigest(jsonBody)
    return Base64.encode64(Digest::SHA256.digest(jsonBody)).strip()
end
 
def generateSignature(clientId, requestId, requestTimestamp, requestTarget, digest, secret)
    # Prepare Signature Component
    puts "----- Component Signature -----"
    componentSignature = ("Client-Id:" + clientId")
    componentSignature.concat("\n")
    componentSignature.concat("Request-Id:" + requestId)
    componentSignature.concat("\n")
    componentSignature.concat("Request-Timestamp:" + requestTimestamp)
    componentSignature.concat("\n")
    componentSignature.concat("Request-Target:" + requestTarget)
    # If body not send when access API with HTTP method GET/DELETE
    unless digest.to_s.strip.empty?
        componentSignature.concat("\n")
        componentSignature.concat("Digest:" + digest)
    end
    puts componentSignature
    puts "\n"  

    # Calculate HMAC-SHA256 base64 from all the components above
    hash = OpenSSL::HMAC.digest("sha256", secret, componentSignature)
    signature = Base64.encode64(hash).strip()

    # Prepend encoded result with algorithm info HMACSHA256=
    return "HMACSHA256="+signature 
end
 
# Sample of Usage

# Generate Digest from JSON Body, For HTTP Method GET/DELETE don't need generate Digest
puts "----- Digest -----"
jsonBody = '{\"order\":{\"invoice_number\":\"INV-20210124-0001\",\"amount\":150000},\"virtual_account_info\":{\"expired_time\":60,\"reusable_status\":false,\"info1\":\"Merchant Demo Store\"},\"customer\":{\"name\":\"Taufik Ismail\",\"email\":\"taufik@example.com\"}}'
digest = generateDigest(jsonBody)
puts digest
puts "\n"
 
# Generate Header Signature
headerSignature = generateSignature(
        "yourClientId",
        "yourRequestId",
        "2020-10-21T03:38:28Z",
        "/request-target/goes-here", # For merchant request to Jokul, use Jokul path here. For HTTP Notification, use merchant path here
        digest, # Set empty string for this argumentes if HTTP Method is GET/DELETE
        "secret-key-from-jokul-back-office")
puts "----- Header Signature -----"
puts headerSignature

</code></pre>

{% endtab %}

{% tab title="GO" %}

```go
package main
 
import (
    "crypto/hmac"
    "crypto/sha256"
    "encoding/base64"
    "fmt"
    "strings"
)
 
const CLIENT_ID = "Client-Id"
const REQUEST_ID = "Request-Id"
const REQUEST_TIMESTAMP = "Request-Timestamp"
const REQUEST_TARGET = "Request-Target"
const DIGEST = "Digest"
const SYMBOL_COLON = ":"
 
// Generate Digest
func generateDigest(jsonBody string) string {
    converted := []byte(jsonBody)
    hasher := sha256.New()
    hasher.Write(converted)
    return (base64.StdEncoding.EncodeToString(hasher.Sum(nil)))
     
}

func generateSignature(clientId string, requestId string, requestTimestamp string, requestTarget string, digest string, secret string) string {
    // Prepare Signature Component
    fmt.Println("----- Component Signature -----")
    var componentSignature strings.Builder
    componentSignature.WriteString(CLIENT_ID + SYMBOL_COLON + clientId)
    componentSignature.WriteString("\n")
    componentSignature.WriteString(REQUEST_ID + SYMBOL_COLON + requestId)
    componentSignature.WriteString("\n")
    componentSignature.WriteString(REQUEST_TIMESTAMP + SYMBOL_COLON + requestTimestamp)
    componentSignature.WriteString("\n")
    componentSignature.WriteString(REQUEST_TARGET + SYMBOL_COLON + requestTarget) 
    componentSignature.WriteString("\n")
    componentSignature.WriteString(DIGEST + SYMBOL_COLON +digest) 
    // If body not send when access API with HTTP method GET/DELETE
    if len(digest) > 0  {
        componentSignature.WriteString("\n")
        componentSignature.WriteString(DIGEST + SYMBOL_COLON +digest)
    }
 
    fmt.Println(componentSignature.String())
    fmt.Println("")
 
    // Calculate HMAC-SHA256 base64 from all the components above
    key := []byte(secret)
    h := hmac.New(sha256.New, key)
    h.Write([]byte(componentSignature.String()))
    signature := base64.StdEncoding.EncodeToString(h.Sum(nil))
    // Prepend encoded result with algorithm info HMACSHA256=
    return "HMACSHA256="+signature
}

// Sample of Usage
func main() {
  
    // Genreate Digest from JSON Body
    var jsonBody = '{\"order\":{\"invoice_number\":\"INV-20210124-0001\",\"amount\":150000},\"virtual_account_info\":{\"expired_time\":60,\"reusable_status\":false,\"info1\":\"Merchant Demo Store\"},\"customer\":{\"name\":\"Taufik Ismail\",\"email\":\"taufik@example.com\"}}'
    digest := generateDigest(jsonBody);
    fmt.Println("----- Digest -----")
    fmt.Println(digest)
    fmt.Println("")
    
    // Generate Signature
    headerSignature := generateSignature(
        "yourClientId",
        "yourRequestId",
        "2020-10-21T03:38:28Z",
        "/request-target/goes-here", // For merchant request to DOKU, use DOKU path here. For HTTP Notification, use merchant path here
        digest, // Set empty string for this argumentes if HTTP Method is GET/DELETE
        "secret-key-from-DOKU-back-office")
 
    fmt.Println("----- Header Signature -----")    
    fmt.Println(headerSignature)
}

```

{% endtab %}
{% endtabs %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://developers.doku.com/get-started-with-doku-api/signature-component/non-snap/sample-code.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
