Embed SignStack into Your App
This guide is the practical companion to Embedding Components. You'll wire up a working signing flow inside your own app — server-side embed-token issuance, browser-side mounting of the web component, and event handling.
The same pattern applies to all four components (<ss-signing-embed>, <ss-resource-editor>, <ss-workflow-editor>, <ss-workflow-monitor>); the differences are which intent you mint a token for and which props each component takes.
The Pattern
- Your server holds the long-lived API key. When a logged-in user wants to access an embedded surface (e.g. sign a document), your server calls SignStack's
POST /v1/orgs/{orgId}/namespaces/{namespaceKey}/auth/embedto mint a short-lived embed token scoped to that user + intent. - Your server returns the token to the browser.
- The browser mounts the SignStack web component and passes the token in.
- The component uses the token for its own API calls; you listen for events (
signed,declined,session-expired).
Step 1: Load the Web Components Bundle
Drop the SignStack web components script into your app's HTML. Once loaded, the four custom elements register themselves and you can use them anywhere in your DOM:
<script type="module" src="https://signstack.ai/web-components.js"></script>
Step 2: Mint an Embed Token (Server-Side)
For an embedded signing flow:
curl -X POST https://api.signstack.ai/v1/orgs/{orgId}/namespaces/{namespaceKey}/auth/embed \
-H "Authorization: Bearer <ACCESS_TOKEN>" \
-H "Content-Type: application/json" \
-d '{
"intent": "signing_session",
"workflowId": "b6f3a8d2-1c4e-4b9a-a7f3-2e8c1d5a9b4f",
"stepKey": "consultant_signs",
"expiresIn": 900,
"allowedOrigins": ["https://yourapp.com"],
"context": {
"recipientEmail": "jane@example.com",
"recipientName": "Jane Doe"
}
}'
Response:
{
"accessToken": "eyJhbGciOi…",
"orgId": "f1e2d3c4-b5a6-4789-a012-345678901234",
"tokenType": "Bearer",
"expiresIn": 900,
"expiresAt": "2026-04-19T16:30:00.000Z",
"scopes": ["..."],
"subject": { "type": "embed", "id": "8a9b0c1d-2e3f-4a5b-6c7d-8e9f0a1b2c3d", "orgId": "f1e2d3c4-b5a6-4789-a012-345678901234" },
"resources": [{ "type": "workflow", "id": "b6f3a8d2-1c4e-4b9a-a7f3-2e8c1d5a9b4f", "actions": ["sign"] }]
}
accessToken is what the browser receives. Pass allowedOrigins to scope the token to your domain (browser CORS protection); set expiresIn to the shortest reasonable window for your UX.
The full intent catalog and security rationale lives in Securely Embedding Components.
Step 3: Mount the Component (Browser-Side)
<ss-signing-embed
workflow-id="b6f3a8d2-1c4e-4b9a-a7f3-2e8c1d5a9b4f"
embed-token="eyJhbGciOi…"
org-id="f1e2d3c4-b5a6-4789-a012-345678901234"
namespace-key="acme-prod"
></ss-signing-embed>
In React (custom elements work natively):
function SigningPage({ workflowId, embedToken, orgId, namespaceKey }) {
const ref = useRef(null);
useEffect(() => {
const el = ref.current;
const onSigned = (e) => console.log('signed', e.detail);
const onDeclined = (e) => console.log('declined', e.detail);
const onExpired = () => refetchEmbedToken();
el.addEventListener('signed', onSigned);
el.addEventListener('declined', onDeclined);
el.addEventListener('session-expired', onExpired);
return () => {
el.removeEventListener('signed', onSigned);
el.removeEventListener('declined', onDeclined);
el.removeEventListener('session-expired', onExpired);
};
}, []);
return (
<ss-signing-embed
ref={ref}
workflow-id={workflowId}
embed-token={embedToken}
org-id={orgId}
namespace-key={namespaceKey}
/>
);
}
The component picks up your app's CSS for typography, colors, and surrounding chrome — no theme-override config to manage.
Step 4: Handle Token Expiry
Embed tokens are deliberately short-lived. When one expires, the component fires a session-expired event. Your handler should call your server to mint a fresh token and update the component's embed-token attribute. The component will reconnect with the new token.
Component Reference
All four components share embed-token, org-id, namespace-key. Per-component specifics:
| Component | Intent (token mint) | Required props | Key events |
|---|---|---|---|
<ss-signing-embed> |
signing_session |
workflow-id |
signed, declined, signing-error, session-expired, closed |
<ss-workflow-editor> |
workflow_editing |
workflow-id |
saved, published, session-expired |
<ss-workflow-monitor> |
workflow_monitoring |
(uses namespace-scoped list) | workflow-selected, session-expired |
<ss-resource-editor> |
resource_editing |
resource-key, resource-kind, version? |
saved, published, session-expired |
(The signing component runs the actual signature capture in a sandboxed context for security; the others render inline within your DOM.)
Common Pitfalls
- Forgetting
allowedOrigins— Tokens are usable from any browser without it. Always pass your app's exact origin(s). - Reusing tokens across users — Each token is scoped to one user/intent. Mint per-session; don't cache server-side.
- Long
expiresIn— Default to 15 minutes. Long-lived embed tokens defeat the security model. - Treating events as authoritative — Always confirm signing completion via webhooks or workflow status; the browser event is a UX signal, not a source of truth.
Related
- Embedding Components — The conceptual overview and component catalog
- Securely Embedding Components (Session Tokens) — Token mechanics, intent catalog, security model
- Webhooks — Authoritative signal that signing completed
