Changelog
io.Connect Desktop 10.4
Release date: 28.08.2026
| Components | Version |
|---|---|
| Electron | 43.2.0 |
| Chromium | 150.0.7871.129 |
| Node.js | 24.18.0 |
The following libraries are bundled with io.Connect Desktop 10.4 and will be used for auto injection:
| Injected Library | Version |
|---|---|
@interopio/desktop |
6.22 |
@interopio/fdc3 |
2.11 |
Breaking Changes
Intent Resolver & Displays API
The Intent Resolver now uses the Displays API in order to operate properly.
As a result, if the Intent Resolver UI is enabled (which is the default), the Displays API will be enabled as well, even if you have explicitly disabled it in the configuration object for initializing the
@interopio/desktoplibrary. In this case, the library will log a warning in the console.To disable the Displays API, you must now also disable the Intent Resolver UI:
import IODesktop from "@interopio/desktop"; const config = { displays: false, intents: { enableIntentsResolverUI: false } }; const io = await IODesktop(config);
New Features
OpenID Connect Authentication
io.Connect Desktop now supports authentication via the OpenID Connect (OIDC) protocol. Authentication is performed by a trusted identity provider and control is returned to the io.Connect platform via a loopback HTTP server or a custom protocol scheme. This enables you to authenticate your users against any identity provider supporting OIDC (Microsoft Entra ID, Auth0, Okta, Google, Keycloak, and more) without having to implement your own authentication controller.
The claim extracted from the ID token becomes the identity of the authenticated user, which is then published to the io.Connect Gateway and to your apps.
To enable OIDC authentication, set the
"authController"property to"oidc"in the"ssoAuth"top-level key of thesystem.jsonsystem configuration file of io.Connect Desktop:{ "ssoAuth": { "authController": "oidc", "options": { "authority": "https://login.microsoftonline.com/<tenant-id>/v2.0", "clientId": "<client-id>", "scopes": ["openid", "profile", "email", "offline_access"], "usernameClaim": "preferred_username", "redirect": { "type": "loopback" } } } }It's required to provide the OAuth 2.0 client ID, settings for redirecting after authentication, and either
"authority"(for identity providers that support OIDC discovery), or both"authorizationEndpoint"and"tokenEndpoint"(for identity providers that don't support it).The
"options"object has the following properties:
Property Type Description "authority"stringBase issuer URL of the OIDC provider to be used for OIDC discovery at /.well-known/openid-configuration. Use this property for identity providers that support OIDC discovery. For providers that don't support OIDC discovery, use"authorizationEndpoint"and"tokenEndpoint"instead."authorizationEndpoint"stringExplicit authorization endpoint URL. Use this together with "tokenEndpoint"if the identity provider doesn't support OIDC discovery. For providers that support OIDC discovery, use"authority"instead."clientId"stringRequired. OAuth 2.0 client identifier registered with the identity provider. "endSessionEndpoint"stringExplicit end session endpoint to be used when the io.Connect platform initiates a logout. Use this when the identity provider doesn't advertise an end session endpoint in its discovery settings. If you don't specify an end session endpoint, the discovered one will be used. If neither is available, the io.Connect platform will only drop the local tokens and the identity provider session will be left intact (the user won't be logged out). "extraAuthParams"objectAdditional provider-specific query parameters to be appended to the authorization request. "issuer"stringIssuer identifier of the OIDC provider (the base URL of the identity provider). Required when using explicit authorization and token endpoints for identity providers that don't support OIDC discovery. "jwksUri"stringJWKS endpoint of the OIDC provider for verifying the signature of the ID token. Required when using explicit authorization and token endpoints for identity providers that don't support OIDC discovery. "loginSurface""system-browser"|"embedded-window"Specifies where the identity provider login will be displayed. If set to "system-browser"(recommended), the login will be displayed by opening the default system browser. If set to"embedded-window", the login will be opened in an io.Connect Window (discouraged practice, blocked by some identity providers like Google). Defaults to"system-browser"."logoutOnShutdown"booleanIf true, a logout request for ending the identity provider session will be sent when the io.Connect platform shuts down. The next platform launch will require a new login. Defaults tofalse."redirect"objectRequired. Redirection endpoint settings to be sent to the identity provider for redirecting after authentication. It's possible to configure a loopback HTTP server or a custom protocol scheme. "scopes"string[]OAuth 2.0 scopes to request from the identity provider during authentication. Defaults to ["openid", "profile", "email"]."timeoutMs"numberInterval in milliseconds to wait for the authentication process to complete. Defaults to 300000."tokenEndpoint"stringExplicit token endpoint URL. Use this together with "authorizationEndpoint"if the identity provider doesn't support OIDC discovery. For providers that support OIDC discovery, use"authority"instead."usernameClaim"stringThe name of the claim to be extracted from the ID token and to be used as the identity of the authenticated user. Defaults to "sub"."window"objectSettings for the io.Connect Window when using an embedded window to display the login. The
"redirect"object accepts settings either for a loopback HTTP server, or for a custom protocol scheme.Use a loopback HTTP server on the local machine as a redirection endpoint. This is the recommended approach, supported by most identity providers:
{ "ssoAuth": { "options": { "redirect": { "type": "loopback", "host": "localhost", "port": 9372, "path": "/callback" } } } }The
"redirect"object for a loopback HTTP server has the following properties:
Property Type Description "host""127.0.0.1"|"localhost"Loopback host to use in the redirect URI. Defaults to "127.0.0.1"."path"stringPath for the loopback redirection URI. Defaults to "/callback"."port"numberFixed loopback port. Use a fixed port for identity providers that require exact URI matching for redirection. Can be omitted for identity providers that don't enforce exact port matching, in which case the OS will assign an available port on startup. "type"stringRequired. Type of the redirection endpoint. Must be set to "loopback".⚠️ Note that some identity providers accept only one of the two supported loopback hosts, so make sure that the value of the
"host"property matches the redirect URI registered with the identity provider.⚠️ Note that Microsoft Entra ID, Okta, Google, and Keycloak ignore the loopback port, so you can omit the
"port"property and let the OS assign an available one on startup - no fixed port has to be reserved. Auth0 requires a fixed port.Use a custom protocol scheme for redirection after authentication only when the provider rejects loopback redirection URIs. The io.Connect platform will automatically register the specified scheme with the OS before initiating login:
{ "ssoAuth": { "options": { "redirect": { "type": "custom-scheme", "scheme": "ioconnect", "path": "callback" } } } }The
"redirect"object for a custom protocol scheme has the following properties:
Property Type Description "path"stringPath for the custom protocol scheme. Defaults to "callback"."scheme"stringRequired. Custom protocol scheme to be used as a redirection endpoint. "type"stringRequired. Type of the redirection endpoint. Must be set to "custom-scheme".⚠️ Note that on macOS the OS routes only custom protocol schemes declared in the app bundle. Using any other custom protocol scheme other than the ones declared requires repackaging the app. You can also use a loopback redirection endpoint instead.
The
"window"object has the following properties:
Property Type Description "height"numberHeight in pixels for the login window. "mode""flat"|"tab"|"html"|"frameless"io.Connect Window mode for the embedded login window. Defaults to "html"."userAgent"stringString to be used for the User-Agentrequest header."width"numberWidth in pixels for the login window. To initiate a logout on demand, invoke the
"T42.GD.Execute"Interop method with a"logout"command. This will end the identity provider session, drop the local tokens, and by default restart io.Connect Desktop, so that a new login will be required:const methodName = "T42.GD.Execute"; const logoutArgs = { command: "logout", args: { restart: true } }; await io.interop.invoke(methodName, logoutArgs);When an OIDC or an SSO authentication controller is configured, every request to a REST data store will now carry an
Authorization: Bearer <access-token>header and anauthheader holding the io.Connect authentication info. This allows your REST service to verify the token and to serve per-user data.⚠️ Note that opening the identity provider login in an embedded window is a discouraged practice and is blocked by some identity providers like Google. When using an embedded window, a loopback redirection endpoint must specify a fixed
"port".
Isolated Browser Sessions for Apps
It's now possible to start an app instance in an isolated browser session, so that its cookies, cache, local and session storage are separated from the default session and from all other isolated sessions. This is useful when you need to run several instances of the same app authenticated as different users, or when an app must not share its browsing data with the rest of the platform.
To start an app in an isolated browser session, use the
"session"property of the"details"top-level key in the app definition:{ "name": "my-app", "type": "window", "details": { "url": "https://example.com/my-app", "session": { "partition": "persist:my-app" } } }The
"session"object has the following properties:
Property Type Description "inheritCookies"objectSettings for copying cookies from the default session into the isolated session when it's created. Has no effect without "partition"."partition"stringKey of the isolated session. Prefix the value with "persist:"to store the session data on disk and preserve it between restarts. Without the prefix, the session is kept in memory only and is discarded when io.Connect Desktop exits.The browser session configuration is preserved when the app instance is saved in Global and Workspace Layouts - the browser session with which a window has been created is saved in the Layout and takes precedence over the session defined in the app definition when the Layout is restored.
Apps that specify the same
"partition"value share the same isolated browser session. A window opened by an app inherits the session of the app that opened it.If your app must reuse an existing authenticated session (e.g., an SSO session established in the default browser session), use the
"inheritCookies"object to copy the relevant cookies into the isolated browser session at the moment it's created:{ "details": { "session": { "partition": "persist:my-app", "inheritCookies": { "domains": ["login.example.com"] } } } }The
"domains"property accepts a list of domains whose cookies will be copied from the default session. Each value matches the specified domain and its subdomains.All platform functionalities that operate on a browser session are applied to the isolated browser sessions as well. This includes NTLM authentication, web permissions, downloads, request and response header manipulation, URL filtering, proxy settings, and the injected io.Connect library.
⚠️ Note that cookies are copied only once, when the isolated browser session is created. Later changes to the cookies in the default session aren't propagated.
⚠️ Note that the Cookies API always operates on the default browser session, regardless of the session of the calling window. Only the cookie storage is isolated, not the API.
Transparency & Hardware Acceleration
By design, the Workspaces App and the Web Group App web pages are rendered over the app windows participating in the respective Workspace or web group. This requires the platform to ensure that the app windows below the web pages remain visible and can receive mouse events, which in turn determines how custom popups (menus, panels, overlays) displayed over the app windows must be implemented.
The
-webkit-app-regionCSS property is now used in both platform modes for defining which areas of the Workspaces App and the Web Group App are transparent (the app window below is visible and receives the mouse events) and which are opaque (the area remains rendered and clickable over the app windows):/* This area will be passed through, so the app window below will be visible and will receive mouse events. */ .app-window-area { background-color: transparent; -webkit-app-region: transparent; } /* This area will be opaque, making the custom popup visible and clickable over the app windows. */ .my-custom-popup { background-color: grey; -webkit-app-region: opaque; }⚠️ Note that the
-webkit-app-regionproperty isn't inheritable, so you must declare it explicitly on each element that has to define an area. Also, this property controls only how the platform treats the area, not how it looks - to make an element visually transparent or opaque, you still have to use standard CSS for background color and opacity.ℹ️ For details on the transparent and opaque areas and how to define them, see the Capabilities > Windows > Workspaces and the Capabilities > Windows > Window Management sections.
Default Platform Mode
In the default platform mode, the Workspaces App and the Web Group App web pages are now rendered over the app windows, as they already are in the advanced platform mode, and the platform uses the transparent and opaque areas defined via the
-webkit-app-regionCSS property to determine which areas to pass through to the app windows below.As a result, custom popups, menus, and panels can now be implemented as regular HTML elements in both platform modes, and the dedicated external popup windows that were required in the default platform mode since io.Connect Desktop 10.0 are no longer necessary.
Configuration changes aren't required - in the default platform mode hardware acceleration is always enabled and this mechanism is always active.
The following table summarizes what you have to do depending on your setup:
Setup Action You are using the default Workspaces App and Web Group App. Nothing - the default apps already contain the necessary -webkit-app-regiondeclarations.You have a custom Workspaces App or Web Group App using @interopio/workspaces-ui-reactor@interopio/groups-ui-reactearlier than 4.5.1.Nothing - the platform will detect the library version and will continue to use external popup windows. You have a custom Workspaces App or Web Group App using @interopio/workspaces-ui-reactor@interopio/groups-ui-react4.5.1 or later and theuseExternalWindowPopup()hook.Nothing - your existing popups will continue to work. You can optionally migrate them back to popups created from HTML elements. You have a custom Workspaces App or Web Group App using @interopio/workspaces-ui-reactor@interopio/groups-ui-react4.5.1 or later with your own custom elements displayed over app windows, or you override or replace the default styles.Mark your custom elements with -webkit-app-region: opaqueor-webkit-app-region: transparent.Advanced Platform Mode
The
"UseAppRegion"value for the"mode"property of the"transparency"object under the"hardwareAcceleration"property of the"windowManagement"top-level key in thesystem.jsonsystem configuration file of io.Connect Desktop is now available in the 10.x release line.When hardware acceleration is enabled, the platform must cut the app window areas out of the Workspaces App and the Web Group App web pages so that the app windows below remain visible and can receive mouse events. This may cut out custom popups (menus, panels, overlays) displayed over the app windows.
Setting the
"mode"property to"UseAppRegion"instructs the platform to honor the transparent and opaque areas defined via the-webkit-app-regionCSS property when determining which areas to cut out:{ "windowManagement": { "hardwareAcceleration": { "enabled": true, "transparency": { "mode": "UseAppRegion" } } } }⚠️ Note that hardware acceleration and the
"transparency"settings are valid only in the advanced platform mode. In the default platform mode, hardware acceleration is always enabled and these settings won't have any effect.⚠️ Note that the
"UseAppRegion"mode requires@interopio/workspaces-ui-reactversion 4.5.1 or later and@interopio/groups-ui-react4.5.1 or later for the Workspaces App and the Web Group App respectively.
Workspace Tab Title Overflow
Two new CSS variables are available for controlling how the title of a Workspace tab behaves when it's longer than the available space:
Variable Description --workspace-tab-title-mask-imageMask image applied to the title of a Workspace tab, used for the text fade-out effect on text overflow. Set to noneto disable the text mask.--workspace-tab-title-overflowControls how the title of a Workspace tab is rendered when it overflows the available space. The existing
--workspace-tab-text-maskvariable is no longer applied to the Workspace tab titles directly - it now only defines the fade-out gradient and is used as the default value of--workspace-tab-title-mask-image. Any custom gradient specified for--workspace-tab-text-maskwill continue to be applied as before.#root { /* The title will be truncated with an ellipsis instead of fading out. */ --workspace-tab-title-mask-image: none; --workspace-tab-title-overflow: ellipsis; }⚠️ Note that this feature requires
@interopio/workspaces-ui-reactversion 4.6 or later.
Workspace Selection Metric
io.Insights now publishes the
"workspace_selected"platform metric for io.Connect Desktop. Use it to find out how often your users switch between Workspaces and which Workspace Layouts they actually work with.The metric is a counter which is incremented each time a Workspace becomes the selected one - when the user clicks its tab, when it's restored individually or as part of a Global Layout, and when a new Workspace is created. Selecting an already selected Workspace, renaming a Workspace, reordering the Workspace tabs, or focusing an app within the Workspace don't increment the metric.
The metric has a
"layout"attribute holding the name of the Workspace Layout, or"unknown"if the Workspace isn't tied to a saved Layout.
Tracing Commands Sent from io.Manager
io.Insights now publishes a span for each command that io.Connect Desktop receives from io.Manager and executes locally - e.g., retrieving system information, collecting logs, refreshing, restarting or stopping apps, restarting the platform, or executing code.
The span is named
"interopio.desktop.manager.command"and has the following attributes in addition to the common span attributes:
Attribute Type Description commandIdstringID of the command as assigned by io.Manager. commandTypestringType of the command - e.g., "GetSystemInfo","GetLogs","RestartApps","ExecuteCode".The span is created as a child of the io.Manager span that has triggered the command and shares its trace ID. This allows you to follow an entire operation as a single trace in your observability backend (from the request in io.Manager to its execution in io.Connect Desktop), instead of having to correlate two unrelated traces manually.
Both attributes can be used in the span filtering context, which allows you to control the tracing of individual command types:
⚠️ Note that io.Manager must also be configured to publish traces. By default, a command that arrives without trace context from io.Manager won't start a new trace and no command span will be created for it.
Clearing Cache & Storage Data
The
iodesktopobject injected in the globalwindowobject has been extended with two new methods for clearing cache and storage data.Use the
clearStorageData()method to clear the storage data for the app. Pass an object with astoragesproperty to clear only specific types of storage:// Clearing all storage data. await iodesktop.clearStorageData(); // Clearing only the cookies and the IndexedDB data. await iodesktop.clearStorageData({ storages: ["cookies", "indexdb"] });⚠️ Note that the object accepted as an argument by the
clearStorageData()method is fully aligned with the Electron storage data settings. For more details on the available properties and their accepted values, see the Electron documentation.Use the
clearAuthCache()method to clear the cached HTTP authentication credentials:await iodesktop.clearAuthCache();As with the already available
clearCache()andclearHostResolverCache()methods, your app must have the"allowClearingCache"top-level key in its app definition set totruein order to use these methods:{ "allowClearingCache": true }All cache clearing operations are also available to the end users via the tray icon menu of io.Connect Desktop. The "Diagnostics" section has been reorganized into "System", "Cache", and "Debugging" submenus, with the "Cache" submenu holding the "Clear Preload Scripts Cache", "Clear Network Cache", "Clear Host Resolver Cache", "Clear Storage Data", and "Clear Auth Cache" options.
Download File Path
The
displayInfoobject inside theDownloadItemobject has been updated with a newpathproperty that holds the full path of the downloaded file - the directory of the saved file and the actual name with which the file was saved. Thepathproperty is populated once the download has been completed successfully and isundefinedfor downloads that are still in progress or have failed.The
DownloadItemobject is used by the [list()](../../../../reference/javascript/io.connect desktop/downloadsmanager/index.html#DownloadsManager-list) andonUpdate()methods of the API exposed via thedownloadsproperty of the globaliodesktopobject. You can use the newpathproperty to determine the location of the downloaded file after the download has been completed.The following example demonstrates how to retrieve the path of a completed download:
const handler = item => { if (item.displayInfo.state === "completed") { console.log(`Download saved to "${item.displayInfo.path}".`); } }; iodesktop.downloads.onUpdate(handler);
Window Title Priority
The title of an io.Connect window can be set from several sources - the user (by editing the window title manually), the io.Connect API, the HTML document of the app, and the app definition. It's now possible to define explicitly the title priority - the order in which the platform will consider these sources when determining the effective window title.
To specify the priority order, use the
"titlePriority"property of the"details"top-level key in the app definition:{ "name": "my-app", "type": "window", "title": "My App", "details": { "url": "https://example.com/my-app", "titlePriority": ["custom", "user", "config", "document"] } }The first source in the array that has a value will be used as the window title. Sources omitted from the array will be entirely ignored. Sources with no value (
undefinedor an empty string) will be skipped. If none of the listed sources has a value, the window title will be an empty string.The
"titlePriority"property accepts an array with the following values:
Value Description "config"The title specified in the app definition. "custom"The title specified dynamically via the io.Connect API. "document"The title specified in the HTML document of the app. "user"The title specified by the user by editing the window title manually. If the
"titlePriority"property isn't specified, the default priority order is["user", "custom", "document", "config"]. If the"syncTitleWithDocumentTitle"property is set to"preserveCustomTitle", the default priority order is["custom", "user", "document", "config"].⚠️ Note that the
"titlePriority"property takes precedence over the"syncTitleWithDocumentTitle"property. If"titlePriority"isn't specified, the existing title behavior will be preserved.
Suppressing System Error Dialogs
io.Connect Desktop displays native OS dialogs on critical errors - e.g., when the system configuration is invalid, when no apps are available for the user, or when another instance of the platform is already running. It's now possible to suppress system errors for unhandled exceptions and unhandled
Promiserejections in the main process, so that io.Connect Desktop will exit silently and the error will only be written to the platform log files.To suppress the system error dialogs, use the
"suppressSystemErrors"top-level key in thesystem.jsonsystem configuration file of io.Connect Desktop:{ "suppressSystemErrors": true }The same behavior can be achieved by starting io.Connect Desktop with the
--noDialogscommand line argument.On Windows:
io-connect-desktop.exe --noDialogsOn macOS:
open -a "io.Connect Desktop" --args --noDialogsWhen a dialog is suppressed, the platform logs a warning containing the title and the content of the dialog and exits with an exit code corresponding to the error.
⚠️ Note that only the native dialogs originating from the platform are suppressed. Native dialogs displayed by apps running in the platform aren't affected.
OS Information for Remote Stores
The metadata that io.Connect Desktop sends to remote stores (app, Layout, and app preferences) in the
gdrequest header has been extended with information about the operating system of the user machine. This allows your REST service to make OS-aware decisions when serving app definitions, Layouts, or app preferences.The
gdheader holds a stringified JSON object which now contains an additional"os"property with the following shape:{ "os": { "arch": "x64", "platform": "win32", "release": "10.4.0" } }The
"os"object has the following properties:
Property Type Description "arch"stringCPU architecture of the OS (e.g., "x64","arm64")."platform"stringPlatform identifier of the OS (e.g., "win32","darwin")."release"stringRelease version of the OS.
Improvements & Bug Fixes
Upgraded to Electron 43.2.0 (Chromium 150).
Reworked the per-window zoom implementation to use the native zoom control of the underlying browser engine. As a result, disabling the zoom for an app now reliably prevents it from being zoomed, and the zoom factor of an app is preserved when the app navigates or is reloaded. This also improves the handling of zoom in the standalone platform windows (the splash screen, the "Open" app, alerts, and dialogs) - the zoom in these windows is now isolated and changing it no longer affects the apps hosted on the same domain, and vice versa.
Improved the handling of the per app response header settings - the rules defined in an app definition are now applied to the apps loaded in
<iframe>elements within the app as well, including cross-origin ones. Previously, the only way to modify the response headers for an app loaded in an<iframe>element was to define the rule globally.Improved the positioning of the Intent Resolver on multi-monitor setups when using vertical monitors or different scaling.
Improved closing Workspaces and apps in them in order to prevent visual artifacts during the close operation.
Improved the platform mechanism for reporting the visibility of web apps hosted in the advanced platform mode via the standard
document.visibilityStateproperty and thevisibilitychangeevent. Now, an app is reported as hidden when it's fully covered by another window, when its io.Connect window group or Workspace is minimized, or when it isn't the selected tab in a tab group, in a Workspace window tab group, or in a deselected Workspace. Irregularly shaped io.Connect window groups are excluded from the visibility checks against the windows behind them. The platform throttles these hidden apps automatically and your apps can now also rely on the standard visibility APIs in order to pause expensive operations.Fixed an issue with the width of the Workspace tabs and the Workspace window tabs, where the platform applied a maximum width programmatically, overriding the custom values specified via CSS variables.
Fixed an issue with retrieving the selected tab of an io.Connect window tab group on platform startup, where several windows in the same tab group could report themselves as the selected one.
Fixed an issue related to the order in which auto-started apps are launched in the case where an app is registered while a boot sequence stage is already running.
Fixed an issue with the dialog for unsaved Layout changes, where saving or discarding the changes threw an error if the current Layout had been removed in the meantime.
Fixed several issues on macOS related to hiding and showing the Workspaces App instances - the Workspaces App instance is now correctly displayed with its saved bounds and state, and initializing a hidden frame no longer makes it visible.