Authentication

ทุก request ที่ best-system ยิงมาที่ wallet API ของคุณ แนบ header 2 ตัว — verify ให้ผ่านก่อนประมวลผลเสมอ ไม่ผ่านห้ามแตะเงิน

Headers ที่แนบมาทุก request

Headerค่า
X-Api-KeyAPI key ที่ best-system ออกให้ — ตรวจว่าตรงกับที่คุณถืออยู่
X-SignatureHMAC-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):

typescript
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