搜尋完整文件

輸入關鍵字,例如 idempotency、proposal lifecycle 或權限。

選擇 開啟
English
瀏覽文件

Activity · 身分驗證

簽署 Activity 請求

Activity 信任由 host server 簽署的請求。簽章會綁定 tenant、actor、method、path、query string、body bytes 與請求時間。請勿把 gateway secret 放進瀏覽器或行動裝置 App。

必填 header

每個 /api/v1 請求都必須包含四個 gateway header:

Header
x-tenant-id由 host 選定的 tenant UUID
x-actor-id由 host 管理的呼叫者身分
x-feedaas-timestamp目前的 Unix 秒數
x-feedaas-signature小寫十六進位 HMAC-SHA256 簽章

Timestamp tolerance 預設為 300 秒。Activity 會先拒絕過期的 timestamp,再檢查簽章。

簽章 payload

以換行字元依序串接以下七個值。沒有 query string 時,仍須保留空白的 query string 行:

timestamp
UPPERCASE_METHOD
request_path
raw_query_string
tenant_id
actor_id
sha256_hex(raw_body)

使用該 Activity deployment 的 gateway secret 簽署 UTF-8 bytes,再把 HMAC digest 編碼成小寫十六進位字串。

Path 必須以 / 開頭,例如 /api/v1/posts。Query string 不包含 ?。Body hash 必須根據實際送出的 bytes 計算。簽署後若重新格式化 JSON,digest 會改變,請求也會失效。

Node.js 簽章函式

import { createHash, createHmac } from "node:crypto";

export function signActivityRequest({
  secret,
  timestamp,
  method,
  path,
  query = "",
  tenantId,
  actorId,
  body = ""
}) {
  const bodyHash = createHash("sha256").update(body).digest("hex");
  const payload = [
    timestamp,
    method.toUpperCase(),
    path,
    query,
    tenantId,
    actorId,
    bodyHash
  ].join("\n");

  return createHmac("sha256", secret).update(payload).digest("hex");
}

只產生一次 timestamp,也只序列化一次 body。簽署與送出請求時必須使用完全相同的值。

失敗行為

狀況Status 與 code
缺少 x-tenant-id400 missing_tenant_id
Tenant ID 不是 UUID400 invalid_tenant_id
缺少 x-actor-id400 missing_actor_id
缺少 timestamp 或格式錯誤401 missing_timestamp401 invalid_timestamp
Timestamp 超過允許時間401 expired_timestamp
缺少簽章401 missing_signature
簽章不符401 invalid_signature

身分驗證錯誤使用以下格式:

{
  "error": {
    "code": "invalid_signature",
    "message": "invalid x-feedaas-signature header"
  }
}

安全邊界

目前契約是每個 Activity deployment 使用一組 gateway secret,不是每個 tenant 各自擁有 secret。簽章功能應留在受信任的 host gateway,並透過營運設定輪替 deployment secret。

簽署後的 actor_id 代表 host 正在以哪個 actor 的身分呼叫。這不會把 business authorization 移交給 Activity。

下一步:發佈貼文並讀取時間軸