Skip to content

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 ​

  1. Integration Target: Only supports third-party backend services (Node.js/Java/Python/Go etc. server-side calls)
  2. Security Requirements: Prohibits front-end browsers from directly storing SK. Keys must be stored in server-side environment variables or configuration files
  3. 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 ​

RuleDescription
Authentication CoverageAll interfaces require uniform authentication, no whitelist exceptions
HTTP MethodsSupports any HTTP Method: GET/POST/PUT/DELETE
Content-TypeFixed as application/json
Auth LocationAuthentication info is fixed in HTTP request header Authorization

AK/SK Credential Explanation ​

FieldTypePurposeSecurity Requirement
AK (Access Key)Public Key IDIdentifies caller's reseller identity, participates in signature calculationCan be printed in request logs
SK (Secret Key)Private Key SecretHMAC-SHA256 signature key, core verification credentialStrictly 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_tw4tfhidw9tuqu6r4vbgklmprp0xwrhr

II. Authentication Core: Token Generation Specification ​

Payload Structure Definition ​

The signature carrier structure for token generation (field case is strictly distinguished):

json
{
  "Login": "user-test",
  "Reseller": "re-test",
  "Ts": 1782965433,
  "Nonce": "Xs92dF7s3kGd29sL"
}

Payload Field Details ​

FieldTypeRequiredConstraint Rules
LoginstringYesUser account/phone number to be operated on, must belong to the reseller corresponding to current AK
ResellerstringYesReseller code, must be consistent with AK's reseller; for direct customer business without reseller, pass empty string ""
Tsint64YesUnix timestamp in seconds; server validates time difference between client and server ≤300s, rejects if exceeded
NoncestringYesCryptographically 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

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:

  1. Perform standard Base64 encoding
  2. Character replacement: + → -, / → _
  3. Remove all trailing padding symbols =

Example Output:

eyJMb2dpbiI6InVzZXItdGVzdCIsIlJlc2VsbGVyIjoicmUtdGVzdCIsIlRzIjoxNzgyOTY1NDMzLCJOb25jZSI6IlhzOTJkRjdzM2tHZDI5c0wifQ

Step 4: Concatenate Signature Source ​

signSource = {AK}.{PayloadBase64String}

Example:
signSource = rak_if7r3r5rr2t1inhutldf.eyJMb2dpbiI6InVzZXItdGVzdCIsIlJlc2VsbGVyIjoicmUtdGVzdCIsIlRzIjoxNzgyOTY1NDMzLCJOb25jZSI6IlhzOTJkRjdzM2tHZDI5c0wifQ

Step 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 KeyRequiredDescription
AuthorizationYesBearer + complete aksk token generated above
Content-TypeYesFixed as application/json
X-Accept-LanguageOptionalPass zh to return business error messages in Chinese
RefererOptionalReseller 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 ​

http
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:

json
{
  "success": true,
  "message": "Operation description text",
  "data": {}
}

Standard Authentication Error Responses ​

1. Replay Attack (Duplicate Nonce Usage) ​

json
{
  "success": false,
  "message": "Replay request detected"
}

2. Timestamp Outside Offset Window ​

json
{
  "success": false,
  "message": "Invalid or expired timestamp"
}

3. Signature Verification Failed ​

Returned for AK/SK errors, payload tampering, or signature case errors:

json
{
  "success": false,
  "message": "Signature verification failed"
}

4. Nonce Length Less Than 8 Bits ​

json
{
  "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

javascript
// ❌ 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

python
# ❌ 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 ​

python
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}")
typescript
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}`);
})();
go
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)
}
java
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();
        }
    }
}
bash
#!/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"}
    ]
  }'

Next Steps ​