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-id | 400 missing_tenant_id |
| Tenant ID 不是 UUID | 400 invalid_tenant_id |
缺少 x-actor-id | 400 missing_actor_id |
| 缺少 timestamp 或格式錯誤 | 401 missing_timestamp 或 401 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。
下一步:發佈貼文並讀取時間軸。