261 lines
18 KiB
Markdown
261 lines
18 KiB
Markdown
# MSC1956: Integrations API
|
|
|
|
"Integration managers" are applications that help clients bring integrations (bridges, bots, widgets, etc)
|
|
to users. This can be for things like setting up an IRC bridge or adding a Giphy bot to the room. Integration
|
|
managers have been popularized by Riot, however other clients also have support for concept as well although
|
|
to a lesser extent.
|
|
|
|
Integration managers are important to the Matrix ecosystem as they help abstract away the underlying integration
|
|
and allow providers of the integratiosn to manage access to them. For example, there are multiple XMPP bridges
|
|
available in the Matrix ecosystem and an integration manager is in the best position to handle the different APIs
|
|
each exposes, generalizing the API exposed to clients. Similarly, the integration manager could charge for access
|
|
to specific integrations such as sticker packs or per-user access to a bridge.
|
|
|
|
This proposal introduces a new Matrix API: the "Integrations API" (or "Integrations Specification") which covers
|
|
how integration managers and integrations themselves cooperate with clients. Typically these kinds of extensions
|
|
to Matrix would be put into the Client-Server API, however the integration manager is not typically the same as
|
|
the user's homeserver and is therefore ideal to be specified indepdently.
|
|
|
|
|
|
## Glossary
|
|
|
|
Due to the introduction of a new API, some common terminology is to be established:
|
|
|
|
An **Integration Manager** (or *Integrations Manager*, or simply *Manager*) is an application which assists users
|
|
and/or clients in setting up *Integrations*.
|
|
|
|
**Integrations** are something the *Integration Manager* exposes, such as *Bots*, *Bridges*, and *Widgets*.
|
|
|
|
A **Bot** is typically a Matrix user which provides a utility service, such as Github Notifications or reaction
|
|
GIFs.
|
|
|
|
A **Bridge** is typically an Application Service which proxies events between Matrix and a 3rd party platform,
|
|
such as IRC. Bridges may also operate in a single direction and have other features like *Puppeting*, which are
|
|
not covered here. For information on the various types of bridging, please see the
|
|
[reference guide](https://matrix.org/docs/guides/types-of-bridging.html).
|
|
|
|
**Widgets** are embedded web applications in a Matrix client. These are split into two types: **Account Widgets**
|
|
and **Room Widgets**. *Account Widgets* are specific to a particular Matrix user and not shared with other users
|
|
whereas *Room Widgets* are shared with the members of the room they reside in.
|
|
|
|
A **Trusted Integration Manager** is an *Integration Manager* which the client has deemed trustworthy by its own
|
|
criteria. For example, this may be defined as being known as an account widget, discovered by .well-known, or
|
|
being set in the client's configuration. By proxy, an **Untrusted Integration Manager** is the opposite.
|
|
|
|
The **Integration Manager API** is the set of HTTP endpoints which clients can use to interact with a given
|
|
*Integration Manager*.
|
|
|
|
The **Widget API** is the set of `postMessage` APIs which are used for clients and *Widgets* to communicate with
|
|
each other when embedded.
|
|
|
|
The **Integrations API** is the set of both the *Integration Manager API* and *Widget API* as well as any other
|
|
details which affect *Widgets* or *Integration Managers* and their interactions with clients.
|
|
|
|
|
|
## Proposal
|
|
|
|
A new Integrations API be introduced into Matrix which consists of the components listed in this proposal.
|
|
|
|
**Components**:
|
|
|
|
* API Standards (see later section of this proposal)
|
|
* Discovery - [MSC1957](https://github.com/matrix-org/matrix-doc/pull/1957)
|
|
* Widgets
|
|
* Includes [MSC1236](https://github.com/matrix-org/matrix-doc/issues/1236)
|
|
* Includes [MSC1958](https://github.com/matrix-org/matrix-doc/pull/1958)
|
|
* Includes [MSC1960](https://github.com/matrix-org/matrix-doc/pull/1960)
|
|
* MSC for extensions and alterations not yet defined
|
|
* ***TODO: MSC for each or group them by subject?***
|
|
* The first version of the Widget API is to be `0.1.0`, with the existing `0.0.x` versions being flagged as
|
|
development versions which are otherwise unspecified.
|
|
* Sticker picker and custom emoji
|
|
* Includes [MSC1951](https://github.com/matrix-org/matrix-doc/pull/1951)
|
|
* Includes [MSC1959](https://github.com/matrix-org/matrix-doc/pull/1959)
|
|
* Authentication in integration managers - [MSC1961](https://github.com/matrix-org/matrix-doc/pull/1961)
|
|
* Terms of service / policies - [MSC2140](https://github.com/matrix-org/matrix-doc/pull/2140)
|
|
* Integration manager specific APIs
|
|
* MSC and scope not yet defined
|
|
|
|
***TODO: Define where paid integrations, OAuth, etc all fit if at all.***
|
|
***TODO: Finalize what goes into this spec.***
|
|
|
|
|
|
## Proposed API standards
|
|
|
|
All HTTP APIs in this specification must consume and produce JSON unless otherwise indicated. Errors emitted by
|
|
these APIs should follow the standard error responses defined by other APIs in Matrix. Some common error responses
|
|
implementations may encounter are:
|
|
* `403` `{"errcode":"M_UNKNOWN_TOKEN","error":"Invalid token"}`
|
|
* `400` `{"errcode":"M_MISSING_PARAM","error":"Missing 'matrix_server_name'"}`
|
|
* `400` `{"errcode":"M_INVALID_PARAM","error":"'matrix_server_name' must be a string"}`
|
|
* `400` `{"errcode":"M_NOT_FOUND","error":"The sharable URL did not resolve to a pack"}`
|
|
|
|
|
|
## Tradeoffs
|
|
|
|
Specifying a whole new set of APIs means introducing another complex system into Matrix, potentially causing
|
|
confusion or concerns about the architecture of Matrix or its implementations. It is believed by the author that
|
|
having a dedicated set of APIs for this system within Matrix is important to reduce the burden on homeserver
|
|
authors and to support client authors in their ambitions to grow Matrix through bridges, bots, etc.
|
|
|
|
It is also questionable if integration managers should be a concept within Matrix as the APIs which clients would
|
|
be interacting with can be generically exposed by the integrations themselves without the need for a manager. The
|
|
manager's role in this specification is to provide clients with the opportunity to quickly get themselves connected
|
|
with the larger Matrix ecossytem without adding the burden of designing their own interface. The majority of the
|
|
APIs are defined such that a client is able to put their own UI on top of the manager instead of embedding that
|
|
manager if desired by the client.
|
|
|
|
|
|
## Potential issues
|
|
|
|
Clients which support today's ecosystem of integration managers have a lot of work to do to support this proposal
|
|
in all its parts. In addition, integration managers themselves have a decent amount of work in order to become
|
|
compliant. The exercise of this proposal is not to make development harder for the projects in the ecosystem, but
|
|
to standardize on a set of APIs which bridge the gap between managers while also patching inadequacies in the current
|
|
systems.
|
|
|
|
|
|
## Security considerations
|
|
|
|
Each proposal which branches off this proposal has its own set of security considerations. As a whole, clients are
|
|
expected to make decisions on which integration managers are trusted, and integration managers are encouraged to do
|
|
the same with clients and integrations.
|
|
|
|
----
|
|
|
|
## How all of this is meant to work (versus before)
|
|
|
|
This portion of the proposal is not required reading - it is supplemental information to help explain how integration
|
|
managers work in a world with this API and prior. This is also meant to be moderately high level and doesn't go into
|
|
the specific API endpoints one would call.
|
|
|
|
### Integration managers today (pre-API)
|
|
|
|
Integration managers are very much a Riot concept that has lead to enough utility to make it worth putting the idea
|
|
in the spec. An integration manager is typically just a UI for interacting with bridges/bots/widgets instead of having
|
|
to do all the bits manually or through a command line-like interface. Riot defines an integration manager as a set
|
|
of URLs: one for the UI (`ui_url`) and one for its API (`rest_url`). There are other URLs that also take place, but
|
|
they're covered in more detail later on in this text.
|
|
|
|
Before an integration manager can even be shown to the user, an authentication dance must take place. This is to
|
|
acquire an authentication token (wrongly named a `scalar_token` in Riot) - this token is then provided to the integration
|
|
manager where applicable via a `scalar_token` query string parameter. The auth dance involves getting an OpenID token
|
|
from the homeserver for the user, passing that to the integration manager via its API URL, and getting back a token
|
|
it can then use for future requests. The integration manager internally takes the OpenID token and verifies it by
|
|
doing a federated request to the homeserver - this is how it claims the token and gets a user ID back. This is also
|
|
why homeservers generally need working federation in order to use integrations, at least until recently when Synapse
|
|
could support exposing the OpenID claim endpoint without the rest of federation (Modular and similar deployments use
|
|
this).
|
|
|
|
The entire auth dance is done in the background, so the user doesn't see this happening. If any of the steps go wrong,
|
|
the user is warned that the integration manager is offline/inaccessible. After the auth dance, Riot does a terms of
|
|
service check to ensure the user has accepted all applicable policies. It does this by using the API URL to get the
|
|
authentication token owner's information (`/account`) which can return an error if there are unaccepted policies. If
|
|
there are policies to accept, Riot prompts before continuing. Provided the user accepts all the policies, Riot moves
|
|
on to rendering the integration manager window using the UI URL as a base. Depending on what the user clicked depends
|
|
on how the URL is constructed. Typically users would click the 4/9 squares in the context of the room, so a generic
|
|
URL referencing the "homepage" of the manager and the room ID is supplied to the manager. The user's authentication
|
|
token for the manager is also included in the URL.
|
|
|
|
The integration manager then takes all the information from the URL and starts to render the UI. In this case, it would
|
|
be rendering the homepage so it asks its backend for information about integrations it supports and starts trying to
|
|
figure out which ones are feasible. In the process, it queries Riot itself for some information (bot membership, room
|
|
publicity, room member count, etc) - this is done over a special `postMessage` API named `ScalarMessaging` (which is
|
|
not really Scalar-specific). Note that this API is different from the Widget `postMessage` API - more on that in a bit.
|
|
|
|
The ScalarMessaging API acts in the background and allows the integration manager to check the state of things as well
|
|
as perform actions. For example, when the user wants to add a bot to the room the manager will use the ScalarMessaging
|
|
API to determine if the bot is already in the room, and if it isn't it will use ScalarMessaging to cause the user to
|
|
invite the bot to the room. The expectation is generally that the bot will auto-accept invites without needing the
|
|
integration manager or Riot to interfere. When the bot is being removed from the room, it is not kicked through the API.
|
|
Instead, the integration manager calls its backend which impersonates the bot to leave the room.
|
|
|
|
The ScalarMessaging API is locked down enough to ensure only the integration manager can interact with it.
|
|
|
|
When the user finally wants to close the integration manager, they can click outside of it to have Riot dismiss the dialog
|
|
or they can click a close button within the integration manager which uses the ScalarMessaging API to close itself.
|
|
|
|
The other thing the ScalarMessaging class lets integration managers do is add widgets into the room and onto the user's
|
|
account. Widgets added by an integration manager are almost always wrapped by the integration manager itself. Widgets
|
|
are simply URLs that are rendered in iframes, so when the integration manager wraps a widget it means there's the top
|
|
level iframe supplied by Riot and another iframe supplied by the integration manager's wrapper. The wrapper usually
|
|
provides some features like being able to talk the Widget `postMessage` API (here on out known as the Widget API)
|
|
and a fullscreen button. Dimension, Scalar's opensource "competitor", doesn't require any authentication in order to
|
|
load this widget wrapper however Scalar does. Riot solves this by having a "widget URL whitelist" in the configuration
|
|
for when to provide an authentication token to the widget through its URL.
|
|
|
|
Scalar has two methods of checking for an authentication token, both of which are used to try and avoid the dreaded
|
|
"Forbidden" error page. The first is simply using the authentication token it was provided by the client. The second
|
|
involves cookies that are scoped to the Scalar domain. Typically the cookie is set after a token has been successfully
|
|
used (as provided by the client). The cookies helps avoid the forbidden error page when Riot decides it can't send
|
|
the authentication token to the widget/manager (typically when people change to Dimension or another integration manager).
|
|
|
|
Dimension uses a similar scheme for ensuring it has a token available, though it uses localstorage in place of cookies.
|
|
When both the provided and stored token fail, Dimension uses Riot's OpenID exchange API to acquire a new token by asking
|
|
the user for permission to share their identity. This is supposed to be used as a last resort, given Dimension only needs
|
|
a token to determine the user's stickerpacks and nothing more (for widgets).
|
|
|
|
It is worth noting that widgets are designed such that the integration manager gets no special treatment, however in
|
|
practice integration manager widgets are very difficult to manage from a client perspective, primarily for authentication
|
|
reasons. Widgets are simply supposed to be iframes with no dealing of tokens from a spec perspective.
|
|
|
|
The sticker picker is a particularly interesting widget in that it's at the user's account level and not in a room. By
|
|
nature of being a widget, it is supposed to be independent of the integration manager however in practice users find it
|
|
confusing when their integration manager changes and their sticker picker is the "old" one. This is something that can
|
|
usually be mitigated by the client (removing/replacing the sticker picker widget when the user asks to change their
|
|
integration manager), but so far no client has opted to do so.
|
|
|
|
The sticker picker widget uses a capabilities subsystem in the Widget API to get permission to send events (stickers)
|
|
on behalf of the user. Sticker pickers are one of the widgets which require authentication so the widget can show the
|
|
user the sticker packs they have enabled. Riot currently has the capabilities exchange happen in the background, though
|
|
it could expose it as a dialog to the user.
|
|
|
|
The final aspect of integration managers in the current ecosystem is conference calls: Riot uses a Jitsi widget to make
|
|
a conference call. Because different integration managers have different opinions on how the Jitsi widget should be declared,
|
|
Riot supports a configuration option to change the base URL of the Jitsi widget before it gets added to the room state.
|
|
The Jitsi URL in the config almost always points to an integration manager which wraps the widget.
|
|
|
|
### Integration managers in a post-API world
|
|
|
|
This proposal defines an API for how integration managers are supposed to work, taking into consideration user expectations,
|
|
technical limitations, and other issues with the current state of affairs. Most critically, this new API brings forth a
|
|
new authentication scheme for integration managers (and therefore widgets) by making somewhat radical changes to the way
|
|
things work.
|
|
|
|
The first major change is that integration managers become widgets. This is confusing at first, but if we run the thought
|
|
experiment for a bit it starts to make some sense. Widgets already have a well-specified API they can use to talk to the
|
|
client, and with some modifications (proposed here) the same API can be used to run an integration manager. This proposal
|
|
builds on the capabilities system to add additional actions needed by integration managers, such as adding readonly views
|
|
of the room membership and ability to invite users. This does away with the existing API which is not as well specified.
|
|
|
|
Widgets under this proposal also lose their authentication tokens, which means integration managers also lose an authentication
|
|
token. Authentication tokens are not completely gone though: the APIs to get them still exist for reasons described a bit
|
|
later on, and widgets can use the now-specified OpenID exchange API to acquire a token if it needs one. There's additionally
|
|
a provision within the proposal to allow clients to skip the prompt under some circumstances, such as when dealing with a
|
|
sticker picker or integration manager - these kinds of widgets are likely to need/request OpenID information for good reason
|
|
so the client can do so quietly in the background without nagging the user. Other widgets, like custom widgets, are expected
|
|
to prompt for confirmation from the user.
|
|
|
|
With this new authentication system, clients no longer need to track a whitelist of widget URLs to append tokens to and
|
|
generally don't need to track the tokens for themselves. Terms of service acceptance is also expected to be done by the
|
|
widgets (including integration manager) themselves, though smarter clients like Riot can try and optimize for it by still
|
|
doing the auth&check dance.
|
|
|
|
This proposal also defines a set of APIs for clients to interact with the integration manager directly, avoiding the use
|
|
of iframes where applicable. The theory is that clients wanting to control the integrations experience can do so by invoking
|
|
the integration manager's API on top of the client's native UI/UX. An example of where this might be worthwhile for Riot is
|
|
the sticker picker: instead of rendering an iframe and having to deal with a lot of complicated APIs, Riot could instead
|
|
just do the auth dance and get all the information it needs from the widget. A similar approach could be taken for adding
|
|
an IRC bridge to a room: if the client were driving the manager's API, it could offer a button instead of rendering a whole
|
|
iframe.
|
|
|
|
To handle the Jitsi use case, this proposal introduces a "make me a widget" API. The API exists on integration managers to
|
|
construct a widget for the client, doing away with Riot's Jitsi URL in the config.
|
|
|
|
Integration managers like Scalar can still require an authentication token to render the actual widget by having a small
|
|
wrapper which uses the OpenID exchange API. The wrapper should also persist the token somewhere (cookies/localstorage) so
|
|
it can load the next time unobtrusively.
|
|
|
|
Fundamentally the power an integration manager has is unchanged by this proposal, though how they perform actions is vastly
|
|
different, hopefully for the better.
|