Authentication
ทุก request ที่ best-system ยิงมาที่ wallet API ของคุณ แนบ header 2 ตัว — verify ให้ผ่านก่อนประมวลผลเสมอ ไม่ผ่านห้ามแตะเงิน
Headers ที่แนบมาทุก request
| Header | ค่า |
|---|---|
X-Api-Key | API key ที่ best-system ออกให้ — ตรวจว่าตรงกับที่คุณถืออยู่ |
X-Signature | HMAC-SHA256(rawBody, secret) เข้ารหัสเป็น hex |
body เป็น JSON เสมอ (Content-Type: application/json)
Verify จาก raw bytes เท่านั้น
signature คำนวณจาก raw body ทั้งก้อนแบบ byte ต่อ byte ด้วย secret ที่ best-system ออกให้ ฝั่งคุณจึงต้องเก็บ raw bytes ของ request ไว้ verify ก่อน แล้วค่อย parse เป็น JSON ทีหลัง
ห้าม re-serialize
อย่า JSON.parse แล้ว JSON.stringify กลับมาคำนวณ signature — ลำดับ key, ช่องว่าง, หรือรูปแบบตัวเลขที่ต่างไปแม้ byte เดียวจะทำให้ signature ไม่ตรงทั้งที่ request ถูกต้อง
ตัวอย่าง middleware สำหรับทุก endpoint ใต้ /api (Express):
import express from "express";
import { createHmac, timingSafeEqual } from "node:crypto";
const app = express();
// รับ raw bytes ไว้ก่อน — signature คิดจาก raw body ห้าม parse ก่อน verify
app.use("/api", express.raw({ type: "application/json" }));
app.use("/api", (req, res, next) => {
if (req.headers["x-api-key"] !== process.env.BS_API_KEY) {
return res.json({ code: 40003 });
}
const expected = createHmac("sha256", process.env.BS_SECRET!)
.update(req.body) // raw bytes — ห้าม JSON.parse แล้วค่อย stringify
.digest("hex");
const given = String(req.headers["x-signature"] ?? "");
const ok =
given.length === expected.length &&
timingSafeEqual(Buffer.from(given), Buffer.from(expected));
if (!ok) return res.status(401).json({ code: 30002 });
req.body = JSON.parse(req.body.toString("utf8"));
next();
});ใช้ timingSafeEqual เพื่อกัน timing attack — และต้องเทียบความยาวก่อน เพราะฟังก์ชันนี้ throw ถ้า buffer ยาวไม่เท่ากัน
เมื่อ signature ไม่ผ่าน
ตอบได้ 2 แบบ (best-system รองรับทั้งคู่):
- HTTP 200 พร้อม body ที่มี
code: 30002 - HTTP 401
ทั้งสองกรณีห้ามประมวลผล txns[] ใดๆ ต่อ — ดูรหัสทั้งหมดที่ Seamless codes
Credential มาจากไหน
- best-system เป็นผู้ออก
api_key+secretให้คุณ ผ่านหน้า bo: Api Management → API Credential seamless_callback_url(base URL ของ endpoints ทั้งหมด) ลงทะเบียนคู่กับ credential ชุดเดียวกัน- เก็บ
secretไว้ฝั่ง server เท่านั้น — ห้ามฝังใน client/mobile และหมุน (rotate) ได้โดยประสานกับทีม best-system