10 KiB
MSC1957: Integration manager discovery
Note: this proposal is part of a larger "Integrations API" which has not yet been defined. See MSC1956 for details.
Note: this proposal makes use of the existing Widget API proposed by MSC1236.
Users should have the freedom to choose which integration manager they want to use in their client, while also accepting suggestions from their homeserver and client. Clients need to know where to find the different integration managers and how to contact them.
Proposal
A single logged in user may be influenced by zero or more integration managers at any given time. Managers are sourced from the client's own configuration, homeserver discovery information, and the user's personal account data in the form of widgets. Clients should support users using more than one integration manager at a given time, although the rules for how this can be handled are defined later in this proposal.
Client-configured integration managers
This is left as an implementation detail. In the case of Riot, this is likely to be part of the existing
config.json
options, although likely modified to support multiple managers instead of one.
Homeserver-configured integration managers
The integration managers suggested by a homeserver are done through the existing .well-known discovery mechanism. The added optional fields, which should not affect a client's ability to log a user in, are:
{
"m.integrations": {
"managers": [
{
"api_url": "https://integrations.example.org",
"ui_url": "https://integrations.example.org/ui"
},
{
"api_url": "https://bots.example.org"
}
]
}
}
As shown, the homeserver is able to suggest multiple integration managers through this method. Each manager
must have an api_url
which must be an http
or https
URL. The ui_url
is optional and if not provided
is the same as the api_url
. Like the api_url
, the ui_url
must be http
or https
if supplied.
The ui_url
is ultimately treated the same as a widget, except that the data
object from the widget is not
present and must not be templated here. Variables like $matrix_display_name
are able to function, however.
Integration managers should never use the $matrix_user_id
as authoritative and instead seek other ways to
determine the user ID. This is covered by other proposals.
The api_url
is the URL clients will use when not embedding the integration manager, and instead showing
its own purpose-built interface.
Clients should query the .well-known
information for the homeserver periodically to update the integration
manager settings for that homeserver. The client is not expected to validate or use any other information
contained in the response. Current recommendations are to query the configuration when the client starts up
and every 8 hours after that. Clients can additionally refresh the configuration whenever they feel is
necessary (such as every time the user opens the integration manager).
User-configured integration managers
Users can specify integration managers in the form of account widgets. The type
is to be m.integration_manager
and the content would look something similar to:
{
"url": "https://integrations.example.org/ui?displayName=$matrix_display_name",
"data": {
"api_url": "https://integrations.example.org"
}
}
The api_url
in the data
object is required and has the same meaning as the homeserver-defined api_url
.
The url
of the widget is analogous to the ui_url
from the homeserver configuration above, however normal
widget rules apply here.
The user is able to have multiple integration managers through use of multiple widgets.
The query string shown in the example is to demonstrate that integration managers are widgets and can make use of the template options provided to widgets.
Display order of integration managers
Clients which have support for integration managers should display at least 1 manager, but should
display multiple via something like tabs. Clients must prefer to display the user's configured
integration managers over any defaults, and if only displaying one manager must pick the first
manager after sorting the state_key
s of the applicable widgets in lexicographical order. Clients
can additionally display default managers if they so wish, and should preserve the order defined in
the various defaults. If the user has no configured integration managers, the client must prefer
to display one or more of the managers suggested by the homeserver over the managers recommended
by the client.
The client can optionally support a way to entirely disable integration manager support, even if the user and homeserver have managers defined.
The rationale for having the client prefer to use the user's integration managers first is so that the user can tailor their experience within Matrix if desired. Similarly, a homeserver may wish to subject all of their users to the same common integration manager as would be common in some organizations. The client's own preference is a last ditch effort to have an integration manager available to the user so they don't get left out.
Displaying integration managers
Clients simply open the ui_url
(or equivalent) in an iframe
or similar. In the current ecosystem,
integration managers would receive a scalar_token
to identify the user - this is no longer the case
and instead integration managers must seek other avenues for determining the user ID. Other proposals
cover how to do this in the context of the integrations API.
Integration managers shown in this way must be treated like widgets, regardless of source. In practice this means exposing the Widget API to the manager and applying necessary scoping to keep the manager as an account widget rather than a room widget.
Discovering a manager by only the domain name
Clients may wish to ask users for a single canonical domain name so they can find the manager to add to the user's account transparently. This differs from the .well-known discovery which allows homeservers to recommend their own integration manager: the homeserver is not recommending a default here. The user has instead opted to pick an integration manager (identified only by domain name) and the client is expected to resolve that to a set of URLs it can use for the manager.
Similar to the .well-known discovery done by servers (and clients during login), clients which have an
integrations domain (eg: "example.org") make a regular HTTPS request to
https://example.org/.well-known/matrix/integrations
which returns an object which looks like the
following:
{
"m.integrations_widget": {
"url": "https://integrations.example.org/ui?displayName=$matrix_display_name",
"data": {
"api_url": "https://integrations.example.org"
}
}
}
The response should be parsed as JSON. If the endpoint returns an error or is missing the m.integrations_widget
property, the client should assume there is no integrations manager running on that domain. The
m.integrations_widget
is an object which has the exact same format as the account widget for
an integration manager, described above. The client should wrap the object verbatim into the appropriate
account data location.
Because the .well-known file would be accessed by web browsers, among other platforms, the server should be using appropriate CORS headers for the request. The recommended headers are the same as those which are already recommended for homeserver discovery in the Client-Server API.
Note: this could reuse the client-server mechanic for discovery and just omit the homeserver information however that conflates many concerns together on the one endpoint. A new endpoint is instead proposed to keep the concerns isolated.
The query string shown in the example is to demonstrate that integration managers are widgets and can make use of the template options provided to widgets.
Tradeoffs
We could limit the user (and by extension, the homeserver and client) to exactly 1 integration manager and not worry about tabs or other concepts, however this restricts a user's access to integrations. In a scenario where the user wants to use widgets from Service A and bots from Service B, they'd end up switching accounts or clients to gain access to either service, or potentially just give up and walk away from the problem. Instead of having the user switch between clients, we might as well support this use case, even if it is moderately rare.
We could also define the integration managers in a custom account data event rather than defining them as a widget. Doing so just adds clutter to the account data and risks duplicating code in clients as using widgets gets us URL templating for free (see the section earlier on in this proposal about account widgets for more information: "User-configured integration managers").
Future extensions
Some things which may be desirable in the future are:
- Avatars for the different managers
- Human-readable names for the different managers
- Supporting
ui_url
s targeting specific clients for a more consistent design
Security considerations
When displaying integration managers, clients should not trust that the input is sanitary. Per the
proposal above, an integration manager is only permitted to be served from HTTP(S) URIs. A given
integration manager can still have malicious intent however, and clients should ensure any sandboxing
on the manager is appropriate such that it can communicate with the client, but cannot perform
unauthorized actions. Other URI schemes are just as dangerous and could potentially be allowed by
this proposal - use cases are less defined and desirable for schemes like file://
and are excluded
by this proposal. They can be added in a future proposal if a use case arises.