Authentication Guide
Document Overview
This specification is the unified authentication standard for all interfaces. All business interfaces provided externally by the platform adopt the AKSK Bearer authentication scheme.
Important Notes
- Integration Target: Only supports third-party backend services (Node.js/Java/Python/Go etc. server-side calls)
- Security Requirements: Prohibits front-end browsers from directly storing SK. Keys must be stored in server-side environment variables or configuration files
- Authentication Implementation: Authentication logic is completely based on server-side source code implementation. Signature and validation rules are globally unified
I. Basic Universal Standards
Universal Interface Rules
| Rule | Description |
|---|---|
| Authentication Coverage | All interfaces require uniform authentication, no whitelist exceptions |
| HTTP Methods | Supports any HTTP Method: GET/POST/PUT/DELETE |
| Content-Type | Fixed as application/json |
| Auth Location | Authentication info is fixed in HTTP request header Authorization |
AK/SK Credential Explanation
| Field | Type | Purpose | Security Requirement |
|---|---|---|---|
| AK (Access Key) | Public Key ID | Identifies caller's reseller identity, participates in signature calculation | Can be printed in request logs |
| SK (Secret Key) | Private Key Secret | HMAC-SHA256 signature key, core verification credential | Strictly prohibited: plaintext transmission, front-end storage, code repository commits. Only backend configuration/environment variable access |
Test Example Credentials
⚠️ For reference only, cannot be used directly. Test/production credentials will be separately issued
AK: rak_if7r3r5rr2t1inhutldf
SK: rsk_tw4tfhidw9tuqu6r4vbgklmprp0xwrhrII. Authentication Core: Token Generation Specification
Payload Structure Definition
The signature carrier structure for token generation (field case is strictly distinguished):
{
"Login": "user-test",
"Reseller": "re-test",
"Ts": 1782965433,
"Nonce": "Xs92dF7s3kGd29sL"
}Payload Field Details
| Field | Type | Required | Constraint Rules |
|---|---|---|---|
| Login | string | Yes | User account/phone number to be operated on, must belong to the reseller corresponding to current AK |
| Reseller | string | Yes | Reseller code, must be consistent with AK's reseller; for direct customer business without reseller, pass empty string "" |
| Ts | int64 | Yes | Unix timestamp in seconds; server validates time difference between client and server ≤300s, rejects if exceeded |
| Nonce | string | Yes | Cryptographically secure random string, length 8~128 bits, only uppercase/lowercase letters + digits; must generate fresh value for each request, duplicate Nonce treated as replay attack |
Complete Token Generation Steps (Order Cannot Be Changed)
Step 1: Generate Request Temporary Parameters
- Generate 16-bit random Nonce (recommended length)
- Get current system time, convert to Unix timestamp in seconds
- JavaScript/TypeScript:
Math.floor(Date.now() / 1000) - Other languages: Use corresponding system timestamp methods
- JavaScript/TypeScript:
Step 2: Serialize Payload
Convert Payload object to standard JSON string with no extra spaces or line breaks:
{"Login":"user-test","Reseller":"re-test","Ts":1782965433,"Nonce":"Xs92dF7s3kGd29sL"}Step 3: URL-Safe Raw Base64 Encoding
Equivalent to Go standard library base64.RawURLEncoding, conversion rules:
- Perform standard Base64 encoding
- Character replacement:
+→-,/→_ - Remove all trailing padding symbols
=
Example Output:
eyJMb2dpbiI6InVzZXItdGVzdCIsIlJlc2VsbGVyIjoicmUtdGVzdCIsIlRzIjoxNzgyOTY1NDMzLCJOb25jZSI6IlhzOTJkRjdzM2tHZDI5c0wifQStep 4: Concatenate Signature Source
signSource = {AK}.{PayloadBase64String}
Example:
signSource = rak_if7r3r5rr2t1inhutldf.eyJMb2dpbiI6InVzZXItdGVzdCIsIlJlc2VsbGVyIjoicmUtdGVzdCIsIlRzIjoxNzgyOTY1NDMzLCJOb25jZSI6IlhzOTJkRjdzM2tHZDI5c0wifQStep 5: HMAC-SHA256 Calculate Signature
- Key: SK plaintext
- Hash Algorithm: SHA256
- Output Format: Lowercase hexadecimal string (uppercase will fail verification)
Step 6: Concatenate Complete AK-SK Token
token = aksk_{AK}.{PayloadBase64}.{HMACSignatureHex}
Example:
token = aksk_rak_if7r3r5rr2t1inhutldf.eyJMb2dpbiI6InVzZXItdGVzdCIsIlJlc2VsbGVyIjoicmUtdGVzdCIsIlRzIjoxNzgyOTY1NDMzLCJOb25jZSI6IlhzOTJkRjdzM2tHZDI5c0wifQ.a7f29d0c8e1b356xxxx💡 Prefix
aksk_is fixed and cannot be modified
Step 7: Assemble Authentication Request Header
Authorization: Bearer {token}III. Universal Request Header Specification
All interfaces follow unified request header specification:
| Header Key | Required | Description |
|---|---|---|
| Authorization | Yes | Bearer + complete aksk token generated above |
| Content-Type | Yes | Fixed as application/json |
| X-Accept-Language | Optional | Pass zh to return business error messages in Chinese |
| Referer | Optional | Reseller front-end domain name for platform reseller source statistics; not required if none (mandatory for reseller users, optional for personal users) |
Complete Request Header Example
Authorization: Bearer aksk_rak_if7r3r5rr2t1inhutldf.eyJMb2dpbiI6Imd4eS10ZXN0IiwiUmVzZWxsZXIiOiJjbXE6IiwiVHM6IjE3ODI5NjU0MzMiLCJOb25jZSI6IlhzOTJkRjdzM2tHZDI5c0wifQ.a7f29d0c8e1b356xxxx
Content-Type: application/json
X-Accept-Language: zh
Referer: https://re-test.example.com/IV. Universal Response Format
All interfaces return HTTP status code 200. Business success/failure is distinguished by success field in JSON:
{
"success": true,
"message": "Operation description text",
"data": {}
}Standard Authentication Error Responses
1. Replay Attack (Duplicate Nonce Usage)
{
"success": false,
"message": "Replay request detected"
}2. Timestamp Outside Offset Window
{
"success": false,
"message": "Invalid or expired timestamp"
}3. Signature Verification Failed
Returned for AK/SK errors, payload tampering, or signature case errors:
{
"success": false,
"message": "Signature verification failed"
}4. Nonce Length Less Than 8 Bits
{
"success": false,
"message": "nonce too short"
}V. Common Integration Pitfalls ⚠️
1. Timestamp Unit Error
Problem: JavaScript/TypeScript native Date.now() is in milliseconds
Solution: Must divide by 1000 and floor to convert to seconds, otherwise timestamp is deemed invalid
// ❌ Wrong
const ts = Date.now();
// ✅ Correct
const ts = Math.floor(Date.now() / 1000);2. Non-standard Base64 Format
Problem: Failed to replace +/- or failed to remove trailing = padding
Solution: Strictly follow URL-Safe Raw Base64 encoding rules
3. Payload Field Case Error
Problem: Using lowercase login/reseller/ts/nonce causes server JSON parsing corruption
Solution: Must use exact field names: Login/Reseller/Ts/Nonce
4. Uppercase Hex Signature Output
Problem: HMAC digest output as uppercase string
Solution: HMAC digest must be converted to lowercase; uppercase strings fail server verification
# ❌ Wrong
signature = hmac.new(sk.encode(), sign_source.encode(), hashlib.sha256).hexdigest().upper()
# ✅ Correct
signature = hmac.new(sk.encode(), sign_source.encode(), hashlib.sha256).hexdigest()5. Nonce Reuse
Problem: Same random string repeated in short-term requests triggers replay interception
Solution: Must generate fresh Nonce for each request
6. SK Plaintext Exposure Risk
Problem: SK printed in logs, stored in front-end, or committed to repository
Solution: SK only allowed in backend service environment variables or encrypted configuration
VI. Code Examples
import hmac
import hashlib
import base64
import json
import time
import random
import string
import requests
class AKSKAuth:
def __init__(self, ak, sk):
self.ak = ak
self.sk = sk
def generate_nonce(self, length=16):
"""Generate random nonce of specified length"""
chars = string.ascii_letters + string.digits
return ''.join(random.choice(chars) for _ in range(length))
def get_timestamp(self):
"""Get current unix timestamp in seconds"""
return int(time.time())
def build_payload(self, login, reseller=""):
"""Build payload object"""
return {
"Login": login,
"Reseller": reseller,
"Ts": self.get_timestamp(),
"Nonce": self.generate_nonce()
}
def encode_payload(self, payload):
"""Encode payload as URL-Safe Raw Base64"""
json_str = json.dumps(payload, separators=(',', ':'), ensure_ascii=False)
base64_encoded = base64.b64encode(json_str.encode()).decode()
url_safe = base64_encoded.replace('+', '-').replace('/', '_').rstrip('=')
return url_safe
def generate_signature(self, ak, payload_base64):
"""Generate HMAC-SHA256 signature"""
sign_source = f"{ak}.{payload_base64}"
signature = hmac.new(
self.sk.encode(),
sign_source.encode(),
hashlib.sha256
).hexdigest()
return signature, sign_source
def generate_token(self, login, reseller=""):
"""Generate complete AK/SK Token"""
payload = self.build_payload(login, reseller)
payload_base64 = self.encode_payload(payload)
signature, _ = self.generate_signature(self.ak, payload_base64)
token = f"aksk_{self.ak}.{payload_base64}.{signature}"
return token
def get_auth_header(self, login, reseller=""):
"""Get complete Authorization header"""
token = self.generate_token(login, reseller)
return f"Bearer {token}"
def request_with_auth(self, method, url, login, reseller="", **kwargs):
"""Send HTTP request with AK/SK authentication"""
headers = kwargs.get('headers', {})
headers['Authorization'] = self.get_auth_header(login, reseller)
headers['Content-Type'] = 'application/json'
kwargs['headers'] = headers
response = requests.request(method, url, **kwargs)
return response
# Usage example
if __name__ == "__main__":
AK = "rak_if7r3r5rr2t1inhutldf"
SK = "rsk_tw4tfhidw9tuqu6r4vbgklmprp0xwrhr"
auth = AKSKAuth(AK, SK)
token = auth.generate_token(login="user-test", reseller="re-test")
print(f"Generated Token: {token}")
auth_header = auth.get_auth_header(login="user-test", reseller="re-test")
print(f"Authorization: {auth_header}")import axios, { AxiosRequestConfig } from 'axios';
import crypto from 'crypto';
interface PayloadData {
Login: string;
Reseller: string;
Ts: number;
Nonce: string;
}
class AKSKAuth {
private ak: string;
private sk: string;
constructor(ak: string, sk: string) {
this.ak = ak;
this.sk = sk;
}
private generateNonce(length: number = 16): string {
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
let result = '';
for (let i = 0; i < length; i++) {
result += chars.charAt(Math.floor(Math.random() * chars.length));
}
return result;
}
private getTimestamp(): number {
return Math.floor(Date.now() / 1000);
}
private buildPayload(login: string, reseller: string = ''): PayloadData {
return {
Login: login,
Reseller: reseller,
Ts: this.getTimestamp(),
Nonce: this.generateNonce()
};
}
private encodePayload(payload: PayloadData): string {
const jsonStr = JSON.stringify(payload);
const base64Encoded = Buffer.from(jsonStr).toString('base64');
const urlSafe = base64Encoded
.replace(/\+/g, '-')
.replace(/\//g, '_')
.replace(/=+$/, '');
return urlSafe;
}
private generateSignature(ak: string, payloadBase64: string): { signature: string; signSource: string } {
const signSource = `${ak}.${payloadBase64}`;
const signature = crypto
.createHmac('sha256', this.sk)
.update(signSource)
.digest('hex');
return { signature, signSource };
}
public generateToken(login: string, reseller: string = ''): string {
const payload = this.buildPayload(login, reseller);
const payloadBase64 = this.encodePayload(payload);
const { signature } = this.generateSignature(this.ak, payloadBase64);
const token = `aksk_${this.ak}.${payloadBase64}.${signature}`;
return token;
}
public getAuthHeader(login: string, reseller: string = ''): string {
const token = this.generateToken(login, reseller);
return `Bearer ${token}`;
}
public async requestWithAuth(
method: 'GET' | 'POST' | 'PUT' | 'DELETE',
url: string,
login: string,
reseller: string = '',
data?: any,
headers?: any
) {
const config: AxiosRequestConfig = {
method,
url,
headers: {
...headers,
'Authorization': this.getAuthHeader(login, reseller),
'Content-Type': 'application/json'
}
};
if (data) {
config.data = data;
}
return axios(config);
}
}
// Usage example
(async () => {
const AK = 'rak_if7r3r5rr2t1inhutldf';
const SK = 'rsk_tw4tfhidw9tuqu6r4vbgklmprp0xwrhr';
const auth = new AKSKAuth(AK, SK);
const token = auth.generateToken('user-test', 're-test');
console.log(`Generated Token: ${token}`);
const authHeader = auth.getAuthHeader('user-test', 're-test');
console.log(`Authorization: ${authHeader}`);
})();package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/base64"
"encoding/json"
"fmt"
"math/rand"
"time"
"github.com/go-resty/resty/v2"
)
type PayloadData struct {
Login string `json:"Login"`
Reseller string `json:"Reseller"`
Ts int64 `json:"Ts"`
Nonce string `json:"Nonce"`
}
type AKSKAuth struct {
AK string
SK string
}
func (a *AKSKAuth) GenerateNonce(length int) string {
const charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
b := make([]byte, length)
for i := range b {
b[i] = charset[rand.Intn(len(charset))]
}
return string(b)
}
func (a *AKSKAuth) GetTimestamp() int64 {
return time.Now().Unix()
}
func (a *AKSKAuth) BuildPayload(login, reseller string) PayloadData {
return PayloadData{
Login: login,
Reseller: reseller,
Ts: a.GetTimestamp(),
Nonce: a.GenerateNonce(16),
}
}
func (a *AKSKAuth) EncodePayload(payload PayloadData) (string, error) {
jsonBytes, err := json.Marshal(payload)
if err != nil {
return "", err
}
urlSafe := base64.RawURLEncoding.EncodeToString(jsonBytes)
return urlSafe, nil
}
func (a *AKSKAuth) GenerateSignature(ak, payloadBase64 string) (string, string) {
signSource := fmt.Sprintf("%s.%s", ak, payloadBase64)
h := hmac.New(sha256.New, []byte(a.SK))
h.Write([]byte(signSource))
signature := fmt.Sprintf("%x", h.Sum(nil))
return signature, signSource
}
func (a *AKSKAuth) GenerateToken(login, reseller string) (string, error) {
payload := a.BuildPayload(login, reseller)
payloadBase64, err := a.EncodePayload(payload)
if err != nil {
return "", err
}
signature, _ := a.GenerateSignature(a.AK, payloadBase64)
token := fmt.Sprintf("aksk_%s.%s.%s", a.AK, payloadBase64, signature)
return token, nil
}
func (a *AKSKAuth) GetAuthHeader(login, reseller string) (string, error) {
token, err := a.GenerateToken(login, reseller)
if err != nil {
return "", err
}
return fmt.Sprintf("Bearer %s", token), nil
}
// Usage example
func main() {
AK := "rak_if7r3r5rr2t1inhutldf"
SK := "rsk_tw4tfhidw9tuqu6r4vbgklmprp0xwrhr"
auth := &AKSKAuth{AK: AK, SK: SK}
token, err := auth.GenerateToken("user-test", "re-test")
if err != nil {
fmt.Printf("Error generating token: %v\n", err)
return
}
fmt.Printf("Generated Token: %s\n", token)
authHeader, err := auth.GetAuthHeader("user-test", "re-test")
if err != nil {
fmt.Printf("Error getting auth header: %v\n", err)
return
}
fmt.Printf("Authorization: %s\n", authHeader)
}import com.google.gson.Gson;
import com.google.gson.JsonObject;
import org.apache.commons.codec.binary.Hex;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.Random;
public class AKSKAuth {
private String ak;
private String sk;
private Gson gson;
public AKSKAuth(String ak, String sk) {
this.ak = ak;
this.sk = sk;
this.gson = new Gson();
}
private String generateNonce(int length) {
String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
StringBuilder sb = new StringBuilder();
Random random = new Random();
for (int i = 0; i < length; i++) {
sb.append(chars.charAt(random.nextInt(chars.length())));
}
return sb.toString();
}
private long getTimestamp() {
return System.currentTimeMillis() / 1000;
}
private JsonObject buildPayload(String login, String reseller) {
JsonObject payload = new JsonObject();
payload.addProperty("Login", login);
payload.addProperty("Reseller", reseller);
payload.addProperty("Ts", getTimestamp());
payload.addProperty("Nonce", generateNonce(16));
return payload;
}
private String encodePayload(JsonObject payload) {
String jsonStr = gson.toJson(payload);
String base64Encoded = Base64.getEncoder().encodeToString(jsonStr.getBytes(StandardCharsets.UTF_8));
return base64Encoded
.replace("+", "-")
.replace("/", "_")
.replaceAll("=+$", "");
}
private String generateSignature(String ak, String payloadBase64) throws Exception {
String signSource = ak + "." + payloadBase64;
Mac mac = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKey = new SecretKeySpec(sk.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
mac.init(secretKey);
byte[] signature = mac.doFinal(signSource.getBytes(StandardCharsets.UTF_8));
return Hex.encodeHexString(signature);
}
public String generateToken(String login, String reseller) throws Exception {
JsonObject payload = buildPayload(login, reseller);
String payloadBase64 = encodePayload(payload);
String signature = generateSignature(ak, payloadBase64);
return String.format("aksk_%s.%s.%s", ak, payloadBase64, signature);
}
public String getAuthHeader(String login, String reseller) throws Exception {
String token = generateToken(login, reseller);
return "Bearer " + token;
}
public static void main(String[] args) {
String AK = "rak_if7r3r5rr2t1inhutldf";
String SK = "rsk_tw4tfhidw9tuqu6r4vbgklmprp0xwrhr";
AKSKAuth auth = new AKSKAuth(AK, SK);
try {
String token = auth.generateToken("user-test", "re-test");
System.out.println("Generated Token: " + token);
String authHeader = auth.getAuthHeader("user-test", "re-test");
System.out.println("Authorization: " + authHeader);
} catch (Exception e) {
e.printStackTrace();
}
}
}#!/bin/bash
AK="rak_if7r3r5rr2t1inhutldf"
SK="rsk_tw4tfhidw9tuqu6r4vbgklmprp0xwrhr"
LOGIN="user-test"
RESELLER="re-test"
# Generate timestamp (seconds)
TIMESTAMP=$(date +%s)
# Generate random Nonce (16 chars)
NONCE=$(openssl rand -hex 8 | tr -d '\n')
# Build Payload JSON
PAYLOAD="{\"Login\":\"$LOGIN\",\"Reseller\":\"$RESELLER\",\"Ts\":$TIMESTAMP,\"Nonce\":\"$NONCE\"}"
# Base64 URL-Safe encode Payload
PAYLOAD_BASE64=$(echo -n "$PAYLOAD" | base64 | tr '+/' '-_' | tr -d '=')
# Concatenate signature source
SIGN_SOURCE="$AK.$PAYLOAD_BASE64"
# Calculate HMAC-SHA256 signature (lowercase Hex)
SIGNATURE=$(echo -n "$SIGN_SOURCE" | openssl dgst -sha256 -hmac "$SK" -hex | cut -d' ' -f2)
# Assemble complete Token
TOKEN="aksk_$AK.$PAYLOAD_BASE64.$SIGNATURE"
# Build Authorization header
AUTH_HEADER="Bearer $TOKEN"
echo "Token: $TOKEN"
echo "Authorization: $AUTH_HEADER"
# Send request example
curl -X POST https://api.example.com/v1/chat/completions \
-H "Authorization: $AUTH_HEADER" \
-H "Content-Type: application/json" \
-H "X-Accept-Language: en" \
-d '{
"model": "gpt-4",
"messages": [
{"role": "user", "content": "Hello"}
]
}'