API security

OpenFin API security enables desktop owners and application providers to determine the API calls that are available for an OpenFin application. Applications must declare in their manifest that they use security-sensitive APIs (secured APIs) for functionality that is outside the security sandbox, such as launching an external application or using fullscreen mode. While these features can be beneficial, OpenFin understands that desktop owners may need to restrict certain APIs from running on a desktop computer, particularly from an unknown or untrusted application. API security enables this by giving the Desktop Owner tools to prevent application developers from implementing features that may be deemed sensitive to an organization.

📘

Note

"API" in this article can refer to individual functions or methods (such as System.openUrlWithBrowser()) or to entire Web APIs (such as geolocation).

Historically, desktop owners have been able to block access to such APIs on a per-app basis, if a particular app is not trusted or should not have elevated permissions. However, this arrangement is opt-out: desktop owners must explicitly block particular apps from using particular API functions; all others are allowed.

Starting in v20 of the OpenFin runtime, the enhanced security model prevents apps from accessing secured API functions unless the apps are explicitly granted permission to use them.

Enhanced security model

In order to leverage APIs, application providers must declare the use of specific API functions in their application manifest file, and explicitly declare API functions used in child window options. This assists desktop owners to recognize API intent up-front. If an API function is not permitted by the organization or needs to be enabled for ease of application functionality, the desktop owner may define settings to block or allow use of the API function.

For versions of OpenFin prior to v20, if a desktop owner does not block an application’s use of a secured API, it is permitted. Starting in v20, if the desktop owner (or their delegate) does not explicitly allow a secured API for an application, it is blocked by default.

Versions of OpenFin between v20 and v24 automatically allow secured APIs if the runtime fails to connect to the RVM or if the RVM doesn't exist. Starting in v24, secured APIs are blocked if the RVM cannot be reached (due to messaging failures) or if the RVM doesn't exist (the runtime was launched from the CLI).

Development exception

To simplify application development, if the application is running from localhost, API security is the same as in v19 and earlier: Only the app manifest declaration is needed to access the API; no desktop owner setting or other permission is required.

For developers, this exception removes the need to take an extra step to allow APIs to be used. Be sure to test your application on a non-local server, and with both enabling and disabling the secured APIs it uses, to ensure that it behaves correctly under those circumstances.

For desktop owners, if you want to prevent this exception for developers’ desktops, define the following registry key as a DWORD value set to 0 : HKEY_CURRENT_USER\SOFTWARE\OpenFin\RVM\Settings\enableSBDLocalhostTrusted

If this key is not defined or is set to a non-zero value, the exception for localhost is allowed.

Delegating control

A desktop owner has the ultimate control over whether to allow or block a particular API for a particular application. However, a desktop owner can delegate control to end-users via a prompt to decide to allow the application to use the requested API(s).

The dialog box presented to the user lists the actions represented by the APIs (not the API names themselves), with a link to Review security permissions for detailed information.

  • If the user blocks the use of the APIs, then the application still runs, but it doesn’t have access to the requested APIs and the user will be prompted again on the next launch.

  • If the user allows the use of the APIs, they aren’t prompted again on future launches.

  • If the application is updated and uses new secured APIs that aren't blocked or allowed by the desktop owner or OpenFin, then the user is prompted again, for the new permissions.

Review Security Permissions dialog box

This dialog box can be customized through the following settings: (starting in RVM 6.9)

  • App icon: The icon defined for the application's shortcut in shortcut settings in the app manifest; used next to the application name in this dialog box.

  • Email address: The same email as is defined in the support information.

  • "more information" link target: A URL defined by the securityPermissionsMoreInfoUrl property of the startup_app or platform object in the app manifest.

Secured APIs

In OpenFin, the following APIs are secured. Therefore, in order for an application to use them, they must be declared in an application’s manifest, and allowed by the desktop owner or their delegate.

APIType
System.downloadAssetOpenFin
System.launchExternalProcessOpenFin
System.readRegistryValueOpenFin
System.registerCustomProtocolOpenFin (RVM 12+, Runtime v34+)
System.unregisterCustomProtocolOpenFin (RVM 12+, Runtime v34+)
System.checkCustomProtocolStateOpenFin (RVM 12+, Runtime v34+)
System.terminateExternalProcessOpenFin
System.getAllExternalWindowsOpenFin (deprecated in Runtime v20; removed in v22)
System.openUrlWithBrowserOpenFin
ExternalWindow.wrapOpenFin (deprecated in Runtime v20; removed in v22)
Application.getFileDownloadLocationOpenFin (Runtime v32+)
Application.setFileDownloadLocationOpenFin
audioWeb
videoWeb
geolocationWeb
notificationsWeb
midiSysexWeb
pointerLockWeb
fullscreenWeb
openExternalWeb (from Electron)
clipboard-readWeb
clipboard-sanitized-write (starting in OpenFin version 23)Web

Declaring APIs in an application manifest file

An application must declare the secured APIs that it uses in its manifest file. If it attempts to use secured APIs that it hasn’t declared, they are blocked.
For complete details on defining an application manifest, refer to Manifest settings.

To declare secured APIs used by the application, list them within a permissions object, categorized by the namespace they belong to (which may be webAPIs), as shown in the following examples. For most APIs, the name is a key with a Boolean value, except Web APIs, where listing the API name in an array indicates that it is used.

For System.openUrlWithBrowser, the key is an object with two members:

  • enabled, a Boolean for whether the method is used

  • protocols, an array of custom protocols

For methods related to custom protocols, the permission can be either a plain Boolean or an object similar to the one used for System.openUrlWithBrowser; the protocols member in this case declares custom protocol schemes that are used with each method. The methods related to custom procotols are the following:

The location of the permissions object varies, depending on the way the application uses OpenFin APIs.

  • For applications that use the Platform API, you can set permissions inside the following objects:

    • platform: The permissions object declares APIs for the platform only (and not for windows or views). If you specify a providerUrl, then this URL is able to execute the enabled permissions.

    • defaultWindowOptions: The permissions object declares APIs for every window launched.

    • viewDefaultOptions: The permissions object declares APIs for every view launched. Be sure to consider whether you load third-party content into views, which might also use APIs.

  • startup_app: Use this object for applications that do not use the Platform API.

{
    "platform": {
        "uuid": "OpenfinPOC",
        "applicationIcon": "http://localhost:5555/favicon.ico",
        "autoShow": false,
        "permissions": {
            "System": {
                "launchExternalProcess": {
                    "enabled": true,
                    "assets": {
                        "enabled": true
                    },
                    "downloads": {
                        "enabled": true
                    },
                    "executables": {
                        "enabled": true
                    }
                },
                "openUrlWithBrowser": {
                    "enabled": true,
                    "protocols": [
                        "slack",
                        "msteams"
                    ]
                },
                "registerCustomProtocol" : true,
                "unregisterCustomProtocol": {
                    "enable": true,
                    "protocols": [
                        "PROTOCOL1",
                        "PROTOCOL2"
                    ]
                },
                "checkCustomProtocolState": {
                    "enable": true,
                    "protocols": [
                        "PROTOCOL1",
                        "PROTOCOL2"
                    ]
                },
                "readRegistryValue": false,
                "terminateExternalProcess": true
            },
            "webAPIs": [
                "notifications",
                "audio",
                "video"
            ]
        },
        "defaultWindowOptions": {
            "permissions": {
                "System": {
                    "launchExternalProcess": {
                        "enabled": true,
                        "assets": {
                            "enabled": true
                        },
                        "downloads": {
                            "enabled": true
                        },
                        "executables": {
                            "enabled": true
                        }
                    },
                    "readRegistryValue": false,
                    "terminateExternalProcess": true
                },
                "webAPIs": [
                    "notifications",
                    "audio",
                    "video"
                ]
            },
            "defaultViewOptions": {
                "permissions": {
                    "System": {
                        "launchExternalProcess": {
                            "enabled": true,
                            "assets": {
                                "enabled": true
                            },
                            "downloads": {
                                "enabled": true
                            },
                            "executables": {
                                "enabled": true
                            }
                        },
                        "readRegistryValue": false,
                        "terminateExternalProcess": true
                    },
                    "webAPIs": [
                        "notifications",
                        "audio",
                        "video"
                    ]
                }
            }
        }
    }
}
{
    "startup_app": {
        "name": "OpenfinPOC",
        "url": "http://example.com:5555/index.html",
        "uuid": "OpenfinPOC",
        "applicationIcon": "http://example.com:5555/favicon.ico",
        "autoShow": true,
        "saveWindowState": true,
        "permissions": {
            "System": {
                "launchExternalProcess": {
                    "enabled": true,
                    "assets": {
                        "enabled": true
                    },
                    "downloads": {
                        "enabled": true
                    },
                    "executables": {
                        "enabled": true
                    }
                },
                "openUrlWithBrowser": {
                    "enabled": true,
                    "protocols": [
                        "slack",
                        "msteams"
                    ]
                },
                "registerCustomProtocol" : true,
                "unregisterCustomProtocol": {
                    "enable": true,
                    "protocols": [
                        "PROTOCOL1",
                        "PROTOCOL2"
                    ]
                },
                "getCustomProtocolState": {
                    "enable": true,
                    "protocols": [
                        "PROTOCOL1",
                        "PROTOCOL2"
                    ]
                },
                "readRegistryValue": false,
                "terminateExternalProcess": true
            },
            "webAPIs": [
                "notifications",
                "audio",
                "video"
            ]
        }
    },
    "runtime": {
        "arguments": "",
        "version": "stable"
    },
    "shortcut": {
        "company": "OpenFin",
        "description": "Openfin POC",
        "icon": "http://example.com:5555/favicon.ico",
        "name": "Openfin POC"
    }
}

Query secure API permissions

Application developers might want their apps to take preemptive action when certain capabilities are not available. For example, a Launch External App button could be disabled when that capability is not permitted.

Starting in v21, the System.queryPermissionForCurrentContext() method returns the permission state of a specific secured API. By using this method, an app can alter the UI to disable or hide features that cannot be performed due to the permission status.

Example usage

The System.queryPermissionForCurrentContext() method has one parameter, the name of the secure API to query.

Here is what it looks like to use it:

System.queryPermissionForCurrentContext('System.launchExternalProcess').then(result => {
  if (result.granted) {
    renderLaunchExternalProcessButton();
  } 
});

The shape of the return value is QueryPermissionResult which is as follows:

interface QueryPermissionResult {
  permission: string,
  state: 'granted' | 'denied' | 'unavailable',
  granted: boolean, 
  rawValue?: unknown
}

Configuring Desktop Owner settings

The primary mechanism for desktop owners to control access to secured APIs is through definitions in a desktop owner settings file. For information about other settings, refer to Desktop owner settings.

Starting in RVM version 7.0, the RVM reads the DesktopOwnerSettings registry key and the desktop owner settings file each time an application is launched; it uses the values as defined at that time for that instance of the application. This feature enables desktop owners to update settings values, including those related to application security, without terminating the RVM or other running applications, possibly by pointing to a completely different file. For already-running applications, the settings values remain as they were defined at the time that the application was launched. All settings related to application security can be refreshed in this manner.

Application security settings

To define API security settings for specific applications, there must be an object named applicationSettings at the top level of the JSON file. The members of this object are key strings. A key can be any of the following:

  • A manifest URL

  • An arbitrary label; in this case, its urls member is a list of strings representing a collection of Chrome match patterns for manifest URLs. This enables you to define one set of API security settings for a group of applications that have similar manifest URLs.

  • The string default, which applies to any application whose manifest URL does not match another key.

Within each sub-object of applicationSettings, a permissions object contains the settings for specific APIs, grouped by namespace. Values are booleans, where true allows the API and false disallows it. If an application declares that it uses an API, and no matching permission definition sets a value for it, then the end-user is prompted to allow or disallow it.

The System.readRegistryValue() method supports more granular control. The enabled member key controls use of the method. In addition, the registryKeys member is an array of registry keys that the application can read when the method is allowed.

For web APIs, similarly to the app manifest, simply listing the name of the API is sufficient to indicate that it is allowed.

Global default permission

You can set a global default for handling cases where the combination of the application and the requested secured API is not covered by the application-specific settings under applicationSettings.
This option is defined in the desktopSettings object.

  • securedAPIDefaultPermission: Possible values are ”allow”, ”deny”, or ”prompt” (default).

Example desktop owner settings

Below is an example of a desktop owner settings file configured with secured APIs.

{
    "desktopSettings": {
        "securedAPIDefaultPermission": "prompt",
        ...
    },
    "applicationSettings": {
        "https://www.examplefinapp.com/manifest1.json": {
            "permissions": {
                "System": {
                    "launchExternalProcess": {
                        "enabled": true,
                        "assets": {
                            "enabled": true
                        },
                        "downloads": {
                            "enabled": true
                        },
                        "executables": {
                            "enabled": true
                        }
                    }
                }
            }
        },
        "http://www.examplefinapp.com/AnotherApp.json": {
            "permissions": {
                "System": {
                    "launchExternalProcess": {
                        "enabled": true,
                        "assets": {
                            "enabled": true
                        },
                        "downloads": {
                            "enabled": true
                        },
                        "executables": {
                            "enabled": true
                        }
                    },
                    "readRegistryValue": {
                        "enabled": true,
                        "registryKeys": [
                            "HKEY_CURRENT_USER\\Software\\OpenFin\\RVM",
                            "HKEY_CURRENT_USER\\Software\\OpenFin\\Runtime",
                            "HKEY_CURRENT_USER\\Software\\Oracle"
                        ]
                    }
                },
                "webAPIs": [
                    "audio",
                    "video"
                ]
            }
        },
        "MyAlias": {
            "urls": [
                "https://example.com/*.json",
                "https://*.example.com/*.json"
            ],
            "permissions": {
                "System": {
                    "launchExternalProcess": {
                        "enabled": true,
                        "assets": {
                            "enabled": true
                        },
                        "downloads": {
                            "enabled": true
                        },
                        "executables": {
                            "enabled": true
                        }
                    },
                    "readRegistryValue": {
                        "enabled": true,
                        "registryKeys": [
                            "HKEY_CURRENT_USER\\Software\\OpenFin\\RVM",
                            "HKEY_CURRENT_USER\\Software\\OpenFin\\Runtime\\Path",
                            "HKEY_CURRENT_USER\\Software\\Oracle"
                        ]
                    }
                }
            }
        },
        "default": {
            "permissions": {
                "System": {
                    "launchExternalProcess": {
                        "enabled": false
                    }
                }
            }
        }
    }
}