0. Overview of linked services and the proxy API

An introduction

Overview

There are several integration scenarios in sharedo where you will want to make calls to an external API. These calls could be from custom UI components (widgets/blades etc) or from the server using custom workflow actions or execution engine scripts.

There are a variety of ways to achieve this, including calling directly using XMLHttpRequest (from the UI) or the http client (from the server). However, both have some complex challenges that need to be resolved, including;

  • From the UI
    • Content Security Policy
    • Cross Origin Requests
    • Configuration
    • Token/Key management
      • Leaking security information
  • From the server
    • Configuration
    • Token/Key management

Content Security Policy

The first issue with calling your API from the UI, and the one most easily resolved is the content security policy (CSP) within sharedo itself. The CSP prevents the browser from loading content or making connections to external sources that haven't explicitly been declared in the CSP feature.

As such, by default, a call from your sharedo instance URL to your custom API URL will be blocked by the CSP.

This is relatively easy to resolve by navigating to global features, locating the "Content Security Policy" feature and adding the url of your API to the `connect-src` section of the configuration.

Cross Origin Requests

The second issue, which also only applies to calling your API from the UI, involves Cross Origin Resource Sharing (CORS). The default behaviour of the browser is to block any XHR requests across different origins. An origin is the same combination of scheme, subdomain, domain and port. If there are differences between those components of the URL, then XHR will be blocked by default.

The upstream API needs to advertise which origins are allowed to call it, and so, your sharedo instance url would need to be added to it's CORS policy to allow the browser to make XHR calls from the sharedo UI to your API.

If you are in control of the integration, it's likely this won't pose any problems as you can control the CORS policy. Most 3rd party services also provide mechanisms to allow CORS on their APIs for your account etc, but if they don't, you would need to either build a facade over the API to be consumed which will forward requests on, or build a custom module extension for sharedo to allow such a facade to run within the sharedo's server side code. (CORS does not apply to server to server calls, it's purely enforced in the browser).

Configuration

For both UI and execution engine calls to your integration API, there is also a question around configuration. Inevitably you will need to run your integration in test, in UAT, in training and in production, all of which potentially having a different instance of the API to be called in different environments.

Whilst there are some mechanics in sharedo for this such as the settings API, it still adds reasonable complexity to your UI and EE integrations to inspect this configuration.

Token/Key management (and leaky security)

It would be unusual to have an integration between sharedo and some upstream API that does not require any form of security. At the minimum, the upstream service would require presentation of an API key, or, more likely, it will implement one of the standard oAuth flows such as authorization code grant, which will require a user to sign in, grant consent to sharedo, and then issue access and refresh tokens that then need to be managed.

On the one hand, the simple API key approach could be done even from the UI by baking the appropriate API key into the JavaScript. This is a fundamental security issue though as the browser isn't a trusted client, and that secret will be exposed anywhere it is used - there's nothing stopping a nefarious actor from obtaining that secret key and using it for their own malicious intent.

Managing the oAuth flows and the tokens required in auth code flow without leaking them into the browser as either cookies or local storage etc, is a non-starter.

Intro to linked services and the proxy

To address all of these potential issues sharedo features a linked service system. This allows the definition of an integration service that sharedo can connect to, along with all of it's configuration, and specifies how it should implement security etc.

This manages the configuration of the service, allowing different instances of sharedo to configure different locations for upstream integration APIs etc, and provides all the facilities for automatic management of keys and tokens.

For instance, where a service is registered as oAuth, using Auth Code flow, it will provide the UI and tooling to link an account to sharedo, allow users to link their own personal accounts if appropriate, and will manage the flow of authentication and consent, then manage the lifetime of any access and refresh tokens automatically.

To go alongside this, a Linked Service Proxy API is available allowing your custom UI and workflow actions etc to call a sharedo API as normal, specify the named service to proxy to, and have sharedo wrap all the appropriate security tokens etc before forwarding the call onto the service and returning the response.

This proxy and the linked service definition addresses all the above common problems.

CSP is no longer in effect as your UI component is calling a standard sharedo API at a known and allowed location.

CORS is no longer in effect as your UI component is calling a standard sharedo API on the same origin, which in turn calls the upstream service - and server to server calls are not affected by CORS.

Configuration is managed within the linked service definition, and as such, your UI component or custom WF action doesn't need to concern itself with configuration issues like the API base address.

Token and key management is handled automatically, server side, based on the security provider chosen when your service was registered. As the tokens are injected into the request from the proxy, none of this information is leaked out to the browser.

Creating a linked service

To create a linked service, sign in with an administrator level account and navigate to /admin/oauth. (Admin > Integrations > Manage Linked services). This then shows a list of the integrations that have been configured for sharedo.

Clicking the "+ Add New" button on the ribbon (top right) will allow you to first select the security mechanism to be used with your service.

The blade that is then presented will vary depending on the type of service being added, but will allow you to configure the specifics of your service. The base url for example. In the screenshot below we chose the legacy shared secret/api key provider, and as such, we have configuration to specify the key.

Be sure to enable the proxy!

Congratulations, you've now registered your external API integration and it's ready for use from the UI or workflow by using the proxy. One final thing you will notice though is that all the providers have the option to "enable proxy" - this must be switched on if you wish to use the service via the proxy API!

Using the linked service proxy

With the service registered, linked and enabled for proxy, you are then free to call the sharedo proxy API at /api/proxy/{serviceSystemName}/_/{apiPath}, where {serviceSystemName} is the system name of the service you registered earlier and {apiPath} is the URL of the upstream API to be called, but without the scheme, domain or port components. The API supports all the common HTTP verbs, so get, put, post, delete etc will all proxy.

For example, assuming you have an upstream service at https://myapi.local:9182/api/info, you would register the linked service using the appropriate authentication provider and configure it's base address as https://myapi.local:9182/. Assuming you named this "myapi", then you would issue a GET request to sharedo's proxy at `/api/proxy/myapi/_/api/info`. This will then route through the proxy, automatically do any token management for you, then forward the request on with appropriate headers before returning the response.

As with all sharedo APIs, your request must be authenticated using a bearer token, but that is handled automatically for you if you are using the UI framework's `$ajax` methods, or the `http` utilities in workflow.

Source code

All source code for this series is available on github here: 
https://github.com/sharedo-tech/sharedo_ide/tree/main/LinkedServiceAndProxy