Skip to main content

Authentication Overview

VertexPlay API uses a multi-layered authentication mechanism to ensure the security of API requests.

Authentication Process

request Headers

All API requests must include the following headers:

Authentication Request (/v2/auth)

HeaderTypeRequiredDescription
Content-TypestringYesMust be application/json
x-agentidstringYesAgent ID
x-timestampstringYesUnix timestamp (milliseconds)
x-noncestringYes32-character random string (for replay attack prevention)
x-signaturestringYesSHA256 Signature

Other API Requests

HeaderTypeRequiredDescription
AuthorizationstringYesBearer token, format: Bearer {accessToken}
Content-TypestringYesMust be application/json
x-agentidstringYesAgent ID
x-timestampstringYesUnix timestamp (milliseconds)
x-noncestringYes32-character random string
x-signaturestringYesSHA256 Signature

Signature Generation

The signature is generated using the SHA256 algorithm to ensure the integrity and authenticity of the request.

Signature Steps

  1. Prepare Signature String: Concatenate the following parameters in order

    agentId + timestamp + nonce + requestBody
  2. Generate Signature: Use the SHA256 algorithm

    signature = SHA256(signatureString)
  3. Add to Request Header: Place the generated signature into the x-signature header

Node.js Example

const crypto = require('crypto');

/**
* Generate a SHA256 signature for API request authentication
* @param {string} agentId - The unique identifier for the agent
* @param {string} timestamp - Current Unix timestamp (string format)
* @param {string} nonce - A unique random string for the request
* @param {Object} requestBody - The payload object of the request
* @returns {string} - The generated hex-encoded signature
*/
function generateSignature(agentId, timestamp, nonce, requestBody) {
// Convert the request body to a standardized JSON string
const bodyString = JSON.stringify(requestBody);

// Concatenate the parameters to create the raw signature string
const signatureString = agentId + timestamp + nonce + bodyString;

// Generate the SHA256 hash
const signature = crypto
.createHash('sha256')
.update(signatureString)
.digest('hex');

return signature;
}

// Usage Example
const agentId = 'integratorNBTest04';
const timestamp = Date.now().toString();
const nonce = crypto.randomBytes(16).toString('hex');
const requestBody = {
cipherText: 'G0ZMDELeJwx+7JcIfIFO...'
};

const signature = generateSignature(agentId, timestamp, nonce, requestBody);
console.log('Generated Signature:', signature);

Python Example

import hashlib
import json
import time
import secrets

def generate_signature(agent_id, timestamp, nonce, request_body):
# 將請求體轉為字符串
body_string = json.dumps(request_body, separators=(',', ':'))

# 組合簽章字符串
signature_string = agent_id + timestamp + nonce + body_string

# 生成 SHA256 簽章
signature = hashlib.sha256(
signature_string.encode('utf-8')
).hexdigest()

return signature

# 使用範例
agent_id = 'integratorNBTest04'
timestamp = str(int(time.time() * 1000))
nonce = secrets.token_hex(16)
request_body = {
'cipherText': 'G0ZMDELeJwx+7JcIfIFO...'
}

signature = generate_signature(agent_id, timestamp, nonce, request_body)

Data Encryption

All sensitive data in requests use AES-256-GCM encryption, and responses are in plain JSON format.

Encryption Format

{
"cipherText": "ivBase64(16字元) + authTagBase64(24字元) + encryptedDataBase64"
}

Encryption Parameters

  • Algorithm: AES-256-GCM
  • Key Length: 256 bits (32 bytes)
  • IV Length: 96 bits (12 bytes)
  • Authentication Tag Length: 128 bits (16 bytes)

cipherText Structure

cipherText consists of three parts, all base64 encoded:

  1. IV (Initialization Vector)

    • 長度:12 bytes
    • Base64 編碼後:16 字元
    • 位置:cipherText[0:16]
  2. Auth Tag (Authentication Tag)

    • Length: 16 bytes
    • After Base64 encoding: 24 characters
    • Position: cipherText[16:40]
  3. Encrypted Data

    • Length: Variable, depends on the original data
    • Base64 encoded
    • Position: cipherText[40:]

Decryption Example (Node.js)

const crypto = require('crypto');

const AES_ALGORITHM = 'aes-256-gcm';

/**
* Decrypts the cipherText using AES-256-GCM
* @param {string} key - AES key (hex format)
* @param {string} cipherText - The combined encrypted string (Base64)
* @returns {Object} - The decrypted JSON object
*/
function symmetricDecrypt(key, cipherText) {
try {
const aesKey = Buffer.from(key, 'hex');

// Separate IV, Auth Tag, and Encrypted Data from the cipherText
// Base64 encoded lengths: 12 bytes IV = 16 chars, 16 bytes Auth Tag = 24 chars
const ivLength = 16;
const authTagLength = 24;

const ivBase64 = cipherText.substring(0, ivLength);
const authTagBase64 = cipherText.substring(ivLength, ivLength + authTagLength);
const encryptedData = cipherText.substring(ivLength + authTagLength);

const aesIv = Buffer.from(ivBase64, 'base64');
const authTag = Buffer.from(authTagBase64, 'base64');

// Create decipher instance
const decipher = crypto.createDecipheriv(AES_ALGORITHM, aesKey, aesIv);

// Set the Authentication Tag for GCM integrity verification
decipher.setAuthTag(authTag);

// Decrypt the data
let decrypted = decipher.update(encryptedData, 'base64', 'utf8');

// final() will throw an error if the Authentication Tag verification fails
decrypted += decipher.final('utf8');

return JSON.parse(decrypted);
} catch (e) {
throw new Error(`Symmetric Decryption Failed: ${e.message}`);
}
}

// Usage Example
const key = 'your-32-byte-hex-key'; // 64 hex characters = 32 bytes
const cipherText = 'G0ZMDELeJwx+7JcI...'; // Complete cipherText string

try {
const decryptedData = symmetricDecrypt(key, cipherText);
console.log('Decrypted Data:', decryptedData);
} catch (error) {
console.error('Decryption Error:', error.message);
}

Encryption Example (Node.js)

/**
* Encrypt data using AES-256-GCM
* @param {string} key - AES key (hex format)
* @param {Object} data - JSON object to be encrypted
* @returns {string} - Encrypted cipherText (Base64 encoded)
*/
function symmetricEncrypt(key, data) {
try {
const aesKey = Buffer.from(key, 'hex');

// Generate a random Initialization Vector (IV) (12 bytes)
const aesIv = crypto.randomBytes(12);

// Initialize the cipher
const cipher = crypto.createCipheriv(AES_ALGORITHM, aesKey, aesIv);

// Encrypt the data
const jsonString = JSON.stringify(data);
let encrypted = cipher.update(jsonString, 'utf8', 'base64');
encrypted += cipher.final('base64');

// Get the Authentication Tag (16 bytes)
const authTag = cipher.getAuthTag();

// Combine into cipherText: ivBase64 + authTagBase64 + encryptedData
const cipherText = aesIv.toString('base64') +
authTag.toString('base64') +
encrypted;

return cipherText;
} catch (e) {
throw new Error(`Symmetric Encryption Failed: ${e.message}`);
}
}

// Usage Example
const data = {
username: 'player001',
amount: 100
};

const cipherText = symmetricEncrypt(key, data);
console.log('Encrypted cipherText:', cipherText);

Error Handling

Authentication Error Codes

CodeDescription
84Decryption Failed - Possible incorrect key or data corruption
83Authentication Failed - Signature verification failed or parameters error

Error Response Format

{
"code": 83,
"message": "Signature verification failed",
"logUUID": "6589bf8d-fe74-48bd-841a-71bf8f848f86"
}

Security Recommendations

  1. Protect Secret Key: Never store Secret Key in Operator code or public locations
  2. Use HTTPS: All API requests must be transmitted over HTTPS
  3. Timestamp Validation: Ensure the timestamp is within a reasonable range (recommended ±1 minute)
  4. Nonce Uniqueness: Use a unique nonce for each request to prevent replay attacks
  5. Token Management: Refresh accessToken regularly; do not use the same token for extended periods
  6. Error Handling: Properly handle Authentication errors to avoid exposing sensitive information

Next Steps

Learn how to Get Access Token to start using the API.