matrix-doc/specification/widgets.rst

773 lines
44 KiB
ReStructuredText

.. Copyright 2020 The Matrix.org Foundation C.I.C.
..
.. Licensed under the Apache License, Version 2.0 (the "License");
.. you may not use this file except in compliance with the License.
.. You may obtain a copy of the License at
..
.. http://www.apache.org/licenses/LICENSE-2.0
..
.. Unless required by applicable law or agreed to in writing, software
.. distributed under the License is distributed on an "AS IS" BASIS,
.. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
.. See the License for the specific language governing permissions and
.. limitations under the License.
Widgets
=======
{{unstable_warning_block_WIDGETS_RELEASE_LABEL}}
Widgets are client-side embedded applications which can communicate with Matrix clients. Widgets
are often used to present information to users and allow them to more interactively collaborate.
Due to platform constraints, unreasonable implementation effort, and client-specific design choices,
widgets are optional in Matrix. Clients are encouraged to support widgets if possible and reasonable,
though degraded behaviour, such as "open in browser" links, is considered acceptable by this
specification.
.. contents:: Table of Contents
.. sectnum::
Changelog
---------
.. topic:: Version: %WIDGETS_RELEASE_LABEL%
{{widgets_changelog}}
This version of the specification is generated from
`matrix-doc <https://github.com/matrix-org/matrix-doc>`_ as of Git commit
`{{git_version}} <https://github.com/matrix-org/matrix-doc/tree/{{git_rev}}>`_.
For the full historical changelog, see
https://github.com/matrix-org/matrix-doc/blob/master/changelogs/widgets.rst
Other versions of this specification
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The following other versions are also available, in reverse chronological order:
- `HEAD <https://matrix.org/docs/spec/widgets/unstable.html>`_: Includes all changes since the latest versioned release.
API Standards
-------------
Throughout this specification, a "client" is referred to as something which is rendering/supporting
("hosting") widgets. Widgets are unique in that they can be considered a client when referred to in
a typical network setting, though this specification ensures that a widget is always referred to as
a "widget" and the term "client" is solely reserved for the widget's host application. Note that
widgets can be hosts to widgets - deciphering which role is which in this context is left as an
exercise for the reader.
The mandatory baseline for a widget is a typical website with the optional communication protocol
described here. When communicating with a Matrix client, the mandatory baseline is the `JavaScript
postMessage API <https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage>`_ using the
protocol described by this specification. In the future more accessible transports for clients will
be considered as optional extensions, such as using operating system-specific hooks.
All objects exchanged over the Widget (``postMessage``) API are JSON objects.
In essence, widgets are typically iframes or the platform equivilant to a website which are accessible
in the client.
All of the schemas in this specification are intended to be referenced by name, and thus can safely
be used in auto-generated implementations which rely on stable naming.
Widget Kinds
------------
Widgets currently can exist in the following places:
* Within rooms, accessible by members/observers of the room.
* For a particular user, accessible only by that user.
{{definition_widgets_shared_props}}
Room Widgets
~~~~~~~~~~~~
Room widgets are defined by state events in the room, and are as such accessible to anyone who is
able to see the state of the room. Widgets can individually apply additional access restrictions
such as preventing non-joined members of the room from accessing the widget's functionality.
Clients MUST NOT show room widgets to the user unless the user is viewing that room or unless the
widget has set an appropriate always-on-screen request through the Widget API.
The ``state_key`` for a room widget MUST match the widget's ``id``. Due to this association, new
widgets in the room must use a unique ``state_key`` (and therefore ``id``). Widgets can be
updated by sending a new state event for the widget's ``state_key``.
Invalid room widgets MUST NOT be shown to users. This is also how widgets are removed from a room:
send a new state event for the same widget ID with at least the ``url`` and/or ``type`` missing
from the event content. Once Matrix allows for state events to be properly deleted then doing so
to the widget state event will be just as valid to remove it from the room.
.. WARNING::
Do not store sensitive information such as tokens, secrets, or passwords
in the widget data as it can be viewed by anyone who can see the room state.
{{m_widget_event}}
Account Widgets
~~~~~~~~~~~~~~~
Account widgets are defined in the user's account data, and are as such only visible to them.
Widgets can individually apply additional access restrictions as needed. Account widgets are
not linked to any particular room.
Account widgets are represented under the ``m.widgets`` account data event as a map of widget ID
to definition. As such, the widget's ``id`` must be unique within this object's properties. The
definition for an account widget is nearly equivilant to a room widget's state event representation,
using the ``type``, ``state_key``, ``sender``, and ``content`` fields of the state event.
Account widgets can be added by adding a new key to the ``m.widgets`` account data, edited by
modifying the appropriate ``AccountWidget`` definition, or deleted by simply removing the appropriate
property from the ``m.widgets`` acount data.
.. WARNING::
Do not store sensitive information such as tokens, secrets, or passwords
in the widget data as it is not secure or encrypted.
{{m_widgets_event}}
Rendering
---------
Widgets SHOULD be rendered using an iframe or platform equivilant. Clients can use platform-specific
rendering for widgets if they are confident in being able to do so, such as in the case of most
video conference widgets.
Clients SHOULD ask for permission to load a widget from the user prior to presenting the widget. If
the user was the last ``sender`` of a widget (not the ``creatorUserId``), the prompt can be skipped.
This prompt is strongly encouraged to ensure that users do not inadvertently send their information
to a third party. Private information such as the user's name, avatar, or IP address can be sent as
a result of how widgets work, and thus clients should attempt to prevent users from sending this
information unknowingly.
URL Templating
~~~~~~~~~~~~~~
The widget's URL is a template of what the client should render and should never be parsed by the
client to determine what the parameters are. All widgets make use of the ``data`` object to store
configuration-like values, which is also where clients should inspect for values needed to render
any UI.
Variable names for the template are the keys of the ``data`` object, with the values being the same
values of the object. Variables are included unencoded in the URL for population by the client, which
MUST use appropriate escaping to ensure the URL will be as valid as possible.
For example, given a ``data`` object like this::
{
"hello": "world",
"answer": 42
}
and a ``url`` of ``https://example.com?var1=$hello&answer=$answer`` the client MUST come up with
a URL of ``https://example.com?var1=world&answer=42`` to render. Complex types, such as objects and
arrays, for variable values do not have defined behaviour - widget creators are encouraged to stick
to "simple" types like numbers, strings, and booleans. Template variables can appear anywhere in the
URL.
Nested variables are not supported, and as such clients should be careful in their templating
approach. For example, if ``hello`` in the above example ``data`` was set to ``$answer``, the literal
value ``$answer`` would be included in the widget URL rather than ``42``.
As mentioned, clients must also encode values on behalf of the widget creator to maintain a valid
URL as much as possible. For example, ``test:value`` could become ``test%3Avalue`` when used as a
template variable value.
A few default variables, which MUST take priority over the same names in ``data``, are:
* ``matrix_user_id`` - The current user's ID.
* ``matrix_room_id`` - The room ID the user is currently viewing, or an empty string if none applicable.
* ``matrix_display_name`` - The current user's display name, or user ID if not set.
* ``matrix_avatar_url`` - The current user's avatar URL as reported in their profile, or and empty
string if not present. This shouldn't be the ``mxc://`` form of the user's avatar, but instead the
full HTTP URL to the ``/media/download`` endpoint for their avatar from the Client-Server API.
* ``matrix_widget_id`` - The widget's ID to allow the widget to communicate effectively with the client.
.. WARNING::
The ``matrix_user_id`` variable MUST NOT be assumed to be the current authenticated user due to
how trivial it is to provide false details with. Widgets which need to store per-user details
or private information will need to verify the user's identity in some other way.
Security Considerations
~~~~~~~~~~~~~~~~~~~~~~~
Clients SHOULD check to ensure that widgets are valid URLs *after* templating but *before* rendering
or asking for permission to load. Invalid URLs from the client's perspective should not be shown to
the user and can be treated as though no ``url`` was present (i.e.: a deleted/invalid widget).
Clients MUST NOT attempt to render widgets with schemes other than ``http:`` and ``https:``. Widgets
using alternative schemes, including template variables as schemes, are considered invalid and thus
should be ignored. This is to prevent widget creators from using ``javascript:`` or similar schemes
to gain access to the user's data.
Clients SHOULD apply a sandbox to their iframe or platform equivilant to ensure the widget cannot
get access to the data stored by the client, such as access tokens or cryptographic keys. More
information on origin restrictions is in the Widget API's security considerations section.
Clients should be aware of a potential `CSRF <https://owasp.org/www-community/attacks/csrf>`_
opportunity due to clients making arbitrary ``GET`` requests to URLs. Typical sites should not
be using ``GET`` as a state change method, though it is theoretically possible.
Widget Types
------------
A widget's ``type`` can be one of the following specified types or a custom type which preferably
uses the Java package naming convention as a namespace. Types prefixed with the ``m.`` namespace
are reserved by this specification.
Besides the ``type`` itself, widget types influence the widget's ``data`` by requiring specified
keys to exist. It is expected that the widget will use these keys as variables for their URL, though
this specification does not require such behaviour. Clients SHOULD treat widgets without the
required ``data`` properties for the types specified here as invalid widgets, thus not rendering
them.
Clients MUST treat widgets of unknown types as ``m.custom``, unless it is impossible for the client
to render the widget kind in that way. For example, custom widgets at the per-user rather than
per-room level might not be possible and thus can be treated as invalid (ignored).
Clients are not required to support all of these widget types (with the implied exception of
``m.custom``) as they can all be safely represented as ``m.custom`` widgets. Similarly, if a
widget fails the schema requirements for its ``type`` then it should be treated as ``m.custom``
by the client.
Custom/Basic Widgets
~~~~~~~~~~~~~~~~~~~~
Custom widgets are the most basic form of widget possible, and represent the default behaviour
for all widgets. They have an explicit widget ``type`` of ``m.custom``, though any
unknown/unsupported widget type for the client will be treated as a custom widget. They have
``data`` matching ``CustomWidgetData``.
{{definition_widgets_custom_data}}
Jitsi Meet Conferences
~~~~~~~~~~~~~~~~~~~~~~
`Jitsi Meet <https://jitsi.org/jitsi-meet/>`_ conferences can be held on a per-room basis with
a widget ``type`` of ``m.jitsi`` and ``data`` matching ``JitsiWidgetData``.
.. Note::
Though technically possible, this widget type should not be used outside of room widgets.
{{definition_widgets_jitsi_data}}
Stickerpickers
~~~~~~~~~~~~~~
Stickerpickers are user widgets which allow the user to send ``m.sticker`` events to the current
room using the Widget API described by this specification. They have a widget ``type`` of
``m.stickerpicker`` and ``data`` which matches ``StickerpickerWidgetData``.
.. Note::
Though technically possible, this widget type should not be used outside of user widgets.
{{definition_widgets_stickerpicker_data}}
Widget Wrappers
---------------
Most widgets in the wild are "wrapped" with some website that provides added functionality or
handles the Widget API communications. They have no formal specification as they are implicitly
handled as part of rendering widgets. As such, they also have no specific requirements to have
any particular behaviour.
A wrapper typically appears on a widget as a ``url`` pointing to a resource which then embeds
the content within another iframe. This allows the widget to be gated by authentication or be
more easily embedded within Matrix (as would be the case for Spotify and similar widgets - the
content to be embedded does not translate directly to a Matrix widget and instead needs a bit
of help from a wrapper to embed nicely).
Widget API
----------
The widget API is a bidirectional communication channel between the widget and the client, initiated
by either side. This communication happens over the `JavaScript postMessage API
<https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage>`_.
The API is split into two parts: ``fromWidget`` (widget -> client) and ``toWidget`` (client -> widget).
Both have the same general API shape: A request, called an ``action``, is sent to the other party
using the ``WidgetApiRequest`` schema. The other party then processes the request and returns an
object matching ``WidgetApiResponse``.
All communication is done within a "session", where the first message sent to either side indicates
the start of the session. Only the client can close/terminate a session by unloading/reloading the
widget.
The ``data`` of a ``WidgetApiRequest`` varies depending on the ``action`` of the request, as does the
``response`` of a ``WidgetApiResponse``.
{{definition_widgets_api_request}}
{{definition_widgets_api_response}}
Timeouts
~~~~~~~~
All requests sent over the API require a response from the other side, even if the response is to
just acknowledge that the request happened. Both widgets and clients should implement timeouts on
their requests to avoid them hanging forever. The default recommended timeout is 10 seconds, after
which the request should be considered not answered and failed. Requests can be retried if they are
failed, though some actions do not lend themselves well to idempotency.
Error Handling
~~~~~~~~~~~~~~
When the receiver fails to handle a request, it should acknowledge the request with an error response.
Note that this doesn't include timeouts, as the receiver will not have had an error processing the
request - it simply did not receive it in time.
An error response takes the shape of a ``WidgetApiErrorResponse``.
{{definition_widgets_api_error}}
Versioning
~~~~~~~~~~
The Widget API version tracks the version of this specification (``r0.1.0`` is Widget API version
``0.1.0``, for example). Both widgets and clients can perform a request with action of
``supported_api_versions`` (``SupportedVersionsActionRequest``) to get the other side's list of
supported versions (``SupportedVersionsActionResponse``). The sender SHOULD NOT use actions which
are unsupported by the intended destination. In the event that the sender and destination cannot
agree on a supported version, either side should abort their continued execution
Actions in this specification list which version they were introduced in for historical purposes.
Actions will always be backwards compatible with prior versions of the specification, though the
specification from time to time may add/remove actions as needed.
In order for a widget/client to support an API version, it MUST implement all actions supported
by that version. For clarity, all actions presented by this document at a given version are
supported by that version. Implicitly, the actions to request supported API versions are mandatory
for all implementations.
.. Note::
For historical purposes, ``0.0.1`` and ``0.0.2`` are additionally valid versions which implement
the same set as ``0.1.0`` (the first version of this specification).
{{definition_widgets_supported_versions_action_request}}
{{definition_widgets_supported_versions_action_response}}
Initiating Communication
~~~~~~~~~~~~~~~~~~~~~~~~
Immediately prior to rendering a widget, the client MUST prepare itself to handle communications
with the widget. Typically this will result in setting up appropriate event listeners for the
API requests.
If the widget was set up with ``waitForIframeLoad: false``, the widget will initiate the
communication by sending a ``fromWidget`` request with ``action`` of ``content_loaded`` (see below).
If ``waitForIframeLoad`` was ``true``, the client will initiate communication once the iframe or
platform equivilant has loaded successfully (see ``waitForIframeLoad``'s description).
Once the client has established that the widget has loaded, as defined by ``waitForIframeLoad``,
it initiates a capabilities negotiation with the widget. This is done using the ``capabilities``
action on the ``toWidget`` API.
The capabilities negotiated set the stage for what the widget is allowed to do within the session.
Clients MUST NOT re-negotiate capabilities after the session has been established.
Prior to the session being initiated, neither side should be sending actions outside of those
required to set up the session. Version checking can happen at any time by either side, though
the initiator of the session should be left responsible for the first version check. For example,
if the client is waiting for a ``content_loaded`` action then the widget should be the one to
request the supported API versions first. Once a version check has been started by one side, it is
implied that the other side can do the same.
A broad sequence diagram for ``waitForIframeLoad: false`` is as follows::
+---------+ +---------+
| Client | | Widget |
+---------+ +---------+
| |
| Render widget |
|-------------- |
| | |
|<------------- |
| |
| `supported_api_versions` request |
|<------------------------------------------|
| |
| `supported_api_versions` response |
|------------------------------------------>|
| |
| `supported_api_versions` request |
|------------------------------------------>|
| |
| `supported_api_versions` response |
|<------------------------------------------|
| |
| `content_loaded` request |
|<------------------------------------------|
| |
| Acknowledge `content_loaded` request |
|------------------------------------------>|
| |
| `capabilities` request |
|------------------------------------------>|
| |
| `capabilities` response |
|<------------------------------------------|
| |
| Approve/deny capabilities |
|-------------------------- |
| | |
|<------------------------- |
| |
A broad sequence diagram for ``waitForIframeLoad: true`` is as follows::
+---------+ +---------+
| Client | | Widget |
+---------+ +---------+
| |
| Render widget |
|-------------- |
| | |
|<------------- |
| |
| | iframe loading
| |---------------
| | |
| |<--------------
| |
| Implicit `onLoad` event from iframe |
|<-----------------------------------------|
| |
| `supported_api_versions` request |
|----------------------------------------->|
| |
| `supported_api_versions` response |
|<-----------------------------------------|
| |
| `supported_api_versions` request |
|<-----------------------------------------|
| |
| `supported_api_versions` response |
|----------------------------------------->|
| |
| `capabilities` request |
|----------------------------------------->|
| |
| `capabilities` response |
|<-----------------------------------------|
| |
| Approve/deny capabilities |
|-------------------------- |
| | |
|<------------------------- |
| |
After both sequence diagrams, the session has been successfully established and can continue as
normal.
Verifying Capabilities
++++++++++++++++++++++
The client MUST have a mechanism to approve/deny capabilities. This can be done within the client's
code, not involving the user, by using heuristics such as the origin and widget type, or it can be
done by involving the user with a prompt to approve/deny particular capabilities.
The capabilities negotiation does not specify a way for the client to indicate to the widget which
capabilities were denied. The widget SHOULD only request the bare minimum required to function and
assume that it will receive all the requested capabilities. Clients SHOULD NOT automatically approve
all requested capabilities from widgets.
Whenever a widget attempts to do something with the API which requires a capability it was denied,
the client MUST respond with an error response indicating as such.
Any capabilities requested by the widget which the client does not recognize MUST be denied
automatically. Similarly, a client MUST NOT send requests to a widget which require the widget
to have been aprroved for a capability that it was denied access to. Clients MUST NOT approve
capabilities the widget did not request - these are implicitly denied.
A complete list of capabilities can be found in the `Available Capabilities`_ section.
Available Capabilities
~~~~~~~~~~~~~~~~~~~~~~
The following capabilities are defined by this specification. Custom capabilities can only be
defined via a namespace using the Java package naming convention.
Screenshots
+++++++++++
``m.capbility.screenshot`` can be requested by widgets if they support screenshots being taken
of them via the ``screenshot`` action. Typically this is only used to verify that the widget API
communications work between a client and widget. Widgets cannot use this capability to initiate
screenshots being taken of them - clients must request screenshots with the ``screenshot`` action.
Sticker Sending
+++++++++++++++
``m.sticker`` can be requested by widgets if they would like to send stickers into the room the
user is currently viewing. This should be implicitly approved by clients for ``m.stickerpicker``
widgets.
Always On Screen
++++++++++++++++
``m.always_on_screen`` can be requested by widgets if they would like to be able to use the
``set_always_on_screen`` action. This should be implicitly approved by clients for ``m.jitsi``
widgets (see the action's spec for more information).
OpenID Connect Authentication
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Widgets can request OpenID Connect credentials from the client (which in turn requests them from the
homeserver) to validate that the current user is who they say they are. The credentials are validated
out of band from the client to ensure the client is not able to falsify them.
There is no required capability for using this flow, however clients SHOULD prompt the user to
approve the widget's request to validate their identity. This prompt can have a "always remember for
this widget"-style checkbox on it, which is supported by the API exchange. Including the user in the
approval prompt does mean that the request is at risk of timing out, and as such there is a two part
exchange involving the client and widget.
The request is always initiated by the widget using the ``fromWidget`` ``get_openid`` action. This
is either responded to immediately with an OpenID Connect token, an indication of the request being
blocked, or an indication that the user is making a decision. When a user makes a selection, the
client uses the ``toWidget`` API to send a ``openid_credentials`` action with the relevant state.
After the widget receives the token from the client, it should validate it with the federation API.
Typically this means handing it off to a backend service which will validate the token and return
another credential the widget can use for future requests.
.. WARNING::
Like with the OpenID Connect endpoints described by the Client-Server API and Federation API, it
is important that the widget ensure the user ID returned by the server matches the server name
given in the token from the client.
When needed, the client MUST call ``/_matrix/client/%CLIENT_MAJOR_VERSION%/user/{userId}/request_token``
to get the needed token to pass through to the widget.
A typical diagram of this flow is::
+-------+ +---------+ +---------+ +---------------+ +-------------+
| User | | Client | | Widget | | WidgetBackend | | Homeserver |
+-------+ +---------+ +---------+ +---------------+ +-------------+
| | | | |
| | Establish Widget API session | | |
| |----------------------------------------->| | |
| | | | |
| | Establish Widget API session | | |
| |<-----------------------------------------| | |
| | | | |
| | fromWidget get_openid request | | |
| |<-----------------------------------------| | |
| | | | |
| | ack with state "request" | | |
| |----------------------------------------->| | |
| | | | |
| Ask if the widget can verify their identity | | | |
|<-------------------------------------------------| | | |
| | | | |
| Approve | | | |
|------------------------------------------------->| | | |
| | | | |
| | Call /_matrix/client/{version}/user/{userId}/request_token | |
| |-------------------------------------------------------------------------------------------------------------------------------------------------------->|
| | | | |
| | | | OpenID Connect token |
| |<--------------------------------------------------------------------------------------------------------------------------------------------------------|
| | | | |
| | toWidget openid_credentials request | | |
| |----------------------------------------->| | |
| | | | |
| | ack with empty response object | | |
| |<-----------------------------------------| | |
| | | | |
| | | Send received token for validation | |
| | |------------------------------------------->| |
| | | | |
| | | | Federated call to /_matrix/federation/v1/openid/userinfo |
| | | |---------------------------------------------------------------->|
| | | | |
| | | | User information |
| | | |<----------------------------------------------------------------|
| | | | |
| | | | Verify returned user information |
| | | |--------------------------------- |
| | | | | |
| | | |<-------------------------------- |
| | | | |
| | | Successful validation response | |
| | |<-------------------------------------------| |
| | | | |
``toWidget`` API
~~~~~~~~~~~~~~~~~~
The ``toWidget`` API is reserved for communications from the client to the widget. Custom
actions can be defined by using the Java package naming convention as a namespace.
Capabilities
++++++++++++
:Introduced in: ``0.1.0``
As part of the capabilities negotiation, the client sends a request with an action of
``capabilities`` (``CapabilitiesActionRequest``) to the widget, which replies with the requested
set of capabilities (``CapabilitiesActionResponse``).
{{definition_widgets_capabilities_action_request}}
{{definition_widgets_capabilities_action_response}}
Screenshots
+++++++++++
:Introduced in: ``0.1.0``
If the widget is approved for use of the ``m.capbility.screenshot`` capability, the client can
send a ``screenshot`` action (``ScreenshotActionRequest``) to request an image from the widget
(returned as a ``ScreenshotActionResponse``).
.. Note::
This is typically only used to verify that communication is working between the widget and client.
.. WARNING::
Widgets have an ability to send extremely large files and non-images via this action. Clients
should only enable support for screenshots in a trusted environment, such as when a widget
developer is making use of the client to test their widget.
{{definition_widgets_screenshot_action_request}}
{{definition_widgets_screenshot_action_response}}
Widget Visibility
+++++++++++++++++
:Introduced in: ``0.1.0``
The client can indicate to the widget whether it is visible or not to the user with the ``visbility``
action request (``VisibilityActionRequest``). If the widget does not receive visibility information,
it must assume that it is visible to the user.
Typically this action is not used on room widgets as they are visible implicitly to the user when
they view that room. Account widgets, however, often get rendered in the background by the client
and thus can be hidden/shown at times.
.. Note::
Stickerpicker widgets and similar often make the best use of this to reload the user's available
content when the widget gets shown again.
This action should only be sent when visibility of the widget to the user changes.
{{definition_widgets_visibility_action_request}}
{{definition_widgets_visibility_action_response}}
OpenID Connect Credential Information
+++++++++++++++++++++++++++++++++++++
:Introduced in: ``0.1.0``
.. Note::
This section assumes the reader has the prior knowledge established by the
`OpenID Connect Authentication <#openid-connect-authentication>`_ section.
This action is used by the client to indicate that the user has made a selection regarding the
prompt to confirm if the widget can verify their identity.
If approved, the request will contain the OpenID Connect token the widget will have to verify. If
defined, the request will indicate as such.
{{definition_widgets_openid_credentials_action_request}}
{{definition_widgets_openid_credentials_action_response}}
``fromWidget`` API
~~~~~~~~~~~~~~~~~~
The ``fromWidget`` API is reserved for communications from the widget to the client. Custom actions
can be defined by using the Java package naming convention as a namespace.
Indicating Content Loaded
+++++++++++++++++++++++++
:Introduced in: ``0.1.0``
In some rendering cases, the widget is expected to send a ``content_loaded`` action request taking
the shape of ``ContentLoadedActionRequest``. The widget can send this any time, even when not
required for establishing the session. Widgets SHOULD NOT send this action after the session has
been established.
{{definition_widgets_content_loaded_action_request}}
{{definition_widgets_content_loaded_action_response}}
Sending Stickers
++++++++++++++++
:Introduced in: ``0.1.0``
If the widget is approved for use of the ``m.sticker`` capability, the widget can send ``m.sticker``
action requests (``StickerActionRequest``) to have the client post an ``m.sticker`` event to the
room the user is currently viewing. If the room is encrypted, the client is responsible for
encrypting the widget's implied event.
The stickers widgets produce MUST meet the requirements of stickers in ``m.sticker`` events. For
creating the sticker event, the client uses the ``name`` or ``description`` from the request
in the event's ``body``, and otherwise copies the ``url`` and ``info`` values from the request
to the event directly (potentially with some validation).
{{definition_widgets_sticker_action_request}}
{{definition_widgets_sticker_action_response}}
Always On Screen
++++++++++++++++
:Introduced in: ``0.1.0``
If the widget is approved for use of the ``m.always_on_screen`` capability, the widget can request
that the client keep it always on screen with a ``set_always_on_screen`` action request
(``StickyActionRequest``).
Widgets by default are *not* always on screen, and only one widget at a time can be always on the
screen. Typically this is used by video conferencing widgets to ensure that the call is not disrupted
when the user switches rooms, and as such clients SHOULD ignore the restriction regarding only
rendering widgets when the user is viewing that room while the widget has requested to be always on
screen.
{{definition_widgets_sticky_action_request}}
{{definition_widgets_sticky_action_response}}
Requesting OpenID Connect Tokens
++++++++++++++++++++++++++++++++
:Introduced in: ``0.1.0``
.. Note::
This section assumes the reader has the prior knowledge established by the
`OpenID Connect Authentication <#openid-connect-authentication>`_ section.
This action is used by the widget to ask the client to start the OpenID Connect token exchange.
The client has three possible responses:
* A ``state`` of ``allowed`` alongside the OpenID Connect token. This is typically used if the user
indicated that the widget is always allowed to verify their identity.
* A ``state`` of ``blocked``. This is typically used when the user has indicated that the widget
can never verify their identity.
* A ``state`` of ``request``. This indicates that the client is asking the user for permission and
will follow up with an appropriate ``toWidget`` ``openid_credentials`` request later.
{{definition_widgets_get_openid_action_request}}
{{definition_widgets_get_openid_action_response}}
Security Considerations
~~~~~~~~~~~~~~~~~~~~~~~
The Widget API can allow for significant control of a client/widget, and thus needs to be secured
as much as possible. Clients should refuse/ignore requests and responses from origins other than
the widget's rendered origin, and should verify that the widget ID matches the expected value.
Widgets have a harder time of determining the origin, though they can rely on techniques like
``window.parent`` to ensure they are talking/responding to the right place.