Web-based interoperability

You can create web content that participates in OpenFin interoperability workflows when loaded in a web browser. Such workflows include context sharing and intents, using the OpenFin Interop, FDC3 and Channel APIs. This functionality is enabled by the Core Web package (published as Web Interop for v37 only).

The Core Web package allows web content that runs in a standard browser tab or a progressive web app (PWA) on a tablet to interact directly with other content in that browser tab or PWA. For example, a user could:

  • Select a contact from a view in their web browser.

  • Watch as the contact's portfolio appears in another view in that web browser tab through context sharing.

The Core Web package enables cross-site communication in a "platform-like" environment within a single web browser tab.

To accomplish this, Core Web requires the platform owner to host the following on the same domain:

  • The top-level app that embeds other content

  • The Web Broker server components described below

Any iframe running under such a top-level app can connect to the page's Web Broker of the page and interoperate, regardless of origin.

There are some limitations to what Core Web is able to accomplish in a browser:

  • Core Web does not connect web pages that exist in separate native web browser tabs. Core Web cannot enable communication between native web browser tabs in a way that conflicts with web browsers' privacy sandboxes.

  • Core Web works with cross-site and cross-origin websites so long as the Web Broker and the top-level app exist in the same origin.

    • Examples of cross-site websites: example.com and ejemplo.com, or compare.com and contrast.com

    • Examples of cross-origin websites: docs.example.com, support.example.com

OpenFin minimizes the differences between the interoperability APIs supported on the desktop and the web. In most cases, code that works with the desktop Interop APIs also works with Core Web, though some changes may be needed.

Core Web interoperability for content developers

If you are a developer who is building content applications which use the OpenFin APIs, the default entry point of the Core Web package provides a connect function. This is designed to complement the type definitions found in @openfin/core.

First steps for content developers

To install @openfin/core-web, run the following command:

npm install @openfin/core-web -S

Core Web is framework agnostic; it is designed to work with any UI framework you choose for building your web content.

Connect to a Web Broker

An @openfin/core-web Web Broker is a piece of hosted infrastructure that you can connect to from a web site in order to interact with other content connected to the same Web Broker. A Web Broker is responsible for deciding whether you can connect to it, and connecting you to other applications via OpenFin's Interop and Channels APIs.

When you connect to a @openfin/core-web broker with a specific URL, it returns a fin connection.

Example: Basic connection setup

import { connect } from '@openfin/core-web';

const brokerUrl = 'http://example.com/web-broker';

(async () => {
    // Connect to the OpenFin Web Broker.
    const fin = await connect({ options: { brokerUrl }});

    // You may now use the `fin` object. In this case, use it to connect to a channel.
    const channelClient = await fin.InterapplicationBus.Channel.connect('some channel name');
})();

Set a timeout

You can use the timeout option (in milliseconds) to specify to abandon the connection after a set amount of time.

The example below shows how to set up a 30-second timeout.

Example: Set a timeout

// This connect call throws if a connection is not established within 30 seconds.
await connect({ options: { brokerUrl, timeout: 30000 }});

Set up an Interop connection

You can configure an Interop connection to automatically set up an Interop client. You can then access the client via the fin.me.interop namespace.
You must specify a Provider ID. An example is shown below:

Example: Connect to an Interop Broker

// Specify an interopConfig with a specific provider ID to initialize the `fin.me.interop` client on connection.
const fin = await connect({ options: { brokerUrl, interopConfig: { providerId: 'PROVIDER_ID' }}});

// fin.me.interop is an InteropClient connected to the `PROVIDER_ID` InteropBroker.
fin.me.interop.addContextHandler((context) => console.log('received context'));

Specify an initial context group

By default OpenFin's Interop Client API does not select a context group. The following example illustrates setting up an initial context group during connection.

Example: Join a default context group

// Specify an interopConfig with a specific provider ID and a context group to initialize the `fin.me.interop` client on connection.
const fin = await connect({ options: { brokerUrl, interopConfig: { providerId: 'provider-id', currentContextGroup: 'red' }}});

// The fin.me.interop client adds a context handler which receives updates published on the `red` context group.
fin.me.interop.addContextHandler((context) => console.log('received context'));

Initialize FDC3

This library does not produce any global variables. To leverage FDC3, you can use the .getFDC3 or .getFDC3Sync APIs of a connected InteropClient. Note that with an Interop configuration provided in connect, fin.me.interop is instantiated as an InteropClient.

Supported versions for fdc3 are 1.2 or 2.0.

Example: Create an FDC3 client

import { connect } from '@openfin/core-web';

const brokerUrl = 'http://example.com/web-broker';

// Specify an interopConfig with a specific provider ID and a context group to initialize the `fin.me.interop` client on connection.
const fin = await connect({ options: { brokerUrl, interopConfig: { providerId: 'PROVIDER_ID', currentContextGroup: 'red' }}});

// Set window.fdc3 to an FDC3 2.0 DesktopAgent which is connected to the `PROVIDER_ID` InteropBroker on the `red' channel.
window.fdc3 = fin.me.interop.getFDC3Sync('2.0');

FDC3 support in Core Web covers the same interfaces and methods as the Core desktop library, but neither library implements the complete FDC3 specification.
FDC3 functionality that is not supported includes the following:

  • Returning IntentResult objects
  • PrivateChannel interface
  • Default implementation of IntentResolution

Context-aware connections and connection inheritance

The @openfin/core-web API has been designed to support inheritance of brokerUrls and Interop configurations if your content is running as a view within an OpenFin Layout. This allows content developers to develop platform-agnostic experiences and ensure that they are able to interact with other content connected to the same Web Broker.

Core Web interoperability for platform developers

If you are a Platform owner who wishes to include OpenFin's web capabilities in your platform, a few steps are required. This section guides you through the process of setting up an environment.

First steps for platform developers

Ensure that @openfin/core-web is installed by running the following command:

npm i @openfin/core-web -S

Host the @openfin/core-web shared worker

An @openfin/core-web/shared-worker entry point is included in this package's distribution. This is a non-customizable, standalone piece of JavaScript that must be hosted on your server for @openfin/core-web to function.

The shared-worker file has already been bundled, which means you just need to host it on a web server on a known URL.

Build a Web Broker

A Web Broker is an HTML page, loaded as a hidden iframe by clients. The Web Broker must be hosted in the same origin as the @openfin/core-web/shared-worker. This iframe acts as a gatekeeper to the shared-worker and therefore must be hosted on the same domain.

In order to build a Web Broker, the following requirements must be met:

  • You must host the @openfin/core-web/shared-worker bundle on a domain (for example https://www.example.com/mysharedworker.js).

  • You must host a web broker page on that same domain (for example, https://www.example.com/web-broker).

  • The web broker page must call init from @openfin/core-web/iframe-broker with the URL of the shared worker.

// This code runs on https://www.example.com/web-broker
import {init} from '@openfin/core-web/iframe-broker;

const sharedWorkerUrl = 'https://www.example.com/mysharedworker.js';

await init({sharedWorkerUrl})

Here is a basic example of hosting a Web Broker:

Example: Set up a basic Web Broker

First, host @openfin/core-web/shared-worker at /openfin-shared-worker.js

File: iframe-broker.html

<html>
    <body>
        <script src ="iframe-broker.js"></script>
    </body>
</html>

File: iframe-broker.js

import { init } from '@openfin/core-web/iframe-broker';

init({
    sharedWorkerUrl: `${location.origin}/openfin-shared-worker.js`
});

Build a host page

A host page is an HTML page that includes the web broker as a hidden iframe as well as other iframes for the content apps.

In order to host a Core Web Interop Provider, the following requirements must be met:

  • You must host the page on the same domain as the web broker (for example, https://www.example.com/web-broker).

  • The page must call connect from @openfin/core-web with the URL of the web broker.

  • The page must call fin.Interop.init to create an Interop Broker.

Here is a basic example of a host page:

Example: Set up a basic host page

File: provider.html

<html>
    <body>
        <script src ="provider.js"></script>

        <!-- Optional content apps -->
        <iframe src="example.html"></iframe>
    </body>
</html>

File: provider.js

import { connect } from '@openfin/core-web';

const brokerUrl = 'https://www.example.com/web-broker';

(async () => {
    // Connect to the OpenFin Web Broker.
    const fin = await connect({ options: { brokerUrl }});

    // You may now use the `fin` object. In this case, we will initiate an interop broker
    await fin.Interop.init('PROVIDER_ID');

})();

Advanced Web Broker configurations

Reject connections

As an owner of an Iframe Broker, your first defense against attacks is existing web security tools such as the frame-ancestors CSP rule, to prevent content that you don't expect from connecting to the broker.

You can implement your own custom logic for the rejectConnections utility function. If neither init or rejectConnection is invoked, an embedding client could hang indefinitely.

Example: Reject a cross-origin connection using @openfin/core-web/iframe-broker

import { init, rejectConnections } from '@openfin/core-web/iframe-broker';

// If the origins do not match.
if (new URL(document.referrer).origin !== location.origin) {
    rejectConnections({
        reason: 'Connections from this domain are not supported' // Reason allows an error to be returned to the connecting client.
    })
} else {
    init({
        sharedWorkerUrl: `${location.origin}/openfin-shared-worker.js`
    });
}

Experimental: Enable cross-tab support

By default, @openfin/core-web disables the sharing of connections across browser tabs. However, this feature can be enabled by specifying the following flag in an iframe Broker:

init({
    sharedWorkerUrl: `${location.origin}/openfin-shared-worker.js`,
    experimental: {
        crossTab: 'same-site'
    }
});

Example: Enable cross-tab support

Note that cross-tab support is experimental and browser-dependent, and respects each browser's privacy sandbox.

See also

The following resources are available from the Code tab of the @openfin/core-web page:

  • Platform developer guide: /@openfin/core-web/docs/platform-developer-guide.md

  • Web application developer guide: /@openfin/core-web/docs/web-application-developer-guide.md

  • API reference: /@openfin/core-web/out/@openfin/core-web