How to integrate your app as iframe in B2CORE

Learn how to integrate a third-party web application into B2CORE as an iframe, including server configuration, theme and language synchronization, and JWT-based authentication via the postMessage API

B2CORE supports embedding third-party web applications directly into the client UI via an iframe. When a custom menu item is configured with the Iframe behavior, B2CORE loads your application inside the interface, providing a seamless experience for clients without leaving the platform.

This guide covers two aspects: configuring the custom menu item in the B2CORE Back Office, and preparing your application to work correctly inside the B2CORE iframe.

Prerequisites

Before proceeding, ensure the following:

Step 1. Configure your server to allow iframe embedding

By default, most web servers and frameworks prevent pages from being embedded in iframes on other domains. To allow B2CORE to load your application, you must configure the appropriate HTTP response headers on your server.

You need to set one or both of the following headers:

Content-Security-Policy

The Content-Security-Policy header with the frame-ancestors directive controls which origins are allowed to embed your page. Set this header to include your B2CORE instance origin:

Content-Security-Policy: frame-ancestors 'self' https://portal.example.com

Replace https://portal.example.com with the actual origin of the B2CORE UI used by your clients. You can specify multiple origins separated by spaces if your application needs to be embedded across several B2CORE instances.

For more information, refer to the Content-Security-Policy documentation on MDN.

X-Frame-Options

The X-Frame-Options header is an older mechanism that achieves a similar result. If you use it, set it to ALLOW-FROM with your B2CORE origin:

X-Frame-Options: ALLOW-FROM https://portal.example.com

The X-Frame-Options: ALLOW-FROM directive is not supported by all browsers. It is recommended to use the Content-Security-Policy header with the frame-ancestors directive as the primary mechanism and include X-Frame-Options only as a fallback for older clients.

For more information, refer to the X-Frame-Options documentation on MDN.

Step 2. Add a custom menu item in the B2CORE Back Office

To make your application accessible to clients, add a custom menu item with the iframe behavior:

Navigate to Promotion > Menu.

Click the eye icon in the General row to view the menu tree.

Click +Create in the upper-right page corner.

Fill in the required fields:

  • In the Name field, enter a unique name for the menu item.
  • In the Caption field, enter the label that clients will see in the menu.
  • In the External URL field, specify the URL of your application.
  • In the Icon field, specify the URL of an SVG icon (16x16 px, monochrome, transparent background).
  • In the Custom Behavior dropdown, select Iframe.

Configure optional restrictions if needed:

  • To limit visibility to specific verification levels, select the appropriate levels in the Verification Level Allowance dropdown.
  • To limit visibility to specific client types, select the corresponding types in the Client Type Allowance dropdown.

Enable the Visible checkbox to make the item appear in the menu.

Click Save to add the custom menu item.

When clients click this menu item, your application will load inside an iframe within the B2CORE UI.

Two other behavior options are available for custom menu items: Same tab (opens the URL in the current browser tab) and New tab (opens the URL in a new browser tab). The iframe option is the only one that embeds your application within the B2CORE interface.

Step 3 (optional). Implement the postMessage communication protocol

If your application needs to identify the authenticated B2CORE user, match the B2CORE UI theme, or follow the language selected by the user, you can implement the postMessage communication protocol described below. This step is optional — if your application does not require user authentication, theme synchronization, or language synchronization, you can skip it.

Message reference

Messages from your application to B2CORE

Message typeDescriptionPayload
embed-iframe-readySignals that the iframe has loaded and is ready to receive messages.{ type: "embed-iframe-ready" }
embed-request-jwt-tokenRequests a JWT authentication token from B2CORE.{ type: "embed-request-jwt-token" }

Messages from B2CORE to your application

Message typeDescriptionPayload
embed-theme-changeSent whenever the B2CORE UI theme changes (and once immediately after embed-iframe-ready).{ type: "embed-theme-change", theme: "dark-theme" | "light-theme" }
embed-language-changeSent whenever the B2CORE UI language changes (and once immediately after embed-iframe-ready).{ type: "embed-language-change", lang: "<language-code>" }
embed-jwt-tokenSuccessful response to a token request.{ type: "embed-jwt-token", token: "<jwt-string>", expiresAt: "<ISO-8601>" }
embed-jwt-token-errorError response when token generation fails.{ type: "embed-jwt-token-error", error: "<error-message>" }

The lang field contains a lowercase ISO 639-1 language code (for example, en, de, ar) matching the language currently selected in the B2CORE UI.

Communication flow

The sequence of messages between your application and B2CORE follows this pattern:

sequenceDiagram
    participant App as Your App (iframe)
    participant B2CORE as B2CORE (host)

    App->>B2CORE: embed-iframe-ready
    B2CORE-->>App: embed-theme-change (initial theme)
    B2CORE-->>App: embed-language-change (initial language)
    App->>B2CORE: embed-request-jwt-token
    alt success
        B2CORE-->>App: embed-jwt-token
    else failure
        B2CORE-->>App: embed-jwt-token-error
    end
    Note over App,B2CORE: Token nears expiry...
    App->>B2CORE: embed-request-jwt-token
    B2CORE-->>App: embed-jwt-token
    Note over App,B2CORE: User toggles theme...
    B2CORE-->>App: embed-theme-change
    Note over App,B2CORE: User changes language...
    B2CORE-->>App: embed-language-change

Signal readiness. When your page finishes loading, send the embed-iframe-ready message to B2CORE. This tells the host that your application is ready to receive data.

Receive the current theme. B2CORE responds with embed-theme-change containing the current theme (dark-theme or light-theme). Apply the theme to your UI. You will also receive this message whenever the user switches themes.

Receive the current language. B2CORE also responds with embed-language-change containing the language code currently selected in the B2CORE UI (for example, en or ar). Apply the corresponding locale to your UI. You will receive this message again whenever the user changes the language.

Request an authentication token. When you need to identify the current user, send embed-request-jwt-token. B2CORE responds with either embed-jwt-token (containing the JWT and its expiration time) or embed-jwt-token-error if token generation fails.

Refresh the token before expiry. The JWT has an expiration time provided in the expiresAt field (ISO 8601 format). Request a new token before the current one expires to maintain uninterrupted access.

Code example

A complete JavaScript snippet you can include in your application:

(function () {
  const B2CORE_ORIGIN = '*'; // Replace with your B2CORE instance origin for production

  let currentToken = null;
  let tokenRefreshTimer = null;

  // --- Send a message to B2CORE ---
  function sendToHost(message) {
    window.parent.postMessage(message, B2CORE_ORIGIN);
  }

  // --- Handle incoming messages from B2CORE ---
  function handleMessage(event) {
    const data = event.data;
    if (!data || !data.type) return;

    switch (data.type) {
      case 'embed-theme-change':
        applyTheme(data.theme);
        break;

      case 'embed-language-change':
        applyLanguage(data.lang);
        break;

      case 'embed-jwt-token':
        handleToken(data.token, data.expiresAt);
        break;

      case 'embed-jwt-token-error':
        console.error('Token error from B2Core:', data.error);
        break;
    }
  }

  // --- Apply theme to your UI ---
  function applyTheme(theme) {
    document.documentElement.setAttribute('data-theme', theme);
  }

  // --- Apply language to your UI ---
  function applyLanguage(lang) {
    document.documentElement.setAttribute('lang', lang);
  }

  // --- Handle received JWT token ---
  function handleToken(token, expiresAt) {
    currentToken = token;

    // Schedule a refresh 2 minutes before expiry
    if (tokenRefreshTimer) {
      clearTimeout(tokenRefreshTimer);
    }

    const refreshIn = new Date(expiresAt).getTime() - Date.now() - 2 * 60 * 1000;

    if (refreshIn > 0) {
      tokenRefreshTimer = setTimeout(requestToken, refreshIn);
    } else {
      requestToken();
    }
  }

  // --- Request a JWT token from B2CORE ---
  function requestToken() {
    sendToHost({ type: 'embed-request-jwt-token' });
  }

  // --- Initialize ---
  window.addEventListener('message', handleMessage);
  sendToHost({ type: 'embed-iframe-ready' });
  requestToken();
})();

Replace the B2CORE_ORIGIN value with the actual origin of your B2CORE instance (for example, 'https://portal.example.com') in production. Using '*' is acceptable during development only, as it allows any origin to communicate with your application.

TypeScript type definitions

If your application is built with TypeScript, you can use the following type definitions:

type EmbedTheme = 'dark-theme' | 'light-theme';

// Messages: Your App -> B2CORE
interface EmbedIframeReadyMessage {
  readonly type: 'embed-iframe-ready';
}

interface EmbedRequestJwtTokenMessage {
  readonly type: 'embed-request-jwt-token';
}

type EmbedOutboundMessage = EmbedIframeReadyMessage | EmbedRequestJwtTokenMessage;

// Messages: B2CORE -> Your App
interface EmbedThemeChangeMessage {
  readonly type: 'embed-theme-change';
  readonly theme: EmbedTheme;
}

interface EmbedLanguageChangeMessage {
  readonly type: 'embed-language-change';
  readonly lang: string; // ISO 639-1 code, e.g. "en", "de", "ar"
}

interface EmbedJwtTokenMessage {
  readonly type: 'embed-jwt-token';
  readonly token: string;
  readonly expiresAt: string; // ISO 8601
}

interface EmbedJwtTokenErrorMessage {
  readonly type: 'embed-jwt-token-error';
  readonly error: string;
}

type EmbedInboundMessage =
  | EmbedThemeChangeMessage
  | EmbedLanguageChangeMessage
  | EmbedJwtTokenMessage
  | EmbedJwtTokenErrorMessage;

Step 4 (optional). Validate the JWT token

The JWT token issued by B2CORE can be validated against the JSON Web Key Set (JWKS) endpoint exposed by the B2CORE API (Admin Panel backend). This is typically the API/admin domain, not the client-facing UI domain:

https://api.<your-domain>/.well-known/jwks.json

Use this endpoint to retrieve the public keys needed to verify the token signature. Most JWT libraries support JWKS-based validation out of the box.

For manual inspection during development, you can decode and verify JWT tokens using the JWT decoder tool.

Last updated on

On this page