Skip to content

Employer Benefits Widget

Embed Vitable's benefits administration dashboard into your application so employers can manage plans, enrollments, and coverage.

The Employer Benefits widget lets you embed Vitable’s benefits administration experience directly into your application. Employers can view employee enrollments, manage plan assignments, and monitor benefits coverage — all without leaving your platform.

Employer benefits administration dashboard

The widget renders inside an iframe and communicates with your app through a secure postMessage bridge. The @vitable-inc/drops SDK handles token management, message validation, and lifecycle events automatically.

Install the SDK:

Terminal window
npm install @vitable-inc/drops
import { VitableConnectProvider, EmployerBenefitsWidget } from "@vitable-inc/drops/react"
import type { AccessTokenResponse } from "@vitable-inc/drops/react"
const VITABLE_WIDGET_URL = "https://app.vitablehealth.com"
function fetchToken(): Promise<AccessTokenResponse> {
return fetch("https://my.backend.com/api/token", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ employer_id: "empr_abc123" }),
})
.then((res) => {
if (!res.ok) throw new Error(`Token fetch failed: ${res.status}`)
return res.json()
})
.then((data) => ({ token: data.token, expiresIn: data.expiresIn }))
}
function App() {
return (
<VitableConnectProvider
baseUrl={VITABLE_WIDGET_URL}
fetchToken={fetchToken}
contextKey="empr_abc123"
>
<EmployerBenefitsWidget
height="800px"
onReady={() => console.log("Widget ready")}
/>
</VitableConnectProvider>
)
}

Wrap your app with VitableConnectProvider, pass a fetchToken function that hits your backend, and drop in the EmployerBenefitsWidget. The SDK handles token refresh, secure iframe communication, and session lifecycle — you just wire up the data source.

baseUrl string required The Vitable widget server URL.

fetchToken () => Promise<{ token: string; expiresIn: number }> required Callback that returns a bound session token from your backend. Called on mount and automatically on refresh.

allowedOrigins string[] Origins allowed for postMessage communication. Defaults to the origin derived from baseUrl.

onError (code: string, message: string) => void Global error handler for all child widgets.

contextKey string Change this value to force a fresh token fetch (e.g., when switching employers).

theme VitableTheme Optional theme configuration to customize the widget’s appearance. See the Theming section for details.

The Employer Benefits widget requires a bound access token — a short-lived session token scoped to a specific employer. Bound tokens ensure the widget can only access data for the employer it was instantiated for, providing row-level security without exposing your API key to the browser.

Your server needs an endpoint that calls the Issue Access Token API to obtain a bound token for a given employer. The frontend will call this endpoint, so your API key stays server-side.

The request uses grant_type: "client_credentials" with a bound_entity of type "employer". The returned token is scoped exclusively to that employer.

import os
import requests
from flask import Flask, request, jsonify
app = Flask(__name__)
VITABLE_API_URL = os.environ["VITABLE_API_URL"]
VITABLE_API_KEY = os.environ["VITABLE_API_KEY"]
@app.post("/api/employer-token")
def create_employer_token():
employer_id = request.json.get("employer_id")
if not employer_id:
return jsonify(error="employer_id is required"), 400
response = requests.post(
f"{VITABLE_API_URL}/v1/auth/access-tokens",
headers={
"Authorization": f"Bearer {VITABLE_API_KEY}",
"Content-Type": "application/json",
},
json={
"grant_type": "client_credentials",
"bound_entity": {"type": "employer", "id": employer_id},
},
)
if not response.ok:
return jsonify(error="Token request failed"), response.status_code
data = response.json()
return jsonify(token=data["access_token"], expiresIn=data["expires_in"])

Place the EmployerBenefitsWidget anywhere inside the provider. It renders an iframe containing the employer benefits administration dashboard.

import { EmployerBenefitsWidget } from "@vitable-inc/drops/react"
function BenefitsAdmin() {
return (
<EmployerBenefitsWidget
height="800px"
onReady={() => console.log("Widget ready")}
onError={(code, message) => {
console.error("Widget error:", code, message)
}}
/>
)
}

width string | number — default "100%" Width of the iframe.

height string | number — default "600px" Height of the iframe.

className string CSS class applied to the iframe.

style CSSProperties Inline styles applied to the iframe.

onReady () => void Fired when the widget iframe has loaded and is ready to interact.

onEmployerBenefitsReady () => void Fired when the employer benefits view has fully initialized inside the iframe. Use this to know when the administration UI is visible and interactive.

onTokenExpired () => void Fired when the session token has expired. The SDK handles refresh automatically — use this for logging or UI updates.

onAuthError (code: string, message: string) => void Fired when authentication fails (e.g., invalid or revoked token).

onError (code: string, message: string) => void Fired on any widget error.

The SDK manages the full token lifecycle automatically:

  1. Initial fetchfetchToken is called when the provider mounts.
  2. Proactive refresh — The token is refreshed automatically 2 minutes before expiration. If the token lifetime is very short, the minimum refresh delay is 30 seconds.
  3. Retry with backoff — If a fetch fails, the SDK retries up to 3 times with exponential backoff (1s, 2s, 4s delays).
  4. Widget initialization — Once the iframe signals it’s ready, the SDK sends the token. The iframe acknowledges receipt before becoming interactive.
  5. Token updates — When the token is refreshed, the SDK pushes the new token to the iframe automatically.
  6. Expiration — If the token expires before a refresh succeeds, the iframe notifies the SDK, which triggers onTokenExpired and attempts a new fetch.

Changing the contextKey prop on the provider forces a full reset — the current token is discarded and fetchToken is called again. Use this when switching between employers:

<VitableConnectProvider
baseUrl={VITABLE_WIDGET_URL}
fetchToken={fetchToken}
contextKey={currentEmployerId}
>
<EmployerBenefitsWidget />
</VitableConnectProvider>