Skip to content

Signature Verification

The iGV platform uses HMAC-SHA256 to sign callback requests. Sellers should verify the signature to ensure request authenticity.

Constructing the Signature String

The signature string is formed by directly concatenating the following three parts (no separator):

raw_string = X-Timestamp + X-Request-Id + secretKey
PartSourceDescription
X-TimestampRequest headerValue of the X-Timestamp header
X-Request-IdRequest headerValue of the X-Request-Id header
secretKeyPlatform-assignedKey assigned by iGV (see Secret Key)

Computing the Signature

Use the secretKey as the HMAC key and compute SHA256 on the raw_string:

expected_signature = HMAC-SHA256(raw_string, secretKey)

Compare the computed result with the X-Signature value from the request header. If they match, the request is authentic.

Full Example

Given data:

  • X-Timestamp: 1734850099000
  • X-Request-Id: 2002986662652579841
  • secretKey: aBcDeFgHiJkLmNoPqRsTuVwXyZ012345

Step 1 — Concatenate the raw string:

17348500990002002986662652579841aBcDeFgHiJkLmNoPqRsTuVwXyZ012345

Step 2 — Compute HMAC-SHA256: Using aBcDeFgHiJkLmNoPqRsTuVwXyZ012345 as the key, compute HMAC-SHA256 on the above raw string.

Step 3 — Compare: Compare the computed result with the X-Signature header value (case-insensitive).

Code Examples

Java

java
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;

public class CallbackSignatureVerifier {

    public static boolean verify(String timestamp, String requestId,
                                  String secretKey, String receivedSignature) throws Exception {
        String rawString = timestamp + requestId + secretKey;

        Mac mac = Mac.getInstance("HmacSHA256");
        SecretKeySpec keySpec = new SecretKeySpec(
            secretKey.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
        mac.init(keySpec);
        byte[] hash = mac.doFinal(rawString.getBytes(StandardCharsets.UTF_8));

        StringBuilder hexString = new StringBuilder();
        for (byte b : hash) {
            hexString.append(String.format("%02x", b));
        }

        return hexString.toString().equalsIgnoreCase(receivedSignature);
    }
}

Python

python
import hmac
import hashlib

def verify_signature(timestamp: str, request_id: str,
                     secret_key: str, received_signature: str) -> bool:
    raw_string = timestamp + request_id + secret_key
    expected = hmac.new(
        secret_key.encode("utf-8"),
        raw_string.encode("utf-8"),
        hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(expected.lower(), received_signature.lower())

Go

go
package main

import (
	"crypto/hmac"
	"crypto/sha256"
	"encoding/hex"
	"strings"
)

func verifySignature(timestamp, requestId, secretKey, receivedSignature string) bool {
	rawString := timestamp + requestId + secretKey

	mac := hmac.New(sha256.New, []byte(secretKey))
	mac.Write([]byte(rawString))
	expected := hex.EncodeToString(mac.Sum(nil))

	return strings.EqualFold(expected, receivedSignature)
}

Handling Verification Failures

If signature verification fails:

  • Return a non-200 status code (recommended: 401 or 403)
  • Log the request for debugging
  • Do not execute any business logic

Security Reminder

Never skip signature verification. Unverified requests may originate from malicious third parties.

All game copyrights, trademarks, and service marks belong to their respective owners.