Ask2DoAsk2Do

Backend integration

The widget never holds your tenant key. Instead, your authenticated panel backend exchanges the long-term key for a short-lived JWT (15-minute TTL) that the widget uses for the WebSocket connection. This guarantees the tenant key only lives on servers you control.

The flow

  1. Logged-in user opens your admin panel.
  2. Widget loads, calls /api/ask2do/token on your backend.
  3. Your backend confirms the user's session and POSTs to cloud.ask2do.com/auth/token with { tenantKey, panelUser: { id, role } }.
  4. Cloud returns a 15-minute JWT.
  5. Your backend forwards the JWT to the widget.
  6. Widget opens its WebSocket using the JWT.

Endpoint contract

Your backend exposes one endpoint, e.g. POST /api/ask2do/token. It must:

Sample response from cloud

{
  "token": "eyJhbGciOiJFZERTQSIsImtpZCI6IjEifQ.eyJzdWIiOiI0MiIsInJvbGUiOiJhZG1pbiIs...",
  "expiresAt": "2026-05-02T13:55:00.000Z"
}

On success, cloud returns 200 with the JWT (~340 chars) and an absolute ISO expiration timestamp. On failure, you get 4xx with { error }.

Code samples

Pick your stack — same logic in every language. The widget calls whichever endpoint you mount.

app.post("/api/ask2do/token", requireLogin, async (req, res) => {
  const r = await fetch("https://cloud.ask2do.com/auth/token", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      tenantKey: process.env.ASK2DO_TENANT_KEY,      // server-only env
      panelUser: { id: String(req.user.id), role: req.user.role },
    }),
    signal: AbortSignal.timeout(5000),
  });
  if (!r.ok) return res.status(502).json({ error: "ask2do auth failed" });
  res.json(await r.json());
});

Security checklist

Where it goes wrong

SymptomCause
Cloud returns 401: invalid tenant keyTenant key is wrong, revoked, or paused. Verify in your portal.
Cloud returns 403: role not allowedYou sent panelUser.role outside admin/owner. Use only those values; junior users should not reach this code path.
Widget shows "invalid token" on connectEndpoint returned a malformed JWT, or the token expired before use. Confirm the response shape matches the sample above.

Next: widget

With the token endpoint live, drop the widget script tag into your panel HTML. Widget script tag →