SocialHub.AI

開發者中心 · 擴展平台

嵌入式頁面-在背景管理中嵌入您自己的工具。

註冊您自己的 https 託管頁面,它將成為 SocialHub 管理員內的一個許可選單項目 - 一個全頁面、沙盒 iframe。 Flash 為您的頁面提供一個短暫的、無 PII 的身份令牌,以便您可以向操作員授權,而無需他們再次登入。

搶先體驗 · 開放擴充模組背後

工作原理

從您的 URL 到選單項目只需四個步驟。

01

註冊您的頁面

工作區管理員可以在 Flash → 設定 → 嵌入頁面 中新增您的 https URL,並設定選單標籤、來源允許清單以及哪些角色/層級可以開啟該 URL。

02

複製簽名秘訣

Flash 會顯示一次簽章金鑰 (slotsec_…)。將其作為伺服器金鑰儲存在您的應用程式中——您需要使用它來驗證 Flash 的身份令牌。

03

Flash 為您的頁面建立框架

該頁面會以側邊欄選單項目的形式出現在允許的運營商的「應用」下方;打開它會在沙盒化的 iframe 中加載您的 URL,並附加 ?flash_context=<token>。

04

驗證 + 授權

讀取令牌,在伺服器端 (HS256) 進行驗證,並根據令牌所包含的工作區 ID 和操作員角色來控制您的使用者介面。

身份令牌

短暫有效,不涉及個人識別訊息,以您的秘密簽名。

每次渲染時,Flash 都會將 ?flash_context=<JWT> 附加到您的 URL。這是一個使用 您的頁面 金鑰簽署的 HS256 JWT(因此您——而不是平台——是信任錨點),有效期最長為 120 秒,並且不包含任何成員個人資料——僅包含工作區 ID 和操作員的不透明 ID + 粗略角色,以便您可以進行授權。

{
  "iss": "flash",
  "aud": "nav.page",
  "slotKey": "nav.page",
  "ctx": {
    "teamId": "team_...",   // the workspace (tenant) — the tenant already owns this
    "userId": "usr_...",    // opaque operator id (NOT an email/name/phone)
    "role":   "org_admin",  // coarse role: org_owner | org_admin | marketer | store_manager
    "pageType": "nav.page",
    "locale": "en"
  },
  "jti": "…", "iat": 1730000000, "nbf": 1730000000,
  "exp": 1730000110          // <= 120s after iat
}

驗證

信任令牌,而非請求。

在您的伺服器上驗證簽名、發行者 (flash)、受眾 (nav.page) 和過期時間。然後根據工作區 ID 及其攜帶的角色進行授權 — 切勿使用 cookie(iframe 沒有可用的來源;請參見下文)。

// Node (jose). The secret is your page's signing secret, shown ONCE at registration.
import { jwtVerify } from "jose";

const SECRET = new TextEncoder().encode(process.env.FLASH_EMBED_SECRET); // slotsec_…

export async function verifyFlashContext(token) {
  const { payload } = await jwtVerify(token, SECRET, {
    algorithms: ["HS256"],
    issuer: "flash",
    audience: "nav.page",
    requiredClaims: ["exp", "jti"],
    maxTokenAge: "120s",
  });
  // payload.ctx = { teamId, userId, role, pageType, locale }
  return payload.ctx; // → authorize the operator with this
}
// In your page: read ?flash_context=… , verify it server-side, then authorize.
const token = new URLSearchParams(location.search).get("flash_context");
// POST it to YOUR backend, verify with the snippet above, and gate the UI on
// ctx.teamId + ctx.role. Never trust it unverified, and never rely on cookies —
// the iframe is a null origin (see "Framing" below).

框架與安全

您的頁面必須實現的功能。

允許框架

您的頁面必須允許被 Flash 嵌入。 socialhub.ai — 不要傳送 X-Frame-Options: DENY;設定 Content-Security-Policy: frame-ancestors https://flash.socialhub.ai.

假設 null 來源

Flash 使用 allow-scripts 和 no-allow-same-origin 對 iframe 進行沙盒化,因此您的頁面運行在 null 來源:不使用 Flash cookie、儲存或父級 DOM。使用令牌進行身份驗證,而不是 cookie。

postMessage 已加入允許列表

主機僅接受來自您註冊的來源的 postMessage,且僅限透過您的 iframe 視窗傳送。請嚴格控制您的允許來源列表,並確保僅支援 https。

如果管理員的簽署金鑰洩露,請立即輪換使用(舊令牌將立即失效)。嵌入式頁面目前處於 搶先體驗階段,預設情況下每個工作區都處於關閉狀態,啟用後需透過 SocialHub 的第三方嵌入式安全審查。

與管理員介面保持一致

打造原生體驗,而非生硬附加。

您的頁面在 SocialHub 管理員內部呈現,因此它應該看起來像是它所屬的。管理是一個單一的、扁平的、淺色的主題,建立在一些代幣上——鏡像它們。 Flash 已經將您的頁麵包裝在帶有「第三方」徽章的標題視窗中,因此請勿添加您自己的頂欄、側邊欄或全頁鑲邊;只是渲染內容。

/* Starter tokens that match the SocialHub admin (flat, light, single-accent).
   Drop into your embedded page so it feels native, not bolted on. */
:root {
  /* type — the admin's three families */
  --font-sans:    "Inter", -apple-system, "Segoe UI", Roboto, sans-serif;
  --font-display: "Plus Jakarta Sans", "Inter", system-ui, sans-serif;
  --font-mono:    "JetBrains Mono", ui-monospace, monospace;

  /* surfaces — light theme only (the admin has no dark mode) */
  --bg:      #fafbfc;  /* page background */
  --surface: #ffffff;  /* cards / panels  */
  --subtle:  #f7fafc;  /* muted fills     */
  --border:  #e2e8f0;  /* hairlines       */

  /* text */
  --text:   #121c3d;   /* primary (brand navy) */
  --text-2: #4a5568;   /* secondary            */
  --muted:  #64748b;   /* muted                */

  /* accent — the admin's primary action colour */
  --accent:      #2ecc87;
  --accent-dark: #25b678;

  /* radius + 4px spacing scale + elevation */
  --radius: 8px; --radius-lg: 12px;
  --space-2: 8px; --space-3: 12px; --space-4: 16px; --space-6: 24px;
  --shadow-sm: 0 1px 3px rgba(0,0,0,.06), 0 1px 2px rgba(0,0,0,.04);
}

body { margin: 0; background: var(--bg); color: var(--text);
       font: 14px/1.5 var(--font-sans); }
h1, h2, h3 { font-family: var(--font-display); color: var(--text); }
.card { background: var(--surface); border: 1px solid var(--border);
        border-radius: var(--radius-lg); box-shadow: var(--shadow-sm);
        padding: var(--space-4); }
.btn  { background: var(--accent); color: #fff; border: 0; font-weight: 600;
        border-radius: var(--radius); padding: 8px 14px; cursor: pointer; }
.btn:hover { background: var(--accent-dark); }
code  { font-family: var(--font-mono); color: var(--text-2); }

無需您自己的 Chrome 瀏覽器

Flash 提供視窗框架和徽章。跳過應用程式的全域導覽/側邊欄/頁眉 — 僅渲染工具本身。

輕薄、扁平、單一強調色

僅限淺色主題(管理員無深色模式):#fafbfc 頁面上的白色卡片,極細的 #e2e8f0 邊框,一個綠色點綴 (#2ecc87)。

填充寬度,流動高度

使用全寬度並讓內容自由流動;主機將調整框架大小(大致為整個視口高度)並支援滾動-不要強制使用 100vh 或固定頁腳。

優雅降級

如果您沒有自行託管字體(Inter / Plus Jakarta Sans / JetBrains Mono),則會回退到系統 UI; Honor 偏好減少動態效果,並偏好淺色配色方案。

這些值追蹤當前的管理主題;將它們作為起點,並在重要的地方保留自己的品牌。我們的目標是讓頁面看起來像是 SocialHub 的一個介面,而不是進入不同產品的視窗。

一個完整的範例

一個功能齊全的嵌入式頁面,約 30 行程式碼即可完成。

一個可直接運作和註冊的極簡 Express 伺服器:它允許 Flash 建置框架、驗證身分令牌、根據操作員角色進行授權,並渲染一個作用域限定於工作區的工具。將管理員中的簽名金鑰複製到 FLASH_EMBED_SECRET 並執行它。

// server.js — a complete, minimal SocialHub Embedded Page (Express + jose).
// Register https://<host>/embed in Flash → Settings → Embedded Pages, allow the
// origin https://<host>, pick roles/tier, then copy the signing secret into env.
import express from "express";
import { jwtVerify } from "jose";

const app = express();
const SECRET = new TextEncoder().encode(process.env.FLASH_EMBED_SECRET); // slotsec_…
const FLASH = "https://flash.socialhub.ai";

app.get("/embed", async (req, res) => {
  // 1. Let ONLY Flash frame this page.
  res.setHeader("Content-Security-Policy", "frame-ancestors " + FLASH);

  // 2. Read + verify the identity token Flash appended (?flash_context=…).
  let ctx;
  try {
    const { payload } = await jwtVerify(String(req.query.flash_context || ""), SECRET, {
      algorithms: ["HS256"], issuer: "flash", audience: "nav.page",
      requiredClaims: ["exp", "jti"], maxTokenAge: "120s",
    });
    ctx = payload.ctx; // { teamId, userId, role, pageType, locale }
  } catch {
    return res.status(401).send("<p>Unauthorized — open this from inside SocialHub.</p>");
  }

  // 3. Authorize on the VERIFIED role (never on the raw request).
  const canEdit = ctx.role === "org_owner" || ctx.role === "org_admin";

  // 4. Render your tool, scoped to ctx.teamId. (Values are verified + opaque;
  //    still escape anything user-supplied you add.)
  res.send(
    '<!doctype html><meta charset="utf-8"><body style="font:14px system-ui;padding:24px">' +
    '<h1>Returns portal</h1>' +
    '<p>Workspace <code>' + ctx.teamId + '</code> · operator <code>' + ctx.userId +
    '</code> · role <b>' + ctx.role + '</b></p>' +
    (canEdit ? '<button>Process a return</button>' : '<p>Read-only for your role.</p>') +
    '</body>'
  );
});

app.listen(3000, () => console.log("Embedded page on :3000/embed"));

1 · 允許框架

frame-ancestors https://flash.socialhub.ai — 因此只有 SocialHub 管理員才能使用 iframe。

2 · 驗證令牌

讀取 ?flash_context,驗證 HS256 + 發行者 flash + 受眾導航頁面 + ≤120 秒過期時間;否則拒絕。

3 · 授權

Gate 功能在已驗證角色上(org_owner / org_admin / …),絕不在原始請求中。

4 · 渲染,範圍限定

為 ctx.teamId(即開啟工具的工作區)渲染您的工具。

然後在 Flash → 設定 → 嵌入頁面 中:新增 URL(例如 https://tools.yourapp.com/embed),列出同源,選擇可以開啟它的角色和級別,並將一次性簽名金鑰貼到伺服器環境中。現在,它將出現在您允許的運營商的 應用程式 下。