SocialHub.AI

Centro de desarrolladores · Ampliar la plataforma

Páginas integradas: añade tus propias herramientas al panel de administración.

Registre su propia página alojada en https y se convertirá en un elemento de menú autorizado dentro del administrador de SocialHub: un iframe de página completa en espacio aislado. Flash entrega a su página un token de identidad sin PII de corta duración para que pueda autorizar al operador sin que vuelva a iniciar sesión.

Acceso temprano · detrás del módulo de extensibilidad abierta

Cómo funciona

Cuatro pasos desde tu URL hasta un elemento de menú.

01

Registra tu página

Un administrador del espacio de trabajo agrega tu URL HTTPS en Flash → Configurar → Páginas incrustadas, con una etiqueta de menú, una lista de orígenes permitidos y los roles/niveles que pueden abrirla.

02

Copiar la clave de firma

Flash muestra una clave secreta de firma una sola vez (slotsec_…). Guárdalo como secreto de servidor en tu aplicación; con él verificarás el token de identidad de Flash.

03

Flash enmarca tu página

La página aparece como un elemento del menú lateral en Aplicaciones para operadores autorizados; al abrirla, se carga la URL en un iframe aislado con ?flash_context=<token> añadido.

04

Verificar + autorizar

Lee el token, verifícalo en el servidor (HS256) y controla la interfaz de usuario según el ID del espacio de trabajo y el rol de operador que contiene.

El token de identidad

De corta duración, sin información personal identificable, con firma digital confidencial.

En cada renderizado, Flash agrega ?flash_context=<JWT> a su URL. Es un JWT HS256 firmado con el secreto de tu página (por lo que tú, no la plataforma, eres el ancla de confianza), válido durante un máximo de 120 segundos y no contiene datos personales de los miembros, solo la identificación del espacio de trabajo y la identificación opaca del operador + rol aproximado, para que puedas autorizar.

{
  "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
}

Verifícalo

Confía en el token, no en la solicitud.

Verifica la firma, el emisor (flash), la audiencia (nav.page) y la fecha de vencimiento en tu servidor. Luego, autoriza mediante el ID del espacio de trabajo y el rol que conlleva; nunca mediante cookies (el iframe no tiene un origen utilizable; ver más abajo).

// 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).

Encuadre y seguridad

Qué debe hacer tu página.

Permitir el marco

Tu página debe permitir la incrustación en Flash.socialhub.ai — no enviar X-Frame-Options: DENY; establecer Content-Security-Policy: frame-ancestors https://flash.socialhub.ai.

Suponer un origen nulo

Flash aísla el iframe con permisos de scripts permitidos y sin permisos de mismo origen, de modo que tu página se ejecuta en un origen null: sin cookies Flash, almacenamiento ni DOM principal. Autentícate con el token, no con cookies.

postMessage está permitido.

El anfitrión solo acepta postMessage desde los orígenes que usted registró y solo desde su ventana iframe. Mantenga su lista de orígenes permitidos ajustada y solo https.

Rote la clave de firma del administrador si se expone (los tokens antiguos dejan de verificarse inmediatamente). Las páginas integradas están en acceso anticipado (), desactivadas por defecto en cada espacio de trabajo, y su activación para producción está sujeta a la revisión de seguridad de integración de terceros de SocialHub.

Apariencia del administrador

Se integra de forma nativa, no como un añadido externo.

Su página se muestra dentro del administrador de SocialHub, por lo que debería verse como si perteneciera. El administrador es un tema único, plano y ligero construido sobre unos pocos tokens: reflejelos. Flash ya envuelve su página en una ventana titulada con una insignia de "Tercero", así que no agregue su propia barra superior, barra lateral o Chrome de página completa; simplemente renderice el contenido.

/* 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); }

Sin personalización

Flash proporciona el marco de la ventana y la insignia. Omite la navegación, la barra lateral y el encabezado globales de tu app: renderiza solo la herramienta.

Ligero, plano, un solo acento

Solo tema claro (el panel de administración no tiene modo oscuro): tarjetas blancas en una página #fafbfc, bordes finos #e2e8f0, un detalle verde (#2ecc87).

Llena el ancho, fluye la altura.

Utilice todo el ancho y permita que el contenido fluya; el host ajusta el tamaño del marco (aproximadamente a la altura completa de la ventana gráfica) y el desplazamiento; no fuerce sus propios pies de página de 100vh ni fijos.

Degradación controlada

Las fuentes (Inter / Plus Jakarta Sans / JetBrains Mono) recurren a system-ui si no las aloja usted mismo; respeta las preferencias de movimiento reducido y esquema de color claro.

Estos valores rastrean el tema de administración actual; trátelos como un punto de partida y mantenga su propia marca donde sea importante. El objetivo es una página que se lea como una superficie con SocialHub, no como una ventana a un producto diferente.

Un ejemplo completo

Una página incrustada funcional en ~30 líneas.

Un servidor Express mínimo que puede ejecutar y registrar tal cual: permite que Flash lo enmarque, verifica el token de identidad, autoriza según el rol del operador y genera una herramienta con ámbito en el espacio de trabajo. Copie el secreto de firma del administrador en FLASH_EMBED_SECRET y ejecútelo.

// 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 · Permitir el marco

frame-ancestors https://flash.socialhub.ai: solo el administrador de SocialHub puede incluirlo en un iframe.

2 · Verificar el token

Leer ?flash_context, verificar HS256 + flash del emisor + página de navegación de la audiencia + caducidad ≤120 s; rechazar en caso contrario.

3 · Autorizar

Las funciones se aprueban con el rol VERIFICADO (org_owner / org_admin / …), nunca en la solicitud original.

4 · Renderizado, con alcance

Renderice su herramienta para ctx.teamId: el espacio de trabajo en el que se abrió.

Luego, en Flash → Configuración → Páginas integradas: agregue la URL (por ejemplo, https://tools.yourapp.com/embed), enumere ese mismo origen, elija las funciones y el nivel que pueden abrirlo y pegue el secreto de firma único en el entorno de su servidor. Ahora aparece en Aplicaciones para los operadores que usted permitió.