Skip to main content
This guide covers how to generate secure, time-limited tokens for embedding dashboards in your application.
This page is specifically about the multi-tenant iframe token flow. If you are embedding Papermap through @papermap/papermap, see React Components for the component integration flow and how it uses workspaceId, dashboardId, and backend token generation.

Overview

Iframe tokens allow you to securely embed Papermap dashboards in your application. Each token:
  • Is signed with HMAC-SHA256 for security
  • Has a configurable expiration time
  • Is specific to a tenant and dashboard
  • Can only be used for the specified dashboard

Token Structure

The token contains:
  • api_key_id: Your API key identifier
  • workspace_id: Your workspace ID
  • tenant_id: The tenant identifier
  • dashboard_id: The specific dashboard ID
  • valid_until: Unix timestamp when token expires
  • signature: HMAC signature for verification

Generating Iframe Tokens

This token generation is different from the one in the Basic Embedding section. The token generation in this section is for multi-tenant iframe embedding.
The tenant-aware dashboardId and backend provisioning model described here can still be relevant when your application uses React components, but this page documents the iframe-specific token flow.
import json
import base64
import time

def generate_iframe_token(
    tenant_id: str,
    workspace_id: str,
    dashboard_id: str,
    valid_until: Optional[int] = None
):
    # 1. Get tenant's dashboard
    tenant_dashboard = TenantDashboard.read(
        session=db,
        filter_by={"tenant_id": tenant_id}
    )

    if not tenant_dashboard:
        raise Exception("Dashboard not found for tenant")

    # 2. Set expiration (default 1 hour)
    if valid_until is None:
        valid_until = int(time.time()) + 3600

    # 3. Create HMAC signature
    payload = f"{workspace_id}{valid_until}"
    signature = hmac.new(
        SECRET_KEY.encode(),
        payload.encode(),
        hashlib.sha256
    ).hexdigest()

    # 4. Encode token
    token_data = {
        "api_key_id": API_KEY_ID,
        "workspace_id": workspace_id,
        "tenant_id": tenant_id,
        "dashboard_id": dashboard_id,
        "valid_until": valid_until,
        "signature": signature
    }

    token_json = json.dumps(token_data)
    encoded_token = base64.urlsafe_b64encode(token_json.encode()).decode()

    return {
        "token": encoded_token,
        "dashboard_id": dashboard_id,
        "expires_at": valid_until
    }

Using the Token in Frontend

Once you have the token, embed the dashboard using an iframe:
<iframe
  src="https://papermap.ai/embedded/dashboard?embedded-token={YOUR_TOKEN}"
  width="100%"
  height="600px"
  frameborder="0"
></iframe>

React Example

import React, { useState, useEffect } from "react";

function DashboardEmbed({ tenantId, workspaceId, dashboardId }) {
  const [token, setToken] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    async function fetchToken() {
      const response = await fetch("/api/dashboards/iframe-token", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ tenantId, workspaceId, dashboardId }),
      });

      const data = await response.json();
      setToken(data.token);
      setLoading(false);
    }

    fetchToken();
  }, [tenantId, workspaceId, dashboardId]);

  if (loading) return <div>Loading dashboard...</div>;

  return (
    <iframe
      src={`https://papermap.ai/embedded/dashboard?embedded-token=${token}`}
      width="100%"
      height="600px"
      frameBorder="0"
      title="Dashboard"
    />
  );
}

Workflow Diagram

1. Client → Request Embed Token
   POST /api/v1/dashboards/iframe-token
   {
     "tenant_id": "org-123",
     "workspace_id": "workspace-456"
   }

2. Your API → Generate Token
   - Lookup dashboard_id for tenant
   - Create HMAC signature
   - Encode as base64 token

3. Return Token to Client
   {
     "token": "eyJhcGlfa2V5X2lkIjoi...",
     "dashboard_id": "dashboard-789",
     "expires_at": 1700000000
   }

4. Frontend → Embed in Iframe
   <iframe src="https://papermap.ai/embedded/dashboard?embedded-token=eyJhcGlfa2V5X2lkIjoi..." />

Token Refresh

Since tokens expire, implement a refresh mechanism:
class DashboardTokenManager {
  private token: string | null = null;
  private expiresAt: number | null = null;

  async getToken(tenantId: string, workspaceId: string, dashboardId: string) {
    // Check if token is still valid (with 5 min buffer)
    if (
      this.token &&
      this.expiresAt &&
      this.expiresAt > Date.now() / 1000 + 300
    ) {
      return this.token;
    }

    // Fetch new token
    const response = await fetch("/api/dashboards/iframe-token", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ tenantId, workspaceId, dashboardId }),
    });

    const data = await response.json();
    this.token = data.token;
    this.expiresAt = data.expires_at;

    return this.token;
  }
}

Security Considerations

Always verify tenant ownership before generating tokensNever generate a token without verifying that the requesting user has access to the tenant’s dashboard.

Tenant Access Verification

# Good - Verify tenant access
if current_user["organization_id"] != tenant_id:
    raise HTTPException(status_code=403, detail="Access denied")

# Then generate token
token = generate_iframe_token(tenant_id, workspace_id, dashboard_id)

Token Expiration

  • Advisable: 1 hour (3600 seconds)
  • Configurable based on your security requirements
  • Shorter expiration = more secure, but requires more frequent refreshes
  • Longer expiration = better UX, but higher security risk

Best Practices

  1. Generate tokens on-demand: Don’t pre-generate and store tokens
  2. Use HTTPS: Always serve your application over HTTPS
  3. Implement token refresh: Refresh tokens before they expire
  4. Log token generation: Monitor for unusual access patterns
  5. Rate limit: Prevent abuse by rate limiting token generation

Next Steps

API Endpoints

Set up REST API endpoints for dashboard operations

Security Best Practices

Learn about security considerations for production