Khi làm việc với các sàn giao dịch tiền mã hóa như OKX, việc implement authentication đúng cách là yếu tố then chốt để đảm bảo tính bảo mật cho các API requests. Bài viết này sẽ hướng dẫn chi tiết cách implement HMAC signature authentication cho OKX API từ cơ bản đến nâng cao.
Tổng quan về OKX API Authentication
OKX sử dụng phương thức HMAC-SHA256 để ký các API requests. Mỗi request cần có signature được tạo từ việc kết hợp các tham số request với secret key của bạn. Điều quan trọng cần hiểu là signature không phải là mã hóa - nó là cơ chế xác thực để chứng minh bạn sở hữu secret key mà không cần gửi key đó qua network.
Các thành phần cần thiết
- API Key: Public identifier cho ứng dụng của bạn
- Secret Key: Khóa bí mật dùng để tạo HMAC signature
- Passphrase: Mật khẩu bổ sung được thiết lập khi tạo API key
- Timestamp: Thời gian request được tạo (ISO 8601 format)
Implementation chi tiết
Bước 1: Cài đặt dependencies
# Python
pip install requests crypto-js
npm install crypto-js axios # Node.js
Bước 2: Implement HMAC Signature Function
# Python implementation
import hmac
import hashlib
import time
import requests
from urllib.parse import urlencode
class OKXAuthenticator:
def __init__(self, api_key: str, secret_key: str, passphrase: str, use_sandbox: bool = False):
self.api_key = api_key
self.secret_key = secret_key
self.passphrase = passphrase
self.base_url = "https://www.okx.com" if not use_sandbox else "https://www.okx.com"
def _sign(self, timestamp: str, method: str, path: str, body: str = "") -> str:
"""
Tạo HMAC-SHA256 signature
Signature = HMAC-SHA256(secretKey, timestamp + method + path + body)
"""
message = timestamp + method + path + body
signature = hmac.new(
self.secret_key.encode('utf-8'),
message.encode('utf-8'),
hashlib.sha256
).digest()
return signature.hex().upper()
def _get_headers(self, method: str, path: str, body: str = "") -> dict:
timestamp = time.strftime("%Y-%m-%dT%H:%M:%S.000Z", time.gmtime())
signature = self._sign(timestamp, method, path, body)
return {
'OK-ACCESS-KEY': self.api_key,
'OK-ACCESS-SIGN': signature,
'OK-ACCESS-TIMESTAMP': timestamp,
'OK-ACCESS-PASSPHRASE': self.passphrase,
'Content-Type': 'application/json'
}
def request(self, method: str, endpoint: str, params: dict = None, body: dict = None):
path = endpoint
if params:
path += '?' + urlencode(params)
body_str = json.dumps(body) if body else ""
headers = self._get_headers(method, endpoint, body_str)
url = self.base_url + endpoint
response = requests.request(method, url, headers=headers, params=params, json=body)
return response.json()
Bước 3: Sử dụng Authentication
# Python - Ví dụ thực tế
import json
Khởi tạo authenticator
auth = OKXAuthenticator(
api_key="YOUR_API_KEY",
secret_key="YOUR_SECRET_KEY",
passphrase="YOUR_PASSPHRASE"
)
Lấy thông tin tài khoản
account_info = auth.request("GET", "/api/v5/account/balance")
print(json.dumps(account_info, indent=2))
Đặt lệnh mua BTC
order_params = {
"instId": "BTC-USDT",
"tdMode": "cash",
"side": "buy",
"ordType": "limit",
"sz": "0.01",
"px": "50000"
}
order_result = auth.request("POST", "/api/v5/trade/order", body=order_params)
print(json.dumps(order_result, indent=2))
Node.js Implementation
// Node.js implementation
const crypto = require('crypto-js');
const axios = require('axios');
class OKXClient {
constructor(apiKey, secretKey, passphrase, passphraseIV, useSandbox = false) {
this.apiKey = apiKey;
this.secretKey = secretKey;
this.passphrase = passphrase;
this.passphraseIV = passphraseIV;
this.baseURL = "https://www.okx.com";
}
// Mã hóa passphrase bằng AES
_encryptPassphrase() {
return crypto.AES.encrypt(this.passphrase, this.passphraseIV).toString();
}
// Tạo signature
_sign(timestamp, method, requestPath, body) {
const message = timestamp + method + requestPath + body;
return crypto.HmacSHA256(message, this.secretKey).toString(crypto.enc.Hex).toUpperCase();
}
// Tạo headers cho request
_getHeaders(method, requestPath, body = '') {
const timestamp = new Date().toISOString();
const bodyString = body ? JSON.stringify(body) : '';
const signature = this._sign(timestamp, method, requestPath, bodyString);
const encryptedPassphrase = this._encryptPassphrase();
return {
'OK-ACCESS-KEY': this.apiKey,
'OK-ACCESS-SIGN': signature,
'OK-ACCESS-TIMESTAMP': timestamp,
'OK-ACCESS-PASSPHRASE': encryptedPassphrase,
'Content-Type': 'application/json'
};
}
async request(method, endpoint, params = null, body = null) {
const bodyString = body ? JSON.stringify(body) : '';
const headers = this._getHeaders(method, endpoint, bodyString);
let url = this.baseURL + endpoint;
if (params) {
url += '?' + new URLSearchParams(params).toString();
}
try {
const response = await axios({
method,
url,
headers,
params,
data: body
});
return response.data;
} catch (error) {
console.error('API Error:', error.response?.data || error.message);
throw error;
}
}
// Lấy danh sách vị thế
async getPositions() {
return this.request('GET', '/api/v5/account/positions');
}
// Lấy thông tin tài khoản
async getAccountBalance() {
return this.request('GET', '/api/v5/account/balance');
}
// Đặt lệnh
async placeOrder(instId, side, ordType, sz, px = null) {
const orderData = {
instId,
tdMode: 'cash',
side,
ordType,
sz
};
if (px) orderData.px = px;
return this.request('POST', '/api/v5/trade/order', null, orderData);
}
}
// Sử dụng
const client = new OKXClient(
'YOUR_API_KEY',
'YOUR_SECRET_KEY',
'YOUR_PASSPHRASE',
'YOUR_PASSPHRASE_IV'
);
(async () => {
try {
const balance = await client.getAccountBalance();
console.log('Balance:', JSON.stringify(balance, null, 2));
} catch (error) {
console.error('Error:', error);
}
})();
Các loại signature requests
OKX API yêu cầu signature cho các endpoint khác nhau với các tham số khác nhau:
- GET requests: Signature chỉ bao gồm timestamp + method + path (không có body)
- POST/PUT/DELETE requests: Signature bao gồm timestamp + method + path + body
- Market data endpoints: Không yêu cầu signature (public endpoints)
Lỗi thường gặp và cách khắc phục
1. Lỗi "signature verification failed"
Nguyên nhân: Signature không khớp với server expectations
# Cách khắc phục - Debug signature
def debug_signature(timestamp, method, path, body, secret_key):
message = timestamp + method + path + body
print(f"Message: {repr(message)}")
print(f"Message length: {len(message)}")
signature = hmac.new(
secret_key.encode('utf-8'),
message.encode('utf-8'),
hashlib.sha256
).digest().hex().upper()
print(f"Signature: {signature}")
return signature
Kiểm tra xem timestamp format có đúng không
OKX yêu cầu: 2024-01-15T10:30:00.000Z
2. Lỗi "invalid passphrase"
Nguyên nhân: Passphrase không được mã hóa đúng cách hoặc sai passphrase
# Python - Mã hóa passphrase nếu cần
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend
import base64
def encrypt_passphrase(passphrase, passphraseIV, secretKey):
"""
Mã hóa passphrase sử dụng AES-256-CBC
passphraseIV và secretKey được cung cấp khi tạo API key
"""
cipher = Cipher(
algorithms.AES(secretKey.encode('utf-8')),
modes.CBC(passphraseIV.encode('utf-8')),
backend=default_backend()
)
encryptor = cipher.encryptor()
# PKCS7 padding
block_size = 16
padding_length = block_size - (len(passphrase) % block_size)
padded_data = passphrase + chr(padding_length) * padding_length
encrypted = encryptor.update(padded_data.encode('utf-8')) + encryptor.finalize()
return base64.b64encode(encrypted).decode('utf-8')
3. Lỗi timestamp out of range
Nguyên nhân: Timestamp của request chênh lệch quá nhiều so với server time
# Python - Đồng bộ thời gian với server
import time
import requests
def get_server_time():
"""Lấy thời gian server OKX"""
response = requests.get("https://www.okx.com/api/v5/public/time")
data = response.json()
if data['code'] == '0':
return int(data['data'][0]['ts']) / 1000 # Convert ms to seconds
return None
def sync_timestamp(authenticator):
"""Đồng bộ timestamp với server OKX"""
server_time = get_server_time()
if server_time:
local_time = time.time()
drift = server_time - local_time
print(f"Time drift: {drift:.2f} seconds")
return drift
return 0
Sử dụng - gọi khi khởi tạo authenticator
time_drift = sync_timestamp(authenticator)
4. Lỗi "insufficient permissions"
Nguyên nhân: API key không có quyền truy cập endpoint đó
# Kiểm tra và xử lý permission errors
def handle_api_error(response):
error_codes = {
'58001': 'Insufficient trading permissions',
'58002': 'Insufficient reading permissions',
'58003': 'Insufficient transfer permissions',
'58004': 'Insufficient withdrawal permissions',
'58005': 'Insufficient account permissions'
}
if response.get('code') != '0':
code = response.get('code')
msg = response.get('msg', 'Unknown error')
if code in error_codes:
print(f"Permission Error: {error_codes[code]}")
print(f"Details: {msg}")
print("Solution: Please regenerate API key with correct permissions")
else:
print(f"API Error {code}: {msg}")
return True
return False
Best Practices bảo mật
- Không hardcode credentials: Sử dụng environment variables hoặc secure vault
- Rotating keys: Thường xuyên thay đổi API keys
- IP whitelisting: Giới hạn IP được phép truy cập API
- Rate limiting: Implement exponential backoff khi gặp lỗi rate limit
- Request signing: Luôn ký tất cả requests để tránh replay attacks
Kết luận
Việc implement OKX API authentication đòi hỏi sự chính xác trong từng bước. Hãy đảm bảo timestamp format chính xác, signature được tạo đúng theo specification, và passphrase được xử lý phù hợp với cấu hình API key của bạn. Nếu gặp khó khăn, hãy bắt đầu với sandbox environment trước khi chuyển sang production.