Authentication & Security
Security is critical for wallet integrations. Game Provider employs a dual-layer security model.
1. Signature Validation (HMAC-SHA256)
All requests from Game Provider to your Wallet API are signed. You must validate the signature on every inbound request.
| Property | Value |
|---|---|
| Algorithm | HMAC-SHA256 |
| Output encoding | Base64 (standard, not URL-safe) |
| Headers sent | X-Public-Key, X-Signature |
| Secret source | Shared secret provided during onboarding, one per operator/environment |
| Payload that is signed | The exact raw request body bytes sent over the wire (UTF-8 encoded JSON) |
| Secret key encoding | UTF-8 bytes of the secret string |
How to Validate
- Read the
X-Public-Keyheader to identify the tenant and look up the corresponding secret key on your side. - Read the
X-Signatureheader. - Compute
Base64(HMAC_SHA256(secret_key_utf8, raw_request_body_bytes)). - Compare with the header value using a constant-time comparison (e.g.
MessageDigest.isEqualin Java,hmac.compare_digestin Python).
[!WARNING] Do not re-serialize the JSON body before computing the HMAC. The signature is computed over the exact bytes on the wire; any reformatting (key reordering, whitespace change, number formatting) will break the signature. Read the raw bytes from the HTTP request input stream, validate HMAC first, then parse JSON.
[!WARNING] If the signatures do not match, reject the request with HTTP 401 and do not process it. Never log the secret key or the signature value at non-debug levels.
2. IP Whitelisting
For additional defense-in-depth, you may whitelist Game Provider's outbound IP ranges. Contact support for the current production IP list; addresses vary per environment.
3. Code Samples (Generation & Validation)
Wallet API: You must validate the signature (Inbound). Gift API: You must generate a signature (Outbound).
Below are examples of how to do both.
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
public class SignatureHelper {
// Use this to VALIDATE requests from Game Provider (Wallet API)
public static boolean isValid(String secretKey, String rawBody, String headerSignature) {
String computed = sign(secretKey, rawBody);
return computed.equals(headerSignature);
}
// Use this to GENERATE signatures for requests to Game Provider (Gift API)
public static String sign(String secretKey, String message) {
try {
Mac mac = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKeySpec = new SecretKeySpec(
secretKey.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
mac.init(secretKeySpec);
byte[] rawHmac = mac.doFinal(message.getBytes(StandardCharsets.UTF_8));
return Base64.getEncoder().encodeToString(rawHmac);
} catch (Exception e) {
throw new RuntimeException("Failed to calculate HMAC", e);
}
}
}
using System;
using System.Security.Cryptography;
using System.Text;
public class SignatureHelper {
// Use this to VALIDATE requests from Game Provider (Wallet API)
public static bool IsValid(string secretKey, string rawBody, string headerSignature) {
string computed = Sign(secretKey, rawBody);
return computed == headerSignature;
}
// Use this to GENERATE signatures for requests to Game Provider (Gift API)
public static string Sign(string secretKey, string message) {
var encoding = new UTF8Encoding();
byte[] keyBytes = encoding.GetBytes(secretKey);
byte[] messageBytes = encoding.GetBytes(message);
using (var hmac = new HMACSHA256(keyBytes)) {
byte[] hashMessage = hmac.ComputeHash(messageBytes);
return Convert.ToBase64String(hashMessage);
}
}
}
package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/base64"
)
// Use this to VALIDATE requests from Game Provider (Wallet API)
func IsValid(secretKey, rawBody, headerSignature string) bool {
computed := Sign(secretKey, rawBody)
return computed == headerSignature
}
// Use this to GENERATE signatures for requests to Game Provider (Gift API)
func Sign(secretKey, message string) string {
key := []byte(secretKey)
h := hmac.New(sha256.New, key)
h.Write([]byte(message))
return base64.StdEncoding.EncodeToString(h.Sum(nil))
}
import hmac
import hashlib
import base64
# Use this to VALIDATE requests from Game Provider (Wallet API)
def is_valid(secret_key, raw_body, header_signature):
computed = sign(secret_key, raw_body)
return computed == header_signature
# Use this to GENERATE signatures for requests to Game Provider (Gift API)
def sign(secret_key, message):
key = bytes(secret_key, 'utf-8')
msg = bytes(message, 'utf-8')
raw_hmac = hmac.new(key, msg, hashlib.sha256).digest()
return base64.b64encode(raw_hmac).decode('utf-8')