Embed Kaelio in an iframe
Integrate Kaelio into your application as an embedded iframe with seamless single sign-on via postMessage.
This guide walks you through embedding Kaelio inside your application as an iframe. Users who are already authenticated in your app will be automatically signed into Kaelio — no login screen, no popup, no redirect.
Before you start
Make sure you have:
- A Kaelio URL configured for iframe embedding (provided
by the Kaelio team, e.g.
https://kaelio.example.com) - A JWT token from your identity provider — either an ID token (recommended) or an access token in JWT format
- Your identity provider registered with Kaelio as a federated login source (the Kaelio team handles this)
ID tokens are recommended because they are always JWTs and contain user identity claims (email, name). Access tokens work too, but only if your IdP issues them as JWTs — some providers return opaque tokens by default.
Step 1: Add the iframe
Place a Kaelio iframe in your application:
<iframe
id="kaelio"
src="https://kaelio.example.com"
allow="clipboard-write"
style="width: 100%; height: 100%; border: none;"
></iframe>Step 2: Handle token requests
When the iframe loads, Kaelio sends a kaelio:request-token
message to your window. Your app must respond with the
user's JWT.
Plain JavaScript
const KAELIO_ORIGIN = 'https://kaelio.example.com';
window.addEventListener('message', (event) => {
// Only respond to messages from Kaelio
if (event.origin !== KAELIO_ORIGIN) return;
if (event.data?.type !== 'kaelio:request-token') return;
// Get a fresh JWT from your auth library
const token = getIdToken(); // your implementation
const iframe = document.getElementById('kaelio');
iframe.contentWindow.postMessage(
{ type: 'kaelio:auth0-token', token },
KAELIO_ORIGIN,
);
});React
import { useEffect, useRef } from 'react';
const KAELIO_ORIGIN = 'https://kaelio.example.com';
function KaelioEmbed() {
const iframeRef = useRef<HTMLIFrameElement>(null);
useEffect(() => {
const handleMessage = (event: MessageEvent) => {
if (event.origin !== KAELIO_ORIGIN) return;
if (event.data?.type !== 'kaelio:request-token') return;
const token = getIdToken(); // your implementation
iframeRef.current?.contentWindow?.postMessage(
{ type: 'kaelio:auth0-token', token },
KAELIO_ORIGIN,
);
};
window.addEventListener('message', handleMessage);
return () => window.removeEventListener('message', handleMessage);
}, []);
return (
<iframe
ref={iframeRef}
src={KAELIO_ORIGIN}
allow="clipboard-write"
style={{ width: '100%', height: '100%', border: 'none' }}
/>
);
}Auth0 SPA SDK
If you use the Auth0 SPA SDK, obtain the raw ID token like this:
const claims = await auth0Client.getIdTokenClaims();
const token = claims.__raw; // the raw JWT stringAuth0 SPA applications do not have the Refresh Token grant
enabled by default. Without it, getTokenSilently() with
useRefreshTokens: true fails with "Grant type 'refresh_token'
not allowed for the client."
Ensure your Auth0 SPA app has these settings:
- Grant Types (Advanced Settings): Authorization Code, Implicit, Refresh Token
- Scopes: request
openid profile email offline_access(offline_accessis required for refresh tokens) - Allowed Web Origins: include all deployed URLs (not just localhost) — missing origins cause silent CORS failures on token refresh
Step 3: Listen for auth events (optional)
Kaelio sends status messages back to your window so you can react to authentication outcomes:
window.addEventListener('message', (event) => {
if (event.origin !== KAELIO_ORIGIN) return;
switch (event.data?.type) {
case 'kaelio:auth-ready':
console.log('Kaelio authenticated successfully');
break;
case 'kaelio:auth-error':
console.error('Kaelio auth failed:', event.data.error);
break;
}
});Message reference
All messages use window.postMessage with origin
validation on both sides.
| Direction | type | Payload | Description |
|---|---|---|---|
| Kaelio → Your app | kaelio:request-token | — | Kaelio needs a JWT token |
| Your app → Kaelio | kaelio:auth0-token | token: string | Send a fresh JWT to Kaelio (this message type is used regardless of your IdP) |
| Your app → Kaelio | kaelio:logout | — | Tell Kaelio to end the session |
| Kaelio → Your app | kaelio:auth-ready | — | Authentication succeeded |
| Kaelio → Your app | kaelio:auth-error | error: string | Authentication failed |
Kaelio may send kaelio:request-token more than once
during a session — for example, when the session needs to
be refreshed. Your listener should stay active for the
lifetime of the iframe.
Step 4: Handle logout
When a user logs out of your app, notify the Kaelio iframe to clear its session:
function logout() {
const iframe = document.getElementById('kaelio');
iframe.contentWindow.postMessage(
{ type: 'kaelio:logout' },
KAELIO_ORIGIN,
);
// Then proceed with your normal logout flow
}Without this, the Kaelio iframe retains its session tokens until they expire naturally.
Token requirements
The JWT you send must meet these criteria:
- Format: A signed JWT (three dot-separated base64 segments). Opaque tokens are not supported.
- Not expired: The token's
expclaim must be in the future. If your token might be stale, refresh it before sending. - Contains identity claims: At minimum, the token should
include
email(orpreferred_username). Additional claims likegiven_nameandfamily_nameare used to populate the user profile in Kaelio.
Security
- Always validate
event.originbefore processing any postMessage. Only respond to messages from the Kaelio origin you expect. - Tokens are held in memory only — they are never written
to
localStorage,sessionStorage, or cookies. - Kaelio validates
event.originon its side as well, ignoring messages from unexpected origins.
Troubleshooting
Kaelio shows a blank screen or loading spinner
The iframe is waiting for a token. Check that:
- Your
messageevent listener is registered before the iframe finishes loading - You are posting to the correct origin (must match the Kaelio URL exactly, including protocol)
- The message type is exactly
kaelio:auth0-token(not a typo)
kaelio:auth-error with "Token exchange failed"
The JWT was received but could not be verified. Common causes:
- The token has expired — refresh it before sending
- The token is opaque (not a JWT) — switch to using an ID token or configure your IdP to issue JWT access tokens
- The IdP is not registered with Kaelio — contact the Kaelio team
kaelio:request-token received but Kaelio still fails
Kaelio waits 10 seconds for your app to respond with the token. If your token retrieval is async (e.g. a network call to refresh), make sure it completes within this window.
Auth0: "Grant type 'refresh_token' not allowed"
Your Auth0 SPA application is missing the Refresh Token grant type. In the Auth0 dashboard, go to your app → Advanced Settings → Grant Types and enable Refresh Token.
Auth0: Silent token refresh fails with a CORS error
Your production domain is missing from the Allowed Web Origins list in your Auth0 app settings. Add all deployed URLs (including production) to that field.
Kaelio requests a token again mid-session
This is normal. When the session nears expiry, Kaelio automatically requests a fresh token. Your listener should always respond with a current, non-expired JWT.
Docs