Merge branch 'main' into travis/msc/media-integrity
@ -0,0 +1,92 @@
|
||||
# MSC1692: Terms of service at registration
|
||||
|
||||
At registration, homeservers may wish to require the user to accept a given set of policy documents,
|
||||
such as a terms of service and privacy policy. There may be many different types of documents, all of
|
||||
which are versioned and presented in (potentially) multiple languages.
|
||||
|
||||
This proposal covers requiring users to accept the list of documents during registration. Future
|
||||
improvements could include informing the user *after* registration that a document has changed, which
|
||||
has been spun out to [MSC3012](https://github.com/matrix-org/matrix-spec-proposals/pull/3012).
|
||||
|
||||
## Proposal
|
||||
|
||||
The [User-Interactive Authentication](https://spec.matrix.org/v1.9/client-server-api/#user-interactive-authentication-api)
|
||||
API (UIA) is currently used during registration to create a new account. In future, it is expected
|
||||
that OIDC will be used instead, which can include support for this MSC's principles without needing
|
||||
to change the Matrix specification itself. As a measure until OIDC is here though, this MSC exists
|
||||
to fill the need.
|
||||
|
||||
A new `m.login.terms` authentication type is introduced, allowing servers to include it in registration
|
||||
flows if it desires. Servers which do not require policy acceptance at registration are not required
|
||||
to support this flow.
|
||||
|
||||
The parameters for the new authentication type look like the following:
|
||||
|
||||
```json
|
||||
{
|
||||
"policies": {
|
||||
"terms_of_service": {
|
||||
"version": "1.2",
|
||||
"en": {
|
||||
"name": "Terms of Service",
|
||||
"url": "https://example.org/somewhere/terms-1.2-en.html"
|
||||
},
|
||||
"fr": {
|
||||
"name": "Conditions d'utilisation",
|
||||
"url": "https://example.org/somewhere/terms-1.2-fr.html"
|
||||
}
|
||||
},
|
||||
"privacy_policy": {
|
||||
"version": "1.2",
|
||||
"en": {
|
||||
"name": "Privacy Policy",
|
||||
"url": "https://example.org/somewhere/privacy-1.2-en.html"
|
||||
},
|
||||
"fr": {
|
||||
"name": "Politique de confidentialité",
|
||||
"url": "https://example.org/somewhere/privacy-1.2-fr.html"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Each key under `policies` is a "Policy ID", and defined by the server. They are an opaque identifier
|
||||
(described later in this proposal). Each policy object associated with the policy ID has a required
|
||||
`version` as a convenience to the client, and is another opaque identifier. All other keys are language
|
||||
codes to represent the same document. The client picks the language which best suits the user.
|
||||
|
||||
Language codes *should* be formatted as per [Section 2.2 of RFC 5646](https://datatracker.ietf.org/doc/html/rfc5646#section-2.2),
|
||||
noting that some implementation *may* use an underscore instead of dash. For example, `en_US` instead
|
||||
of `en-US`. This recommendation is to ensure maximum compatibility with existing conventions around
|
||||
language choices in (Matrix) clients.
|
||||
|
||||
`name` and `url` for each policy document are required, and are arbitrary strings with no maximum
|
||||
length. `url` *must* be a valid URI with scheme `https://` or `http://`. Insecure HTTP is discouraged.
|
||||
|
||||
If a client encounters an invalid parameter, registration should stop with an error presented to the
|
||||
user.
|
||||
|
||||
To complete the stage, accepting *all* of the listed documents, the client submits an empty `auth`
|
||||
dict. The client *should* present the user with a checkbox to accept each policy, including a link
|
||||
to the provided `url`, or otherwise rely on [fallback auth](https://spec.matrix.org/v1.9/client-server-api/#fallback).
|
||||
|
||||
The server is expected to track which document versions it presented to the user during registration,
|
||||
if applicable.
|
||||
|
||||
### Opaque identifier
|
||||
|
||||
This definition is inherited from [MSC1597](https://github.com/matrix-org/matrix-spec-proposals/pull/1597).
|
||||
|
||||
> Opaque IDs must be strings consisting entirely of the characters
|
||||
> `[0-9a-zA-Z._~-]`. Their length must not exceed 255 characters and they must
|
||||
> not be empty.
|
||||
|
||||
## Unstable prefix
|
||||
|
||||
Regrettably, this MSC was implemented with *stable* identifiers before an unstable identifiers process
|
||||
was established. Implementation has existed in some capacity since 2018: https://github.com/matrix-org/synapse/pull/4004
|
||||
|
||||
Noting that the modern MSC process forbids such behaviour, new implementations should use the stable
|
||||
`m.login.terms` identifier regardless of MSC status. If the MSC changes in a breaking way, a new
|
||||
identifier *must* be chosen, and *must* include a proper unstable prefix.
|
||||
@ -0,0 +1,138 @@
|
||||
# MSC2191: Markup for mathematical messages
|
||||
|
||||
Some people write using an odd language that has strange symbols. No, I'm not
|
||||
talking about computer programmers; I'm talking about mathematicians. In order
|
||||
to aid these people in communicating, Matrix should define a standard way of
|
||||
including mathematical notation in messages.
|
||||
|
||||
This proposal presents a format using LaTeX, in contrast with a [previous
|
||||
proposal](https://github.com/matrix-org/matrix-doc/pull/1722/) that used
|
||||
MathML.
|
||||
|
||||
See also:
|
||||
|
||||
- https://github.com/vector-im/riot-web/issues/1945
|
||||
|
||||
|
||||
## Proposal
|
||||
|
||||
A new attribute `data-mx-maths` will be added for use in `<span>` or `<div>`
|
||||
elements. Its value will be mathematical notation in LaTeX format. `<span>`
|
||||
is used for inline math, and `<div>` for display math. The contents of the
|
||||
`<span>` or `<div>` will be a fallback representation or the desired notation
|
||||
for clients that do not support mathematical display, or that are unable to
|
||||
render the entire `data-mx-maths` attribute. The fallback representation is
|
||||
left up to the sending client and could be, for example, an image, or an HTML
|
||||
approximation, or the raw LaTeX source. When using an image as a fallback, the
|
||||
sending client should be aware of issues that may arise from the receiving
|
||||
client using a different background colour.
|
||||
|
||||
Example (with line breaks and indentation added to `formatted_body` for clarity):
|
||||
|
||||
```json
|
||||
{
|
||||
"content": {
|
||||
"body": "This is an equation: sin(x)=a/b",
|
||||
"format": "org.matrix.custom.html",
|
||||
"formatted_body": "This is an equation:
|
||||
<span data-mx-maths=\"\\sin(x)=\\frac{a}{b}\">
|
||||
sin(<i>x</i>)=<sup><i>a</i></sup>/<sub><i>b</i></sub>
|
||||
</span>",
|
||||
"msgtype": "m.text"
|
||||
},
|
||||
"event_id": "$eventid:example.com",
|
||||
"origin_server_ts": 1234567890,
|
||||
"sender": "@alice:example.com",
|
||||
"type": "m.room.message",
|
||||
"room_id": "!soomeroom:example.com"
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Other solutions
|
||||
|
||||
[MSC1722](https://github.com/matrix-org/matrix-doc/pull/1722/) proposes using
|
||||
MathML as the format of transporting mathematical notation. It also summarizes
|
||||
some other solutions in its "Other Solutions" section.
|
||||
|
||||
In comparison with MathML, LaTeX has several advantages and disadvantages.
|
||||
|
||||
The first advantage, which is quite obvious, is that LaTeX is much less verbose
|
||||
and more readable than MathML. In many cases, the LaTeX code is a suitable
|
||||
fallback for the rendered notation.
|
||||
|
||||
LaTeX is a suitable input method for many people, and so converting from a
|
||||
user's input to the message format would be a no-op.
|
||||
|
||||
However, balanced against these advantages, LaTeX has several disadvantages as
|
||||
a message format. Some of these are covered in the "Potential issues" and
|
||||
"Security considerations".
|
||||
|
||||
|
||||
## Potential issues
|
||||
|
||||
### "LaTeX" as a format is poorly defined
|
||||
|
||||
There are several extensions to LaTeX that are commonly used, such as
|
||||
AMS-LaTeX. It is unclear which extensions should be supported, and which
|
||||
should not be supported. Different LaTeX-rendering libraries support different
|
||||
sets of commands.
|
||||
|
||||
This proposal suggests that the receiving client should render the LaTeX
|
||||
version if possible, but if it contains unsupported commands, then it should
|
||||
display the fallback. Thus, it is up to the receiving client to decide what
|
||||
commands it will support, rather than dictating what commands must be
|
||||
supported. This comes at a cost of possible inconsistency between clients, but
|
||||
is somewhat mitigated by the use of a fallback. Clients should, however, aim
|
||||
to support, at minimum, the basic LaTeX2e maths commands and the TeX maths
|
||||
commands, with the possible exception of commands that could be security risks
|
||||
(see below).
|
||||
|
||||
To improve compatibility, the sender's client may warn the sender if they are
|
||||
using a command that comes from another package, such as AMS-LaTeX.
|
||||
|
||||
### Lack of libraries for displaying mathematics
|
||||
|
||||
see the corresponding section in [MSC1722](https://github.com/matrix-org/matrix-spec-proposals/pull/1722/files#diff-4a271297299040dbfa622bfc6d2aab02f9bc82be0b28b2a92ce30b14c5621f94R148-R164)
|
||||
|
||||
|
||||
## Security considerations
|
||||
|
||||
LaTeX is a [Turing complete programming
|
||||
language](https://web.archive.org/web/20160110102145/http://en.literateprograms.org/Turing_machine_simulator_%28LaTeX%29);
|
||||
it is possible to write a LaTeX document that contains an infinite loop, or
|
||||
that will require large amounts of memory. While it may be fun to write a
|
||||
[LaTeX file that can control a Mars
|
||||
Rover](https://wiki.haskell.org/wikiupload/8/85/TMR-Issue13.pdf#chapter.2), it
|
||||
is not desirable for a mathematical formula embedded in a Matrix message to
|
||||
control a Mars Rover. Clients should take precautions when rendering LaTeX.
|
||||
Clients that use a rendering library should only use one that can process the
|
||||
LaTeX safely.
|
||||
|
||||
Clients should not render mathematics by calling the `latex` executable without
|
||||
proper sandboxing, as the `latex` executable was not written to handle
|
||||
untrusted input. (see, for example, <https://hovav.net/ucsd/dist/texhack.pdf>,
|
||||
<https://0day.work/hacking-with-latex/>, and
|
||||
<https://hovav.net/ucsd/dist/tex-login.pdf>.) Some LaTeX rendering libraries
|
||||
are better suited for processing untrusted input.
|
||||
|
||||
Certain commands, such as [those that can create
|
||||
macros](https://katex.org/docs/supported#macros), are potentially dangerous;
|
||||
clients should either decline to process those commands, or should take care to
|
||||
ensure that they are handled in safe ways (such as by limiting recursion). In
|
||||
general, LaTeX commands should be filtered by allowing known-good commands
|
||||
rather than forbidding known-bad commands. Some LaTeX libraries may have
|
||||
options for doing this.
|
||||
|
||||
In general, LaTeX places a heavy burden on client authors to ensure that it is
|
||||
processed safely. Some LaTeX rendering libraries provide security advice, for
|
||||
example, <https://github.com/KaTeX/KaTeX/blob/main/docs/security.md>.
|
||||
|
||||
|
||||
## Conclusion
|
||||
|
||||
Math(s) is hard, but LaTeX makes it easier to write mathematical notation.
|
||||
However, using LaTeX as a format for including mathematics in Matrix messages
|
||||
has some serious downsides. Nevertheless, if clients handle the LaTeX
|
||||
carefully, or rely on the fallback representation, the concerns can be
|
||||
addressed.
|
||||
@ -0,0 +1,158 @@
|
||||
# MSC2409: Proposal to send typing, presence and receipts to appservices
|
||||
|
||||
*Note: This proposal is a continuation of [MSC1888](https://github.com/matrix-org/matrix-doc/pull/1888)
|
||||
and deprecates that one.*
|
||||
|
||||
The [appservice /transactions API](https://spec.matrix.org/v1.11/application-service-api/#put_matrixappv1transactionstxnid)
|
||||
currently supports pushing PDU events (regular message and state events)
|
||||
however it doesn't provision for EDU events (typing, presence and receipts). This means that bridges cannot
|
||||
react to Matrix users who send any typing or presence information in a room the service is part of.
|
||||
|
||||
There is an interest amongst the community to have equal bridging on both sides of a bridge, so that
|
||||
read receipts and typing notifications can be seen on the remote side. To that end, this proposal
|
||||
specifies how these can be pushed to an appservice.
|
||||
|
||||
## Proposal
|
||||
|
||||
### Changes to the registration file
|
||||
|
||||
In order that appservices don't get flooded with EDUs, appservices have to opt-in to receive them by
|
||||
setting `receive_ephemeral` to true. A registration file could look like following:
|
||||
|
||||
```yaml
|
||||
id: "IRC Bridge"
|
||||
url: "http://127.0.0.1:1234"
|
||||
as_token: "30c05ae90a248a4188e620216fa72e349803310ec83e2a77b34fe90be6081f46"
|
||||
hs_token: "312df522183efd404ec1cd22d2ffa4bbc76a8c1ccf541dd692eef281356bb74e"
|
||||
sender_localpart: "_irc_bot"
|
||||
# We want to receive EDUs
|
||||
receive_ephemeral: true
|
||||
namespaces:
|
||||
users:
|
||||
- exclusive: true
|
||||
regex: "@_irc_bridge_.*"
|
||||
aliases:
|
||||
- exclusive: false
|
||||
regex: "#_irc_bridge_.*"
|
||||
rooms: []
|
||||
```
|
||||
|
||||
For now, receiving EDUs is all-or-nothing. A future MSC may add more granular
|
||||
filtering capabilities for appservices.
|
||||
|
||||
### Changes to the /transactions/ API
|
||||
|
||||
The `PUT /_matrix/app/v1/transactions/{txnId}` API currently supports sending PDUs
|
||||
via the `events` array.
|
||||
|
||||
```json
|
||||
{
|
||||
"events": [
|
||||
{
|
||||
"content": {
|
||||
"membership": "join",
|
||||
"avatar_url": "mxc://domain.com/SEsfnsuifSDFSSEF#auto",
|
||||
"displayname": "Alice Margatroid"
|
||||
},
|
||||
"type": "m.room.member",
|
||||
"event_id": "$143273582443PhrSn:domain.com",
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:domain.com",
|
||||
"sender": "@example:domain.com",
|
||||
"origin_server_ts": 1432735824653,
|
||||
"unsigned": {
|
||||
"age": 1234
|
||||
},
|
||||
"state_key": "@alice:domain.com"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
This proposal would extend the `PUT /_matrix/app/v1/transactions/` endpoint to include a new key
|
||||
`ephemeral` to behave similar to the various sections of the CS API `/sync` endpoint. The `ephemeral` key
|
||||
MAY be omitted entirely if there are no ephemeral events to send.
|
||||
|
||||
```json
|
||||
{
|
||||
"ephemeral": [
|
||||
{
|
||||
"type": "m.typing",
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:domain.com",
|
||||
"content": {
|
||||
"user_ids": [
|
||||
"@alice:example.com"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "m.receipt",
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:domain.com",
|
||||
"content": {
|
||||
"$1435641916114394fHBLK:matrix.org": {
|
||||
"m.read": {
|
||||
"@rikj:jki.re": {
|
||||
"ts": 1436451550453
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"events": [
|
||||
// ...
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
The reason for a new key rather than bundling the events into `events` is that
|
||||
existing appservices may mistake them for PDUs and might behave erratically.
|
||||
While `events` may now be a somewhat misleading name, this is an acceptable tradeoff.
|
||||
|
||||
The array is effectively a combination of the `presence` and `ephemeral` sections of the
|
||||
client-server `/sync` API. User-defined ephemeral events don't exist yet, which means there are
|
||||
only three event types that can currently occur:
|
||||
[`m.presence`](https://spec.matrix.org/v1.11/client-server-api/#mpresence),
|
||||
[`m.typing`](https://spec.matrix.org/v1.11/client-server-api/#mtyping),
|
||||
and [`m.receipt`](https://spec.matrix.org/v1.11/client-server-api/#mreceipt).
|
||||
|
||||
This proposal does not cover any other types of events which are sent as EDUs in the federation API,
|
||||
such as to-device events or other e2ee features. Those are left to a separate MSC.
|
||||
|
||||
EDUs are formatted the same way as they are in C-S sync, with the addition of the `room_id` field
|
||||
for room-scoped EDUs (`m.typing` and `m.receipt`). `room_id` is not present in the C-S API because
|
||||
sync nests EDUs inside a room object, but appservices get a flat list of events in all rooms.
|
||||
|
||||
### Expectations of when an EDU should be pushed to an appservice
|
||||
|
||||
It is not clear at face value what should be pushed to an appservice. Appservices claim
|
||||
namespaces of users which registers "interest" in the rooms where those users reside, as
|
||||
well as claiming namespaces of rooms for explicit interest. However, not all EDUs are
|
||||
associated with a single room (presence, etc).
|
||||
|
||||
If the EDU is capable of being associated to a particular room (i.e. `m.typing` and `m.receipt`),
|
||||
it should be sent to the appservice under the same rules as regular events (interest in the room
|
||||
means sending it). For EDUs which are not associated with a particular room, the appservice
|
||||
receives the EDU if it contextually *would* apply. For example, a presence update for a user an
|
||||
appservice shares a room with (or is under the appservice's namespace) would be sent to the
|
||||
appservice.
|
||||
|
||||
For `m.receipt`, private read receipts (`m.read.private`) should only be sent for users within the
|
||||
appservice's namespaces. Normal read receipts and threaded read receipts are always sent.
|
||||
|
||||
## Potential issues
|
||||
|
||||
Determining which EDUs to transmit to the appservice could lead to quite some overhead on the
|
||||
homeserver side. Additionally, more network traffic is produced, potentially straining the local
|
||||
network and the appservice more. As such, appservices have to opt-in to receive EDUs.
|
||||
|
||||
## Security considerations
|
||||
|
||||
The homeserver needs to accurately determine which EDUs to send to the appservice, as to not leak
|
||||
any unnecessary metadata about users. Particularly `m.presence` could be tricky, as no `room_id` is present in
|
||||
that EDU.
|
||||
|
||||
## Unstable prefix
|
||||
|
||||
In the transaction body, instead of `ephemeral`, `de.sorunome.msc2409.ephemeral` is used.
|
||||
|
||||
In the registration file, instead of `receive_ephemeral`, `de.sorunome.msc2409.push_ephemeral` is used.
|
||||
@ -0,0 +1,279 @@
|
||||
# MSC2781: Remove reply fallbacks from the specification
|
||||
|
||||
Currently the specification suggests clients should send and strip a
|
||||
[fallback representation](https://spec.matrix.org/v1.10/client-server-api/#fallbacks-for-rich-replies)
|
||||
of a replied to message. The fallback representation was meant to simplify
|
||||
supporting replies in a new client, but in practice they add complexity, are
|
||||
often implemented incorrectly and block new features.
|
||||
|
||||
This MSC proposes to **remove** those fallbacks from the specification.
|
||||
|
||||
Some of the known issues include:
|
||||
* The content of reply fallback is [untrusted](https://spec.matrix.org/v1.10/client-server-api/#stripping-the-fallback).
|
||||
* Reply fallbacks may leak history. ([#368](https://github.com/matrix-org/matrix-spec/issues/368))
|
||||
* Parsing reply fallbacks can be tricky. ([#350](https://github.com/matrix-org/matrix-spec/issues/350))
|
||||
* It is unclear how to handle a reply to a reply. ([#372](https://github.com/matrix-org/matrix-spec/issues/372))
|
||||
* Localization of replies is not possible when the content is embedded into the event.
|
||||
* It is not possible to fully redact an event once it is replied to. This causes issues with Trust & Safety where
|
||||
spam or other removed content remains visible, and may cause issues with the GDPR Right to be Forgotten.
|
||||
* There are a variety of implementation bugs related to reply fallback handling.
|
||||
|
||||
More details and considerations are provided in the appendices, but these are
|
||||
provided for convenience and aren't necessary to understand this proposal.
|
||||
|
||||
## Proposal
|
||||
|
||||
Remove the [rich reply fallback from the
|
||||
specification](https://spec.matrix.org/v1.10/client-server-api/#fallbacks-for-rich-replies).
|
||||
Clients should stop sending them and should consider treating `<mx-reply>` parts
|
||||
as they treat other invalid html tags.
|
||||
|
||||
Clients are not required to include a fallback in a reply since version 1.3 of
|
||||
the
|
||||
[specification](https://spec.matrix.org/v1.10/client-server-api/#rich-replies).
|
||||
For this reason the reply fallback can be removed from the specification without
|
||||
any additional deprecation period.
|
||||
|
||||
A suggestion for the spec PR: An info box could be included to mention
|
||||
the historical use of the reply fallback, suggesting that clients may encounter
|
||||
such events sent by other clients and that clients may need to strip out such
|
||||
fallbacks.
|
||||
|
||||
Given clients have had enough time to implement replies completely, the
|
||||
overall look & feel of replies should be unchanged or even improved by this
|
||||
proposal. Implementing replies in a client should also be a bit easier with this
|
||||
change.
|
||||
|
||||
An extended motivation is provided at [the end of this document](#user-content-appendix-b-issues-with-the-current-fallbacks).
|
||||
|
||||
## Potential issues
|
||||
|
||||
Old events and events sent by clients implementing an older version of the
|
||||
Matrix specification might still contain a reply fallback. So for at least some
|
||||
period of time clients will still need to strip reply fallbacks from messages.
|
||||
|
||||
Clients which don't implement rich replies may see messages without context,
|
||||
confusing users. However, most replies are in close proximity to the original
|
||||
message, making context likely to be nearby. Clients should also have enough
|
||||
information in the event to render helpful indications to users while they work
|
||||
on full support.
|
||||
|
||||
Clients which aren't using
|
||||
[intentional mentions](https://spec.matrix.org/v1.7/client-server-api/#mentioning-the-replied-to-user)
|
||||
may cause some missed notifications on the receiving side.
|
||||
[MSC3664](https://github.com/matrix-org/matrix-doc/pull/3664) and similar aim to
|
||||
address this issue, and
|
||||
[MSC4142](https://github.com/matrix-org/matrix-spec-proposals/pull/4142) tries
|
||||
to improve the intentional mentions experience for replies generally.
|
||||
Because intentional mentions are already part of the Matrix specification since
|
||||
version 1.7, clients can be expected to implement those first, which should make
|
||||
the impact on notifications minimal in practice.
|
||||
|
||||
## Alternatives
|
||||
|
||||
[MSC2589](https://github.com/matrix-org/matrix-doc/pull/2589): This adds the
|
||||
reply text as an additional key. While this solves the parsing issues, it
|
||||
doesn't address the other issues with fallbacks.
|
||||
|
||||
One could also just stick with the current fallbacks and make all clients pay
|
||||
the cost for a small number of clients actually benefitting from them.
|
||||
|
||||
Lastly one could introduce an alternative relation type for replies without
|
||||
fallback and deprecate the current relation type (since it does not fit the
|
||||
[new format for relations](https://github.com/matrix-org/matrix-doc/pull/2674)
|
||||
anyway). We could specify, that the server is supposed to send the replied_to
|
||||
event in unsigned to the client, so that clients just need to stitch those two
|
||||
events together, but don't need to fetch the replied_to event from the server.
|
||||
It would make replies slightly harder to implement for clients, but it would be
|
||||
simpler than what this MSC proposes.
|
||||
|
||||
## Security considerations
|
||||
|
||||
Overall this should **reduce** security issues as the handling of untrusted
|
||||
HTML is simplified. For an example security issue that could be avoided, see
|
||||
https://github.com/vector-im/element-web/releases/tag/v1.7.3 and the appendix.
|
||||
|
||||
## Unstable prefix
|
||||
|
||||
No unstable prefix should be necessary as clients aren't required to send reply
|
||||
fallbacks for all messages since version 1.3 of the Matrix specification, which
|
||||
changed the wording from "MUST" to "SHOULD".
|
||||
|
||||
## Appendix A: Support for rich replies in different clients
|
||||
|
||||
### Clients without rendering support for rich replies
|
||||
|
||||
Of the 23 clients listed in the [Matrix client matrix](https://matrix.org/clients-matrix)
|
||||
16 are listed as not supporting replies (updated January 2022):
|
||||
|
||||
- Element Android: Relies on the reply fallback.
|
||||
- Element iOS: [Does not support rich replies](https://github.com/vector-im/element-ios/issues/3517)
|
||||
- weechat-matrix: Actually has an [implementation](https://github.com/poljar/weechat-matrix/issues/86) to send replies although it seems to be [broken](https://github.com/poljar/weechat-matrix/issues/233). Doesn't render rich replies. Hard to implement because of the single socket implementation, but may be easier in the Rust version.
|
||||
- Quaternion: [Blocked because of fallbacks](https://github.com/quotient-im/libQuotient/issues/245).
|
||||
- matrixcli: [Doesn't support formatted messages](https://github.com/ahmedsaadxyzz/matrixcli/issues/10).
|
||||
- Ditto Chat: [Seems to rely on the fallback](https://gitlab.com/ditto-chat/ditto/-/blob/main/mobile/scenes/chat/components/Html.tsx#L38)
|
||||
- Mirage: Supports rich replies, but [doesn't strip the fallback correctly](https://github.com/mirukana/mirage/issues/89) and uses the fallback to render them.
|
||||
- Nio: [Unsupported](https://github.com/niochat/nio/issues/85).
|
||||
- Pattle: Client is not being developed anymore.
|
||||
- Seaglass: Doesn't support rich replies, but is [unhappy with how the fallback looks](https://github.com/neilalexander/seaglass/issues/51)?
|
||||
- Miitrix: Somewhat unlikely to support it, I guess?
|
||||
- matrix-commander: No idea, but doesn't look like it.
|
||||
- gotktrix: [Seems to rely on the reply fallback](https://github.com/diamondburned/gotktrix/blob/5f2783d633560421746a82aab71d4f7421e4b99c/internal/app/messageview/message/mcontent/text/html.go#L437)
|
||||
- Hydrogen: [Seems to use the reply fallback](https://github.com/vector-im/hydrogen-web/blob/c3177b06bf9f760aac2bfd5039342422b7ec8bb4/doc/impl-thoughts/PENDING_REPLIES.md)
|
||||
- kazv: Doesn't seem to support replies at all
|
||||
- Syphon: [Uses the reply fallback in body](https://github.com/syphon-org/syphon/blob/fa44c5abe37bdd256a9cb61cbc8552e0e539cdce/lib/views/widgets/messages/message.dart#L368)
|
||||
|
||||
So in summary, 3/4 of the listed clients don't support replies. At least one
|
||||
client doesn't support it because of the fallback (Quaternion). 3 of the command
|
||||
line clients probably won't support replies, since they don't support formatted
|
||||
messages and replies require html support for at least sending.
|
||||
|
||||
Only one client implemented rich replies in the last 1.5 years after the
|
||||
original list was done in October 2020. Other clients are either new in my list
|
||||
or didn't change their reply rendering. I would appreciate to hear, why those
|
||||
client developers decided not to support rich reply rendering and if dropping
|
||||
the reply fallback would be an issue for them.
|
||||
|
||||
Changes from 1.5 years ago as of January 2022:
|
||||
|
||||
- Fractal: [Seems to support replies now!](https://gitlab.gnome.org/GNOME/fractal/-/merge_requests/941)
|
||||
- Commune: Seems to support rich reply rendering and style them very nicely.
|
||||
- NeoChat: [Supports rich replies](https://invent.kde.org/network/neochat/-/blob/master/src/utils.h#L21)
|
||||
- Cinny: [Seems to support rich replies](https://github.com/ajbura/cinny/blob/6ff339b552e242f6233abd86768bb2373b150f77/src/app/molecules/message/Message.jsx#L111)
|
||||
- gomuks: [Strips the reply fallback](https://github.com/tulir/gomuks/blob/3510d223b2d765572bf2e97222f2f55d099119f0/ui/messages/html/parser.go#L361)
|
||||
- Lots of other new clients!
|
||||
|
||||
|
||||
### Results of testing replies without fallback
|
||||
|
||||
So far I haven't found a client that completely breaks without the fallback.
|
||||
All clients that support rendering rich replies don't break, when there is no
|
||||
fallback according to my tests (at least Nheko, Element/Web, FluffyChat and
|
||||
NeoChat were tested and some events without fallback are in #nheko:nheko.im and
|
||||
I haven't heard of any breakage). Those clients just show the reply as normal
|
||||
and otherwise seem to work completely fine as well. Element Android and Element
|
||||
iOS just don't show what message was replied to. Other clients haven't been
|
||||
tested by the author, but since the `content` of an event is untrusted, a client
|
||||
should not break if there is no reply fallback. Otherwise this would be a
|
||||
trivial abuse vector.
|
||||
|
||||
|
||||
## Appendix B: Issues with the current fallbacks
|
||||
|
||||
This section was moved to the back of this MSC, because it is fairly long and
|
||||
exhaustive. It lists all the issues the proposal author personally experienced
|
||||
with fallbacks in their client and its interactions with the ecosystem.
|
||||
|
||||
### Stripping the fallback
|
||||
|
||||
To reply to a reply, a client needs to strip the existing fallback of the first
|
||||
reply. Otherwise replies will just infinitely nest replies.
|
||||
[While the spec doesn't necessarily require stripping the fallback in replies to replies (only for rendering)](https://spec.matrix.org/v1.1/client-server-api/#fallback-for-mtext-mnotice-and-unrecognised-message-types),
|
||||
not doing so risks running into the event size limit, but more importantly, it
|
||||
just leads to a bad experience for clients actually relying on the fallback.
|
||||
|
||||
Stripping the fallback is not trivial. Multiple implementations had bugs in
|
||||
their fallback stripping logic. The edge cases are not covered in the
|
||||
specification in detail and some clients have interpreted them differently.
|
||||
Common mistakes include:
|
||||
|
||||
- Not stripping the fallback in body, which leads to a very long nested chain.
|
||||
- Not dealing with mismatched `<mx-reply>` tags, which can look like you were
|
||||
impersonating someone.
|
||||
|
||||
For the `body` extra attention needs to be paid to only strip lines starting
|
||||
with `>` until the first empty line. Implementations either only stripped the
|
||||
first line, stripped all lines starting with `>` until the first non empty line,
|
||||
that does not start with `>` or stripped only the `formatted_body`. While those
|
||||
are implementation bugs, they can't happen if you don't need to strip a
|
||||
fallback.
|
||||
|
||||
### Creating a new fallback
|
||||
|
||||
To create a new fallback, a client needs to add untrusted html to its own
|
||||
events. This is an easy attack vector to inject your own content into someone
|
||||
elses reply. While this can be prevented with enough care, since Riot basically
|
||||
had to fix this issue twice, it can be expected that other clients can also be
|
||||
affected by this.
|
||||
|
||||
### Requirement of html for replies
|
||||
|
||||
The spec requires rich replies to have a fallback using html:
|
||||
|
||||
> Rich replies MUST have a format of org.matrix.custom.html and therefore a formatted_body alongside the body and appropriate msgtype.
|
||||
|
||||
This means you can't reply using only a `body` and you can't reply with an
|
||||
image, since those don't have a `formatted_body` property currently. This means
|
||||
a text only client, that doesn't want to display html, still needs to support
|
||||
html anyway and that new features are blocked, because of fallbacks.
|
||||
|
||||
### Format is unreliable
|
||||
|
||||
While the spec says how a fallback "should" look, there are variations in use
|
||||
which further complicates stripping the fallback or are common mistakes, when
|
||||
emitting the fallback. Some variations include localizing the fallback,
|
||||
missing suggested links or tags, using the body in replies to files or images
|
||||
or using the display name instead of the matrix id.
|
||||
|
||||
As a result the experience in clients relying on the fallback or stripping the
|
||||
fallback varies depending on the sending client.
|
||||
|
||||
### Replies leak history
|
||||
|
||||
A reply includes the `body` of another event. This means a reply to an event can
|
||||
leak data to users, that joined this room at a later point, but shouldn't be
|
||||
able to see the event because of visibility rules or encryption. While this
|
||||
isn't a big issue, there is still an issue about it: https://github.com/matrix-org/matrix-doc/issues/1654
|
||||
|
||||
This history leak can also cause abusive or redacted messages to remain visible
|
||||
to other room members, depending on the client implementation of replies.
|
||||
|
||||
Historically clients have also sometimes localized the fallbacks. In those cases
|
||||
they leak the users language selection for their client, which may be personal
|
||||
information.
|
||||
|
||||
### Using the unmodified fallback in clients and bridges
|
||||
|
||||
The above issues are minor, if reply fallbacks added sufficient value to
|
||||
clients. Bridges usually try to bridge to native replies, so they need to
|
||||
strip the reply fallback
|
||||
(https://github.com/matrix-org/matrix-doc/issues/1541). Even the IRC bridge
|
||||
seems to send a custom fallback, because the default fallback is not that
|
||||
welcome to the IRC crowd, although the use cases for simple, text only bridges
|
||||
is often touted as a good usecase for the fallback (sometimes even explicitly
|
||||
mentioning bridging to IRC). As a result there are very few bridges, that
|
||||
benefit from the fallback being present.
|
||||
|
||||
Some clients do choose not to implement rich reply rendering, but the experience
|
||||
tends to not be ideal, especially in cases where you reply to an image and now
|
||||
the user needs to guess, what image was being replied to.
|
||||
|
||||
As a result the fallbacks provide value to only a subset of the Matrix
|
||||
ecosystem.
|
||||
|
||||
### Fallbacks increase integration work with new features
|
||||
|
||||
- [Edits explicitly mention](https://github.com/matrix-org/matrix-doc/pull/2676)
|
||||
that a reply fallback should not be sent in the `m.new_content`. This causes
|
||||
issues for clients relying on the fallback, because they won't show replies
|
||||
once a message has been edited (see Element Android as a current example)
|
||||
and similar edge cases.
|
||||
- [Extensible events](https://github.com/matrix-org/matrix-doc/pull/1767)
|
||||
require an update to the specification for fallbacks (because there is no
|
||||
`body` or `formatted_body` anymore after the transition period).
|
||||
[The current proposal](https://github.com/matrix-org/matrix-doc/pull/3644)
|
||||
also intends to just drop the fallbacks in extensible events.
|
||||
|
||||
### Localization
|
||||
|
||||
Since the fallback is added as normal text into the message, it needs to be
|
||||
localized for the receiving party to understand it. This however proves to be a
|
||||
challenge, since users may switch languages freely in a room and it is not easy
|
||||
to guess, which language was used in a short message. One could also use the
|
||||
client's language, but that leaks the user's localization settings, which can be a
|
||||
privacy concern and the other party may not speak that language. Alternatively a
|
||||
client can just send english fallbacks, but that significantly worsens the
|
||||
experience for casual users in non-english speaking countries. The specification
|
||||
currently requires them to not be translated (although some clients don't follow
|
||||
that), but not sending a fallback at all completely sidesteps the need for the
|
||||
spec to specify that and clients relying on an english only fallback.
|
||||
@ -0,0 +1,81 @@
|
||||
# MSC2867: Marking rooms as unread
|
||||
|
||||
There is currently no way to mark a room for later attention. A common use-case is receiving a
|
||||
notification on the go and opening the corresponding room but then deciding to deal with it at a later time.
|
||||
|
||||
This MSC introduces an option to manually mark an room as *Unread*.
|
||||
|
||||
In the above use-case the user would just mark the room as unread and when later opening a matrix
|
||||
client on their desktop PC that room would appear prominently in their room list waiting for attention.
|
||||
|
||||
A related use-case solved by this proposal is wanting to mute a room's notifications while there's an
|
||||
ongoing discussion but still flag it for catching up later.
|
||||
|
||||
Both WhatsApp and Telegram offer this functionality.
|
||||
|
||||
## Proposal
|
||||
|
||||
We add a [room account data](https://matrix.org/docs/spec/client_server/r0.6.1#put-matrix-client-r0-user-userid-rooms-roomid-account-data-type)
|
||||
field `m.marked_unread` which just stores the following:
|
||||
|
||||
```json
|
||||
{
|
||||
"unread": true | false
|
||||
}
|
||||
```
|
||||
|
||||
When this is true a client should show the room with an indeterminate unread marker. This marker should
|
||||
be of similar visual importance to a non-highlight notification badge without the notification count. For example if
|
||||
you have a red circle with small numbers inside for counting notifications next to a room, then a room
|
||||
without notifications but marked as unread should have just the red circle. If a client gets new
|
||||
notifications after marking a room as unread the notification count should be displayed instead as normal.
|
||||
|
||||
The `m.fully_read` marker should not be touched when marking a room as unread to keep the users read position
|
||||
in the room.
|
||||
|
||||
Marking a room as read, if a client implements such a functionality, now involves sending a read receipt for the last
|
||||
event, as well as setting `m.marked_unread` to false.
|
||||
|
||||
The unread flag should be cleared when opening the room again.
|
||||
|
||||
## Potential issues
|
||||
|
||||
Client not aware of this feature will not clear the unread flag, when reading the room. In addition they'll obviously
|
||||
not show the room with a special badge. This seems preferable to the alternative of clearing the unread flag of a room
|
||||
without intending to because it didn't actually show up as unread.
|
||||
|
||||
This proposal has no support for marking threads as unread. This should be handled in a future MSC.
|
||||
|
||||
## Alternatives
|
||||
|
||||
There are multiple possible alternatives here:
|
||||
|
||||
* Marking individual messages as unread as discussed [here](https://github.com/matrix-org/matrix-doc/issues/2506):
|
||||
This is a far more complex feature that has possible interactions with server-side implementations and notification
|
||||
counts. This proposal aims to be a far more lightweight alternative. Looking at other messengers marking a room as
|
||||
unread is a more common operation than marking messages as unread, so it could be argued that others already found
|
||||
this to strike a good balance of complexity and use-cases covered.
|
||||
* Modifying the `m.fully_read` marker instead of introducing a new `m.marked_unread` field:
|
||||
Another idea was setting the `m.fully_read` marker to some earlier event which would then cause clients to show
|
||||
unread messages again. This has two problems:
|
||||
* It makes it harder to distinguish between rooms which happen to have unread messages that you don't necessarily
|
||||
care about and rooms which were manually marked as such and thus should be shown much more prominently.
|
||||
* When trying to work around this, by setting the marker at a special location like the room creation event, we completely
|
||||
lose the user's actual read position in a room whenever they use this feature.
|
||||
* Read receipts could be allowed to go "backwards" to restore notification
|
||||
counts, though this is likely to be riddled with bugs and unexpected
|
||||
behaviour for users. It's better for everyone to keep read receipts linearly
|
||||
progressing forwards.
|
||||
|
||||
## Security considerations
|
||||
|
||||
None.
|
||||
|
||||
## Unstable prefix
|
||||
|
||||
While this feature is not yet fully specced, implementers can use the `com.famedly.marked_unread` room
|
||||
account data type.
|
||||
|
||||
Implementations using this unstable prefix in a released version should automatically migrate
|
||||
user's unread rooms to `m.marked_unread` when this is released as stable.
|
||||
This ensures user's unread rooms are not lost.
|
||||
@ -0,0 +1,66 @@
|
||||
# MSC2870: Protect server ACLs from redaction
|
||||
|
||||
[Server ACLs](https://matrix.org/docs/spec/client_server/r0.6.1#server-access-control-lists-acls-for-rooms)
|
||||
are a way to prevent malicious/untrusted homeservers from participating in a given room. These ACLs
|
||||
are represented by a state event which is easily capable of demolishing all useful functionality of
|
||||
a federated room. Typically this sort of design flaw would be worked out during the MSC process, and
|
||||
in this particular case it was acknowledged as a potential source of accidental mistake, however the
|
||||
impact of making a mistake appears to be larger than anticipated.
|
||||
|
||||
Specifically, the ACLs do not default to allowing all servers when they are set but missing an `allow`
|
||||
field. When an `allow` rule is missing, it means that all servers can no longer participate in the
|
||||
room. The natural reaction to such a disaster is to try sending a new ACL event, however all the
|
||||
receiving servers rightly refuse the event because the specification says so and it's not yet
|
||||
possible to tell if a trusted server is publishing the new ACLs (due to the social nature of the
|
||||
problem space rather than the technical side). Redacting a server ACL event causes the event content
|
||||
to become `{}`, which means no `allow` rule is present.
|
||||
|
||||
## Proposal
|
||||
|
||||
In a future room version, the `allow`, `deny`, and `allow_ip_literals` fields of the `m.room.server_acl`
|
||||
state event are protected from redaction. Typically this measure is only taken when a field is critical
|
||||
to the operation of the protocol, such as in the case of protecting power levels from redactions. ACLs
|
||||
are not as critical to the protocol as most of the other protected event fields, however the consequences
|
||||
of accidentally redacting a server ACL event are disproportionately large.
|
||||
|
||||
## Potential issues
|
||||
|
||||
None foreseen - this MSC should remedy a problem encountered in the wild.
|
||||
|
||||
## Alternatives
|
||||
|
||||
We could instead dictate that a lack of `allow` rule implicitly means `allow: ["*"]`, however this is
|
||||
a behavioural change which is easily missed between room versions. We could also define that `{}` means
|
||||
applying the same mechanics of ACLs when the state event isn't set, however again this is subject to
|
||||
being missed as a behavioural change. Behavioural changes are hard to represent in the specification as
|
||||
room versions are not meant to contain information about how a room might react in the eyes of a room
|
||||
administrator or client implementation, where possible. They are more intended to change server-side
|
||||
algorithms, like the redaction algorithm, to change the functionality under the hood without impacting
|
||||
the room administrator's understanding of their room's function.
|
||||
|
||||
Another possible approach is to have servers prevent sending faulty ACL events by preventing their
|
||||
local clients from doing so, such as by rejecting redaction requests. This doesn't solve the issue
|
||||
over federation, but can reduce the likelihood of such events making it to the federation layer. This
|
||||
is what Synapse currently does to help mitigate the issue. This is only effective if the server (or
|
||||
client, locally) implements it - it's common for both clients and servers to forget to add these checks
|
||||
during development, leading to occasional room breakage. This MSC instead tries to resolve the issue
|
||||
more completely for future room versions, pending replacement of ACLs entirely.
|
||||
|
||||
Meanwhile, [MSC4124](https://github.com/matrix-org/matrix-spec-proposals/pull/4124) exists as a possible
|
||||
permanent replacement for ACLs.
|
||||
|
||||
## Security considerations
|
||||
|
||||
It may be desirable to redact server ACLs due to abusive server names needing to be banned. Clients
|
||||
are encouraged to *not* display the differences to the ACLs without the user opting in to seeing the
|
||||
changes (such as by clicking a 'show details' link).
|
||||
|
||||
Of particular note is that redacted events may be provided to future users/servers, regardless of the
|
||||
history visibility settings. If fields are protected from redaction, this means they will be visible
|
||||
to those future joiners. This may be undesirable in some circumstances. This MSC does not attempt to
|
||||
address this concern.
|
||||
|
||||
## Unstable prefix
|
||||
|
||||
Implementations looking to test this MSC before it lands in a released room version can use `org.matrix.msc2870`
|
||||
as the room version, using [room version 11](https://spec.matrix.org/v1.9/rooms/v11/) as a base.
|
||||
@ -0,0 +1,283 @@
|
||||
# MSC2964: Usage of OAuth 2.0 authorization code grant and refresh token grant
|
||||
|
||||
This proposal is part of the broader [MSC3861: Next-generation auth for Matrix, based on OAuth 2.0/OIDC][MSC3861].
|
||||
|
||||
This MSC in particular defines how clients can leverage the OAuth 2.0 authorization code grant to gain access to the Matrix Client-to-Server API.
|
||||
|
||||
## Proposal
|
||||
|
||||
### Prerequisites
|
||||
|
||||
This proposal requires the client to know the following authorization server metadata about the homeserver:
|
||||
|
||||
- `authorization_endpoint`: the URL where the user should be sent to initiate the login flow
|
||||
- `token_endpoint`: the URL where the client is able to exchange the authorization code for an access token
|
||||
- `response_types_supported`: a JSON array of response types supported by the authorization endpoint
|
||||
- `grant_types_supported`: a JSON array of grant types supported by the authorization endpoint defined in [RFC8414] and used in [RFC6749]
|
||||
- `response_mode_supported`: a JSON array of response modes supported by the authorization endpoint
|
||||
|
||||
All of those metadata values are well-defined in [RFC8414] and used in various RFCs like [RFC6749].
|
||||
|
||||
The discovery of the above metadata is out of scope for this MSC, and is currently covered by [MSC2965](https://github.com/matrix-org/matrix-doc/pull/2965).
|
||||
|
||||
The client must also have a `client_id` to use with this flow.
|
||||
How the client obtains this is out of scope for this MSC, and is currently covered by [MSC2966](https://github.com/matrix-org/matrix-doc/pull/2966).
|
||||
|
||||
### Authorization code grant
|
||||
|
||||
As per [RFC6749], the authorization code grant lets the client obtain an access token through a browser redirect.
|
||||
|
||||
Because this flow has various parameters and security improvements added by other specifications, this describes what is enforced and required to support by the client and the homeserver.
|
||||
|
||||
Homeservers and clients must:
|
||||
|
||||
- support PKCE using the `S256` code challenge method as per [RFC7636]
|
||||
- support the auth code flow as per [RFC6749] section 4.1
|
||||
- support the refresh token grant as per [RFC6749] section 6
|
||||
- use pre-registered, strict redirect URIs
|
||||
- use the `fragment` response mode as per [OAuth 2.0 Multiple Response Type Encoding Practices] for clients with an HTTPS redirect URI
|
||||
|
||||
### Refresh token grant
|
||||
|
||||
When authorization is granted to a client, the homeserver must issue a refresh token to the client in addition to the access token.
|
||||
|
||||
The access token must be short-lived and should be refreshed using the `refresh_token` when expired, as described in [RFC6749] section 6.
|
||||
|
||||
The homeserver should issue a new refresh token each time one is used, and invalidate the old one.
|
||||
It should do this only if it can guarantee that in case a response with a new refresh token is not received and stored by the client, retrying the request with the old refresh token will succeed.
|
||||
|
||||
The homeserver should consider that the session is compromised if an old, invalidated refresh token is being used, and should revoke the session.
|
||||
|
||||
The client must handle access token refresh failures as follows:
|
||||
|
||||
- If the refresh fails due to network issues or a `5xx` HTTP status code from the server, the client should retry the request with the old refresh token later.
|
||||
- If the refresh fails due to a `4xx` HTTP status code from the server, the client should consider the session logged out.
|
||||
|
||||
### Sample flow
|
||||
|
||||
#### Flow parameters
|
||||
|
||||
The client must know the following parameters, through ways described in [MSC2965], [MSC2966] and [MSC2967]:
|
||||
|
||||
- `authorization_endpoint`: the URL where the user is able to access the authorization endpoint to initiate the login flow
|
||||
- `token_endpoint`: the URL where the user is able to access the token endpoint to exchange the authorization code for an access token
|
||||
- `client_id`: the unique identifier allocated for the client
|
||||
- `redirect_uri`: the URI where the user is redirected after the authorization flow used by this client
|
||||
- `scope`: the scope of the access token to request
|
||||
- `response_mode`: the response mode to use, either `fragment` or `query`. It must be `fragment` if the `redirect_uri` is an HTTPS URI, and can be `query` otherwise
|
||||
|
||||
It needs to generate the following values:
|
||||
|
||||
- a random value for the `state`
|
||||
- a cryptographically random value for the `code_verifier`
|
||||
|
||||
#### Authorization request
|
||||
|
||||
It then constructs the authorization request URL using the `authorization_endpoint` value, with the following query parameters:
|
||||
|
||||
- The `response_type` value set to `code`
|
||||
- The `client_id` value
|
||||
- The `redirect_uri` value
|
||||
- The `scope` value
|
||||
- The `state` value
|
||||
- The `response_mode` value
|
||||
- The `code_challenge` computed from the `code_verifier` value using the SHA-256 algorithm, as described in [RFC7636]
|
||||
- The `code_challenge_method` set to `S256`
|
||||
|
||||
This authorization request URL must be opened in the user's browser:
|
||||
|
||||
- For web-based clients, this can be done through a redirection or by opening the URL in a new tab
|
||||
- For native clients, this can be done by opening the URL:
|
||||
- using the system browser
|
||||
- through platform-specific APIs when available, such as [`ASWebAuthenticationSession`](https://developer.apple.com/documentation/authenticationservices/aswebauthenticationsession) on iOS or [Android Custom Tabs](https://developer.chrome.com/docs/android/custom-tabs) on Android
|
||||
|
||||
The rationale for using the system browser is explained in [MSC3861], under "Motivation" → "Benefits of authenticating end-users through the system browser".
|
||||
|
||||
##### Sample authorization request
|
||||
|
||||
Sample authorization request (broken down into multiple lines for readability), with the following values:
|
||||
|
||||
- `authorization_endpoint` set to `https://account.example.com/oauth2/auth`, obtained through [MSC2965]
|
||||
- `client_id` set to `s6BhdRkqt3`, obtained through [MSC2966]
|
||||
- `redirect_uri` set to `https://app.example.com/oauth2-callback`
|
||||
- `state` set to `ewubooN9weezeewah9fol4oothohroh3`
|
||||
- `response_mode` set to `fragment`
|
||||
- `code_verifier` set to `ogie4iVaeteeKeeLaid0aizuimairaCh`
|
||||
- `code_challenge` computed as `72xySjpngTcCxgbPfFmkPHjMvVDl2jW1aWP7-J6rmwU`
|
||||
- `scope` set to `urn:matrix:client:api:* urn:matrix:client:device:AAABBBCCCDDD` (full access to the C-S API, using the `AAABBBCCCDDD` device ID, as per [MSC2967])
|
||||
|
||||
```
|
||||
https://account.example.com/oauth2/auth?
|
||||
client_id = s6BhdRkqt3 &
|
||||
response_type = code &
|
||||
response_mode = fragment &
|
||||
redirect_uri = https://app.example.com/oauth2-callback &
|
||||
scope = urn:matrix:client:api:* urn:matrix:client:device:AAABBBCCCDDD &
|
||||
state = ewubooN9weezeewah9fol4oothohroh3 &
|
||||
code_challenge = 72xySjpngTcCxgbPfFmkPHjMvVDl2jW1aWP7-J6rmwU &
|
||||
code_challenge_method = S256
|
||||
```
|
||||
|
||||
#### Callback
|
||||
|
||||
Once completed, the user is redirected to the `redirect_uri`, with either a successful or failed authorization in the URL fragment or query parameters.
|
||||
Whether the parameters are in the URL fragment or query parameters is determined by the `response_mode` value:
|
||||
|
||||
- if set to `fragment`, the parameters will be placed in the URL fragment, like `https://example.com/callback#param1=value1¶m2=value2`
|
||||
- if set to `query`, the parameters will be in placed the query string, like `com.example.app:/callback?param1=value1¶m2=value2`
|
||||
|
||||
To avoid disclosing the parameters to the web server hosting the `redirect_uri`, clients should use the `fragment` response mode if the `redirect_uri` is an HTTP/HTTPS URI with a remote host.
|
||||
|
||||
In both success and failure cases, the parameters will have the `state` value used in the authorization request.
|
||||
|
||||
##### Successful authorization callback
|
||||
|
||||
Successful authorization will have a `code` value.
|
||||
|
||||
Sample successful authorization:
|
||||
|
||||
```
|
||||
https://app.example.com/oauth2-callback#state=ewubooN9weezeewah9fol4oothohroh3&code=iuB7Eiz9heengah1joh2ioy9ahChuP6R
|
||||
```
|
||||
|
||||
##### Failed authorization callback
|
||||
|
||||
Failed authorization will have the following values:
|
||||
|
||||
- `error`: the error code
|
||||
- `error_description`: the error description (optional)
|
||||
- `error_uri`: the URI where the user can find more information about the error (optional)
|
||||
|
||||
Sample failed authorization:
|
||||
|
||||
```
|
||||
https://app.example.com/oauth2-callback#state=ewubooN9weezeewah9fol4oothohroh3&error=access_denied&error_description=The+resource+owner+or+authorization+server+denied+the+request.&error_uri=https%3A%2F%2Ferrors.example.com%2F
|
||||
```
|
||||
|
||||
#### Token request
|
||||
|
||||
The client then exchanges the authorization code to obtain an access token using the token endpoint.
|
||||
|
||||
This is done by making a POST request to the `token_endpoint` with the following parameters, encoded as `application/x-www-form-urlencoded` in the body:
|
||||
|
||||
- The `grant_type` set to `authorization_code`
|
||||
- The `code` obtained from the callback
|
||||
- The `redirect_uri` used in the authorization request
|
||||
- The `client_id` value
|
||||
- The `code_verifier` value generated at the start of the authorization flow
|
||||
|
||||
The server replies with a JSON object containing the access token, the token type, the expiration time, and the refresh token.
|
||||
|
||||
The access token must be short-lived and should be refreshed using the `refresh_token` when expired.
|
||||
|
||||
##### Sample token request
|
||||
|
||||
```
|
||||
POST /oauth2/token HTTP/1.1
|
||||
Host: account.example.com
|
||||
Content-Type: application/x-www-form-urlencoded
|
||||
Accept: application/json
|
||||
|
||||
grant_type=authorization_code
|
||||
&code=iuB7Eiz9heengah1joh2ioy9ahChuP6R
|
||||
&redirect_uri=https://app.example.com/oauth2-callback
|
||||
&client_id=s6BhdRkqt3
|
||||
&code_verifier=ogie4iVaeteeKeeLaid0aizuimairaCh
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"access_token": "2YotnFZFEjr1zCsicMWpAA",
|
||||
"token_type": "Bearer",
|
||||
"expires_in": 299,
|
||||
"refresh_token": "tGz3JOkF0XG5Qx2TlKWIA",
|
||||
"scope": "urn:matrix:client:api:* urn:matrix:client:device:AAABBBCCCDDD"
|
||||
}
|
||||
```
|
||||
|
||||
#### Token refresh
|
||||
|
||||
When the access token expires, the client must refresh it by making a POST request to the `token_endpoint` with the following parameters, encoded as `application/x-www-form-urlencoded` in the body:
|
||||
|
||||
- The `grant_type` set to `refresh_token`
|
||||
- The `refresh_token` obtained from the token response
|
||||
- The `client_id` value
|
||||
|
||||
The server replies with a JSON object containing the new access token, the token type, the expiration time, and a new refresh token.
|
||||
The old refresh token is no longer valid and should be discarded.
|
||||
|
||||
##### Sample token refresh
|
||||
|
||||
```
|
||||
POST /oauth2/token HTTP/1.1
|
||||
Host: account.example.com
|
||||
Content-Type: application/x-www-form-urlencoded
|
||||
Accept: application/json
|
||||
|
||||
grant_type=refresh_token
|
||||
&refresh_token=tGz3JOkF0XG5Qx2TlKWIA
|
||||
&client_id=s6BhdRkqt3
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"access_token": "2YotnFZFEjr1zCsicMWpAA",
|
||||
"token_type": "Bearer",
|
||||
"expires_in": 299,
|
||||
"refresh_token": "tGz3JOkF0XG5Qx2TlKWIA",
|
||||
"scope": "urn:matrix:client:api:* urn:matrix:client:device:AAABBBCCCDDD"
|
||||
}
|
||||
```
|
||||
|
||||
### User registration
|
||||
|
||||
Users can register themselves by initiating an authorization code flow with the `prompt=create` parameter as defined in [Initiating User Registration via OpenID Connect 1.0](https://openid.net/specs/openid-connect-prompt-create-1_0.html).
|
||||
|
||||
Whether the homeserver supports this parameter is advertised by the `prompt_values_supported` authorization server metadata.
|
||||
|
||||
## Potential issues
|
||||
|
||||
For a discussion on potential issues please see [MSC3861]
|
||||
|
||||
## Alternatives
|
||||
|
||||
The authorization flow could make use of [RFC9126: OAuth 2.0 Pushed Authorization Request][RFC9126] as a way to future-proof the flow.
|
||||
This could help with granting very specific permissions to the client in combination with [RFC9396: OAuth 2.0 Rich Authorization Requests][RFC9396].
|
||||
|
||||
As Matrix clients are 'public clients' in the sense of [RFC6749] section 2.1, this proposal would not benefit from the security aspects of [RFC9126].
|
||||
It could, although, give better feedback to clients when they are trying to start an invalid or unauthorized flow.
|
||||
|
||||
Other alternatives for the global proposal are discussed in [MSC3861].
|
||||
|
||||
## Security considerations
|
||||
|
||||
Since this touches one of the most sensitive parts of the API, there are a lot of security considerations to keep in mind.
|
||||
|
||||
The [OAuth 2.0 Security Best Practice](https://tools.ietf.org/html/draft-ietf-oauth-security-topics-16) IETF draft outlines many potential attack scenarios. Many of these scenarios are mitigated by the choices enforced in the client profiles outlined in this MSC.
|
||||
It motivates the following decisions in this profile:
|
||||
|
||||
- Using strict redirect URIs validation helps mitigate the risk of open redirection attacks.
|
||||
- Using the `code` response mode, alongside PKCE mitigates the risk in cases of redirection hijacking.
|
||||
- Usage of short-lived access tokens, along with rotation of refresh tokens mitigates the impact of leaked tokens.
|
||||
- Using the system browser to authenticate users lowers the risk of credentials exfiltration by the client.
|
||||
|
||||
## Unstable prefix
|
||||
|
||||
None as part of this MSC.
|
||||
|
||||
## Dependencies
|
||||
|
||||
- [MSC2965]
|
||||
- [MSC2966]
|
||||
- [MSC2967]
|
||||
|
||||
[RFC6749]: https://tools.ietf.org/html/rfc6749
|
||||
[RFC7636]: https://tools.ietf.org/html/rfc7636
|
||||
[RFC8414]: https://tools.ietf.org/html/rfc8414
|
||||
[RFC9126]: https://tools.ietf.org/html/rfc9126
|
||||
[RFC9396]: https://tools.ietf.org/html/rfc9396
|
||||
[MSC2965]: https://github.com/matrix-org/matrix-spec-proposals/pull/2965
|
||||
[MSC2966]: https://github.com/matrix-org/matrix-spec-proposals/pull/2966
|
||||
[MSC2967]: https://github.com/matrix-org/matrix-spec-proposals/pull/2967
|
||||
[MSC3861]: https://github.com/matrix-org/matrix-spec-proposals/pull/3861
|
||||
[OAuth 2.0 Multiple Response Type Encoding Practices]: https://openid.net/specs/oauth-v2-multiple-response-types-1_0.html
|
||||
@ -0,0 +1,234 @@
|
||||
# MSC2965: OAuth 2.0 Authorization Server Metadata discovery
|
||||
|
||||
This proposal is part of the broader [MSC3861: Next-generation auth for Matrix, based on OAuth 2.0/OIDC][MSC3861].
|
||||
|
||||
To be able to initiate an OAuth 2.0 login flow to use a Matrix server, the client needs to know the authorization server metadata, as defined in [RFC8414].
|
||||
|
||||
## Proposal
|
||||
|
||||
This introduces a new Client-Server API endpoint to discover the authorization server metadata used by the homeserver.
|
||||
|
||||
### `GET /auth_metadata`
|
||||
|
||||
A request on this endpoint should return a JSON object containing the authorization server metadata as defined in [RFC8414].
|
||||
This endpoint does _not_ require authentication, and MAY be rate limited per usual.
|
||||
|
||||
For example:
|
||||
|
||||
```http
|
||||
GET /_matrix/client/v1/auth_metadata
|
||||
Host: example.com
|
||||
Accept: application/json
|
||||
```
|
||||
|
||||
```http
|
||||
HTTP/1.1 200 OK
|
||||
Content-Type: application/json
|
||||
Cache-Control: public, max-age=3600
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"issuer": "https://account.example.com/",
|
||||
"authorization_endpoint": "https://account.example.com/oauth2/auth",
|
||||
"token_endpoint": "https://account.example.com/oauth2/token",
|
||||
"registration_endpoint": "https://account.example.com/oauth2/clients/register",
|
||||
"revocation_endpoint": "https://account.example.com/oauth2/revoke",
|
||||
"jwks_uri": "https://account.example.com/oauth2/keys",
|
||||
"response_types_supported": ["code"],
|
||||
"grant_types_supported": ["authorization_code", "refresh_token"],
|
||||
"response_modes_supported": ["query", "fragment"],
|
||||
"code_challenge_methods_supported": ["S256"],
|
||||
"...": "some fields omitted"
|
||||
}
|
||||
```
|
||||
|
||||
**Note**: The fields required for the main flow outlined by [MSC3861] and its sub-proposals are:
|
||||
|
||||
- `issuer` (for compliance with [RFC8414])
|
||||
- `authorization_endpoint` ([MSC2964])
|
||||
- `token_endpoint` ([MSC2964])
|
||||
- `revocation_endpoint` ([MSC4254])
|
||||
- `registration_endpoint` ([MSC2966])
|
||||
- `response_types_supported` including the value `code` ([MSC2964])
|
||||
- `grant_types_supported` including the values `authorization_code` and `refresh_token` ([MSC2964])
|
||||
- `response_modes_supported` including the values `query` and `fragment` ([MSC2964])
|
||||
- `code_challenge_methods_supported` including the value `S256` ([MSC2964])
|
||||
|
||||
See individual proposals for more details on each field.
|
||||
|
||||
### Fallback
|
||||
|
||||
If the homeserver does not offer next-generation authentication as described in [MSC3861], this endpoint should return a 404 with the `M_UNRECOGNIZED` error code.
|
||||
|
||||
In this case, clients should fall back to using the existing [login/logout](https://spec.matrix.org/v1.13/client-server-api/#login) and [account-management](https://spec.matrix.org/v1.13/client-server-api/#account-registration-and-management) APIs, as well as [`/account/3pid/add`](https://spec.matrix.org/v1.13/client-server-api/#post_matrixclientv3account3pidadd), [`/delete_devices`](https://spec.matrix.org/v1.13/client-server-api/#post_matrixclientv3delete_devices) and [`DELETE /devices/{id}`](https://spec.matrix.org/v1.13/client-server-api/#delete_matrixclientv3devicesdeviceid).
|
||||
|
||||
## Potential issues
|
||||
|
||||
The authorization server metadata is relatively large and may change over time. The client should:
|
||||
|
||||
- Cache the metadata appropriately based on HTTP caching headers
|
||||
- Refetch the metadata if it is stale
|
||||
|
||||
## Alternatives
|
||||
|
||||
### Use static Client-Server API endpoints
|
||||
|
||||
Instead of using the standard server metadata as defined in [RFC8414], this proposal could have defined a static set of endpoints under the Client-Server API, e.g.:
|
||||
|
||||
- `/_matrix/client/v1/auth/authorize` as the `authorization_endpoint`
|
||||
- `/_matrix/client/v1/auth/token` as the `token_endpoint`
|
||||
- `/_matrix/client/v1/auth/revoke` as the `revocation_endpoint`
|
||||
- `/_matrix/client/v1/auth/register` as the `registration_endpoint`
|
||||
|
||||
This approach has been discarded for three reasons:
|
||||
|
||||
- The proposed approach ensures interoperability with existing OAuth 2.0 libraries/clients, complying with [RFC8414].
|
||||
- The `authorization_endpoint` is user-facing, and implementations may have valid reasons to expose it on a different domain than the Client-Server API. For example, iOS may display the domain name of the authorization endpoint in a confirmation prompt before the user is redirected to it, so it has to be recognizable by the end user.
|
||||
- While the set of metadata fields is currently relatively small and mostly consists of endpoints, it is likely that as the specification evolves and more OAuth 2.0 mechanisms are added, the set of fields will grow. Reusing the authorization server metadata concept as defined in [RFC8414] makes it easier to use existing, well-known OAuth 2.0 flows.
|
||||
|
||||
### Discovery via OpenID Connect Discovery
|
||||
|
||||
Instead of directly exposing the metadata through a Client-Server API endpoint, the homeserver could expose only the issuer URL and let clients discover the metadata using OpenID Connect Discovery.
|
||||
|
||||
In this approach, a new endpoint `/_matrix/client/v1/auth_issuer` would return just the issuer URL:
|
||||
|
||||
```http
|
||||
GET /_matrix/client/v1/auth_issuer
|
||||
Host: example.com
|
||||
Accept: application/json
|
||||
```
|
||||
|
||||
```http
|
||||
HTTP/1.1 200 OK
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"issuer": "https://account.example.com/"
|
||||
}
|
||||
```
|
||||
|
||||
The Matrix client would then discover the OpenID Connect Provider configuration by using [OpenID Connect Discovery].
|
||||
|
||||
The downside of this approach is that it requires an extra roundtrip to get the metadata.
|
||||
It also introduces a dependency on an OpenID Connect specification: [MSC3861] proposals tries to build on OAuth 2.0/IETF standards as much as possible.
|
||||
|
||||
### Discovery via [RFC8414] well-known endpoint
|
||||
|
||||
[RFC8414: OAuth 2.0 Authorization Server Metadata][RFC8414] already defines a standard well-known endpoint, under `.well-known/oauth-authorization-server`.
|
||||
However, the RFC states that an application leveraging this standard should define its own application-specific endpoint, e.g. `/.well-known/matrix-authorization-server`, and _not_ use the `.well-known/oauth-authorization-server` endpoint.
|
||||
|
||||
Considering the rest of the client-server API, there are two potential locations where this could be hosted:
|
||||
|
||||
1. On the server name domain, with well-known delegation, e.g. `https://example.com/.well-known/matrix/auth-metadata`
|
||||
2. On the client-server API endpoint root, e.g. `https://matrix-client.example.com/.well-known/matrix/auth-metadata`
|
||||
|
||||
The first option would require making well-known documents mandatory on the server name domain, with a document that may need to be updated more frequently than existing ones.
|
||||
This isn't practical for some server deployments, and clients may find it challenging to consistently perform this discovery.
|
||||
|
||||
The second option would be very confusing, as all other Matrix APIs on the client-server domain are prefixed with `/_matrix`, whereas the existing `.well-known` documents ([`/.well-known/matrix/client`](https://spec.matrix.org/v1.13/client-server-api/#getwell-knownmatrixclient) and [`/.well-known/matrix/server`](https://spec.matrix.org/v1.13/server-server-api/#getwell-knownmatrixserver)) are hosted on the server name domain.
|
||||
|
||||
### Discovery via existing `.well-known` mechanism
|
||||
|
||||
A previous version of this proposal suggested using the existing [homeserver discovery mechanism](https://spec.matrix.org/v1.13/client-server-api/#server-discovery) to discover the authentication server.
|
||||
|
||||
A new `m.authentication` field is added to the `.well-known` document to support OpenID Connect Provider (OP) discovery.
|
||||
It is an object containing two fields:
|
||||
|
||||
- REQUIRED `issuer` - the OpenID Connect Provider that is trusted by the homeserver
|
||||
- OPTIONAL `account` - the URL where the user is able to access the account management capabilities of the OpenID Connect Provider
|
||||
|
||||
For example:
|
||||
|
||||
```http
|
||||
GET /.well-known/matrix/client
|
||||
Host: example.com
|
||||
Accept: application/json
|
||||
```
|
||||
|
||||
```http
|
||||
HTTP/1.1 200 OK
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"m.homeserver": {
|
||||
"base_url": "https://matrix-client.example.com"
|
||||
},
|
||||
"m.identity_server": {
|
||||
"base_url": "https://identity.example.com"
|
||||
},
|
||||
"m.authentication": {
|
||||
"issuer": "https://account.example.com",
|
||||
"account": "https://account.example.com/myaccount"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This proposal, although implemented in some clients and in Synapse, has the downside of making the well-known discovery mandatory.
|
||||
When implemented in clients, in many circumstances it was hard to go back and use well-known discovery, as they may already know the homeserver URL.
|
||||
Since the authentication server is always tightly coupled to the homeserver (as opposed to the identity server), it makes sense to discover it via a Client-Server API endpoint.
|
||||
|
||||
The account management URL was also part of this proposal, but it was moved to the OpenID Connect Provider metadata because it makes more sense for the provider to advertise it, and not the homeserver.
|
||||
|
||||
### Discovery via the `m.login.oauth2` authentication method
|
||||
|
||||
The spec already defines a `m.login.oauth2` authentication method, but it was never implemented.
|
||||
The downside of this approach is that the plan is to deprecate the old login mechanism and it does not make sense to keep it just to discover the issuer.
|
||||
|
||||
### Discovery via WebFinger
|
||||
|
||||
OIDC already has a standard way to discover OP from an identifier: WebFinger.
|
||||
This is already adopted by Mastodon, and might help solve logging in via 3PIDs like emails.
|
||||
|
||||
Sample exchange:
|
||||
|
||||
```
|
||||
GET /.well-known/webfinger?
|
||||
resource= mxid:@john:example.com &
|
||||
rel= http://openid.net/specs/connect/1.0/issuer
|
||||
Host: example.com
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"subject": "mxid:@john:matrix.org",
|
||||
"links": [
|
||||
{
|
||||
"rel": "http://openid.net/specs/connect/1.0/issuer",
|
||||
"href": "https://account.example.com"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
The `mxid` scheme is a bit arbitrary here.
|
||||
The parameters in the URL should be percent-encoded, this was left unencoded for clarity.
|
||||
|
||||
The benefits of this approach are that it is standard and decouples the authentication server from the Matrix server:
|
||||
different authentication servers could be used by different accounts on the server.
|
||||
|
||||
The downsides of this approach are:
|
||||
|
||||
- the `.well-known/webfinger` resource is dynamic, which can be harder to host/delegate & might conflict with other services leveraging it like Mastodon
|
||||
- this does not cover discovering the authentication server for user registration
|
||||
|
||||
## Security considerations
|
||||
|
||||
None relevant.
|
||||
|
||||
## Unstable prefix
|
||||
|
||||
While this MSC is not in a released version of the specification,
|
||||
clients should use the `org.matrix.msc2965` unstable prefix for the endpoint,
|
||||
e.g. `GET /_matrix/client/unstable/org.matrix.msc2965/auth_metadata`.
|
||||
|
||||
[RFC8414]: https://tools.ietf.org/html/rfc8414
|
||||
[MSC2964]: https://github.com/matrix-org/matrix-spec-proposals/pull/2964
|
||||
[MSC2966]: https://github.com/matrix-org/matrix-spec-proposals/pull/2966
|
||||
[MSC3861]: https://github.com/matrix-org/matrix-spec-proposals/pull/3861
|
||||
[MSC4254]: https://github.com/matrix-org/matrix-spec-proposals/pull/4254
|
||||
[OpenID Connect Discovery]: https://openid.net/specs/openid-connect-discovery-1_0.html
|
||||
@ -0,0 +1,267 @@
|
||||
# MSC2966: Usage of OAuth 2.0 Dynamic Client Registration in Matrix
|
||||
|
||||
This proposal is part of the broader [MSC3861: Next-generation auth for Matrix, based on OAuth 2.0/OIDC][MSC3861].
|
||||
|
||||
This MSC specifies how Matrix clients SHOULD leverage the OAuth 2.0 Dynamic Client Registration Protocol ([RFC 7591](https://tools.ietf.org/html/rfc7591)) to register themselves before initiating an authorization flow.
|
||||
|
||||
In brief, once a client has obtained the homeserver's OAuth 2.0 metadata per [MSC2965], and before it can initiate an authorization request per [MSC2964], the client needs a `client_id`, which it can obtain by registering itself with that homeserver.
|
||||
|
||||
## Proposal
|
||||
|
||||
### Prerequisites
|
||||
|
||||
This proposal requires the client to know the following authorization server metadata about the homeserver:
|
||||
|
||||
- `registration_endpoint`: the URL where the client is able to register itself.
|
||||
|
||||
The discovery of the above metadata is out of scope for this MSC and is currently covered by [MSC2965].
|
||||
|
||||
### Client metadata
|
||||
|
||||
In OAuth 2.0, clients have a set of metadata values associated with their client identifier at an authorization server.
|
||||
These values are used to describe the client to the user and define how the client interacts with the authorization server.
|
||||
|
||||
This MSC specifies what metadata values are required by the Matrix specification and how a client can register itself with a Matrix homeserver to get a client identifier.
|
||||
|
||||
None of the metadata values are specific to Matrix: they are all registered by various specifications in the [OAuth Dynamic Client Registration Metadata](https://www.iana.org/assignments/oauth-parameters/oauth-parameters.xhtml#client-metadata) registry, and normative definitions of them are available in their respective RFCs in the registry.
|
||||
|
||||
|
||||
#### `client_uri` and relationship with other URIs
|
||||
|
||||
Per [RFC 7591](https://tools.ietf.org/html/rfc7591), the `client_uri` MUST point to a valid web page that SHOULD give the user more information about the client.
|
||||
This URL MUST use the `https` scheme and SHOULD NOT require authentication to access.
|
||||
It MUST NOT use a user or password in the authority component of the URI.
|
||||
|
||||
The `client_uri` is required and the server MAY reject client registrations with an invalid or missing `client_uri`.
|
||||
This URI is a common base for all the other URIs in the metadata: those MUST be either on the same host or on a subdomain of the host of the `client_uri`.
|
||||
The port number, path and query components MAY be different.
|
||||
For example, if the `client_uri` is `https://example.com/`, then one of the `redirect_uris` can be `https://example.com/callback` or `https://app.example.com/callback`, but not `https://app.com/callback`.
|
||||
|
||||
#### User-visible metadata values
|
||||
|
||||
The following metadata values SHOULD be used by clients to help users identify the client:
|
||||
|
||||
- `client_name`: Human-readable name of the client to be presented to the user
|
||||
- `logo_uri`: URL that references a logo for the client
|
||||
- `tos_uri`: URL that points to a human-readable terms of service document for the client
|
||||
- `policy_uri`: URL that points to a human-readable policy document for the client
|
||||
|
||||
All the URIs MUST use the `https` scheme and use the `client_uri` as a common base, as defined by the previous section.
|
||||
|
||||
If provided by the client, the homeserver SHOULD show or link to the `tos_uri` and `policy_uri` to the user.
|
||||
They MUST NOT use a user or password in the authority component of the URI.
|
||||
They MUST point to a valid web page and SHOULD NOT require authentication to access.
|
||||
|
||||
All of these metadata values are optional.
|
||||
|
||||
##### Metadata localization
|
||||
|
||||
As per [RFC 7591 sec. 2.2](https://tools.ietf.org/html/rfc7591#section-2.2), these metadata values MAY be localized.
|
||||
For example:
|
||||
|
||||
```json
|
||||
{
|
||||
"client_name": "Digital mailbox",
|
||||
"client_name#en-US": "Digital mailbox",
|
||||
"client_name#en-GB": "Digital postbox",
|
||||
"client_name#fr": "Boîte aux lettres numérique",
|
||||
"tos_uri": "https://example.com/tos.html",
|
||||
"tos_uri#fr": "https://example.com/fr/tos.html",
|
||||
"policy_uri": "https://example.com/policy.html",
|
||||
"policy_uri#fr": "https://example.com/fr/policy.html"
|
||||
}
|
||||
```
|
||||
|
||||
#### Metadata values required by the OAuth 2.0 authorization grant flow
|
||||
|
||||
The following metadata values are required to be present to use the OAuth 2.0 authorization code grant and refresh token grant, as described in [MSC2964]:
|
||||
|
||||
- `redirect_uris`: Array of redirection URIs for use in redirect-based flows
|
||||
- `response_types`: Array of the OAuth 2.0 response types that the client may use
|
||||
- `grant_types`: Array of OAuth 2.0 grant types that the client may use
|
||||
- `token_endpoint_auth_method`: String indicator of the requested authentication method for the token endpoint
|
||||
|
||||
The homeserver MUST support the `none` value for the `token_endpoint_auth_method`, as most Matrix clients are client-side only, do not have a server component, and therefore are public clients.
|
||||
|
||||
To use this grant:
|
||||
|
||||
- the `redirect_uris` MUST have at least one value
|
||||
- the `response_types` MUST include `code`
|
||||
- the `grant_types` MUST include `authorization_code` and `refresh_token`
|
||||
|
||||
#### Redirect URI validation
|
||||
|
||||
The redirect URI plays a critical role in validating the authenticity of the client.
|
||||
The client 'proves' its identity by demonstrating that it controls the redirect URI.
|
||||
This is why it is critical to have strict validation of the redirect URI.
|
||||
|
||||
The `application_type` metadata is used to determine the type of client.
|
||||
It defaults to `web` if not present, and can be set to `native` to indicate that the client is a native application.
|
||||
|
||||
In all cases, the redirect URI MUST NOT have a fragment component.
|
||||
|
||||
##### Web clients
|
||||
|
||||
`web` clients can use redirect URIs that:
|
||||
|
||||
- MUST use the `https` scheme
|
||||
- MUST NOT use a user or password in the authority component of the URI
|
||||
- MUST use the client URI as a common base for the authority component, as defined previously
|
||||
- MAY include an `application/x-www-form-urlencoded` formatted query component
|
||||
|
||||
Examples of valid redirect URIs (with `https://example.com/` as the client URI):
|
||||
|
||||
- `https://example.com/callback`
|
||||
- `https://app.example.com/callback`
|
||||
- `https://example.com:5173/?query=value`
|
||||
|
||||
Examples of invalid redirect URIs (with `https://example.com/` as the client URI):
|
||||
|
||||
- `https://example.com/callback#fragment`
|
||||
- `http://example.com/callback`
|
||||
- `http://localhost/`
|
||||
|
||||
##### Native clients
|
||||
|
||||
`native` clients can use three types of redirect URIs:
|
||||
|
||||
1. Private-Use URI Scheme:
|
||||
- the scheme MUST be prefixed with the client URI hostname in reverse-DNS notation. For example, if the client URI is `https://example.com/`, then a valid custom URI scheme would be `com.example.app:/`.
|
||||
- the URI MUST NOT have an authority component. This means that it MUST have either a single slash or none immediately following the scheme, with no hostname, username, or port.
|
||||
2. "http" URIs on the loopback interface:
|
||||
- it MUST use the `http` scheme
|
||||
- the host part MUST be `localhost`, `127.0.0.1`, or `[::1]`
|
||||
- it MUST have no port in the registered redirect URI. The homeserver MUST then accept any port number during the authorization flow.
|
||||
3. Claimed "https" Scheme URI:
|
||||
- some operating systems allow apps to claim "https" scheme URIs in the domains they control
|
||||
- when the browser encounters a claimed URI, instead of the page being loaded in the browser, the native app is launched with the URI supplied as a launch parameter
|
||||
- the same rules as for `web` clients apply
|
||||
|
||||
These restrictions are the same as defined by [RFC8252 sec. 7](https://tools.ietf.org/html/rfc8252#section-7).
|
||||
|
||||
Examples of valid redirect URIs (with `https://example.com/` as the client URI):
|
||||
|
||||
- `com.example.app:/callback`
|
||||
- `com.example:/`
|
||||
- `com.example:callback`
|
||||
- `http://localhost/callback`
|
||||
- `http://127.0.0.1/callback`
|
||||
- `http://[::1]/callback`
|
||||
|
||||
Examples of invalid redirect URIs (with `https://example.com/` as the client URI):
|
||||
|
||||
- `example:/callback`
|
||||
- `com.example.app://callback`
|
||||
- `https://localhost/callback`
|
||||
- `http://localhost:1234/callback`
|
||||
|
||||
### Dynamic client registration
|
||||
|
||||
Before initiating an authorization flow, the client MUST advertise its metadata to the homeserver to get back a `client_id`.
|
||||
|
||||
This is done through the `registration_endpoint` as described by [RFC7591 sec. 3](https://tools.ietf.org/html/rfc7591#section-3).
|
||||
|
||||
**Note**: Nothing in the usage of the `registration_endpoint` is specific to Matrix. The behaviours described here are the same as the ones defined in [RFC7591 sec. 3](https://tools.ietf.org/html/rfc7591#section-3).
|
||||
|
||||
To register, the client sends an HTTP POST to the `registration_endpoint` with its metadata as JSON in the body.
|
||||
For example, the client could send the following registration request:
|
||||
|
||||
```http
|
||||
POST /register HTTP/1.1
|
||||
Content-Type: application/json
|
||||
Accept: application/json
|
||||
Server: auth.example.com
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"client_name": "My App",
|
||||
"client_name#fr": "Mon application",
|
||||
"client_uri": "https://example.com/",
|
||||
"logo_uri": "https://example.com/logo.png",
|
||||
"tos_uri": "https://example.com/tos.html",
|
||||
"tos_uri#fr": "https://example.com/fr/tos.html",
|
||||
"policy_uri": "https://example.com/policy.html",
|
||||
"policy_uri#fr": "https://example.com/fr/policy.html",
|
||||
"redirect_uris": ["https://app.example.com/callback"],
|
||||
"token_endpoint_auth_method": "none",
|
||||
"response_types": ["code"],
|
||||
"grant_types": [
|
||||
"authorization_code",
|
||||
"refresh_token",
|
||||
"urn:ietf:params:oauth:grant-type:token-exchange"
|
||||
],
|
||||
"application_type": "web"
|
||||
}
|
||||
```
|
||||
|
||||
The server MUST ignore `grant_types` and `response_types` that it does not understand.
|
||||
|
||||
Upon successful registration, the server replies with an *HTTP 201 Created* response, with a JSON object containing the allocated `client_id` and all the registered metadata values.
|
||||
|
||||
With the previous registration request, the server would reply with:
|
||||
|
||||
```json
|
||||
{
|
||||
"client_id": "s6BhdRkqt3",
|
||||
"client_name": "My App",
|
||||
"client_uri": "https://example.com/",
|
||||
"logo_uri": "https://example.com/logo.png",
|
||||
"tos_uri": "https://example.com/tos.html",
|
||||
"policy_uri": "https://example.com/policy.html",
|
||||
"redirect_uris": ["https://app.example.com/callback"],
|
||||
"token_endpoint_auth_method": "none",
|
||||
"response_types": ["code"],
|
||||
"grant_types": ["authorization_code", "refresh_token"],
|
||||
"application_type": "web"
|
||||
}
|
||||
```
|
||||
|
||||
**Note**: in this example, the server has not registered the locale-specific values for `client_name`, `tos_uri`, and `policy_uri`, which is why they are not present in the response. The server also does not support the `urn:ietf:params:oauth:grant-type:token-exchange` grant type, which is why it is not present in the response.
|
||||
|
||||
The client MUST store the `client_id` for future use.
|
||||
|
||||
To avoid the number of client registrations growing over time, the server MAY choose to delete client registrations that don't have an active session.
|
||||
The server MUST NOT delete client registrations that have an active session.
|
||||
|
||||
Clients MUST perform a new client registration at the start of each authorization flow.
|
||||
|
||||
## Potential issues
|
||||
|
||||
Because each client on each user device will do its own registration, they may all have different `client_id`s.
|
||||
This means that the server may store the same client registration multiple times, which could lead to a large number of client registrations.
|
||||
|
||||
This can be mitigated by de-duplicating client registrations that have identical metadata.
|
||||
By doing so, different users on different devices using the same client can share a single `client_id`, reducing the overall number of registrations.
|
||||
|
||||
A subsequent MSC could be proposed to reliably identify multiple instances of the same client beyond a strict comparison using signed client metadata.
|
||||
|
||||
## Alternatives
|
||||
|
||||
An alternative approach would be to have the client host a JSON file containing its metadata and use that URL as the `client_id`.
|
||||
This is what the [*OAuth Client ID Metadata Document* draft](https://datatracker.ietf.org/doc/html/draft-parecki-oauth-client-id-metadata-document) proposes.
|
||||
|
||||
This approach has the advantage of being able to use the same `client_id` for different instances of the same client, but it has the disadvantage of requiring the client to host a JSON file on its own domain, as well as difficulties in handling updates to the metadata.
|
||||
|
||||
## Security considerations
|
||||
|
||||
The restrictions on the metadata values laid out in this MSC are a best effort to prevent client impersonation, but they are not flawless.
|
||||
|
||||
For web clients, it relies on the client's ability to prove ownership of the redirect URI, which can be guaranteed to some extent by sane DNS management and its use of TLS.
|
||||
If a client-related domain name hosts an open redirector, it could be used to impersonate the client.
|
||||
|
||||
For native clients, because they can use private-use URI schemes and localhost redirectors, it relies more on the underlying operating system's security model and their application distribution model.
|
||||
A good example of this is if a mobile client distributed through an app store registers the `app.acme.corp:` scheme in an effort to impersonate "ACME Corp's" app, then "ACME Corp" would have a valid case to take down the malicious app from the app store.
|
||||
|
||||
In both cases, it is crucial for the server to strictly enforce these restrictions and to show as much information about the client as possible to the user so they can make an informed decision.
|
||||
|
||||
## Unstable prefix
|
||||
|
||||
None relevant.
|
||||
|
||||
[RFC7591]: https://tools.ietf.org/html/rfc7591
|
||||
[RFC7592]: https://tools.ietf.org/html/rfc7592
|
||||
[RFC9126]: https://tools.ietf.org/html/rfc9126
|
||||
[MSC2964]: https://github.com/matrix-org/matrix-spec-proposals/pull/2964
|
||||
[MSC2965]: https://github.com/matrix-org/matrix-spec-proposals/pull/2965
|
||||
[MSC3861]: https://github.com/matrix-org/matrix-spec-proposals/pull/3861
|
||||
@ -0,0 +1,138 @@
|
||||
# MSC2967: API scopes
|
||||
|
||||
This proposal is part of the broader [MSC3861: Next-generation auth for Matrix, based on OAuth 2.0/OIDC][MSC3861].
|
||||
|
||||
When a user signs in with a Matrix client, it currently gives the client full access to their Matrix account.
|
||||
|
||||
This proposal introduces access scopes to allow restricting client access to only part(s) of the Matrix client API.
|
||||
|
||||
## Proposal
|
||||
|
||||
[MSC2964] introduces the usage of the OAuth 2.0 authorization code grant to authenticate against a Matrix homeserver.
|
||||
|
||||
An OAuth 2.0 grant has a scope associated to it which provides a framework for obtaining user consent.
|
||||
|
||||
The framework encourages the practise of obtaining additional use consent when a client asks for a new scope that was not granted previously.
|
||||
|
||||
This MSC does not attempt to define all the scopes necessary to cover all Matrix APIs and use cases, but proposes the structure of a namespace and a few scopes to cover existing use cases.
|
||||
|
||||
### Scope format
|
||||
|
||||
All scopes related to Matrix should start with `urn:matrix:` and use the `:` delimiter for further sub-division.
|
||||
|
||||
Scopes related to mapping of Client-Server API access levels should start with `urn:matrix:client:`.
|
||||
|
||||
For future MSCs that build on this namespace, unstable subdivisions should be used whilst in development.
|
||||
|
||||
For example, if MSCXXXX wants to introduce the `urn:matrix:client:foo` scope, it could use `urn:matrix:client:com.example.mscXXXX.foo` during development.
|
||||
If it needs to introduce multiple scopes, like `urn:matrix:client:foo` and `urn:matrix:client:bar`, it could use `urn:matrix:client:com.example.mscXXXX:foo` and `urn:matrix:client:com.example.mscXXXX:bar`.
|
||||
|
||||
### Allocated scopes
|
||||
|
||||
#### Full API read/write access
|
||||
|
||||
To support the existing semantic of granting full access to the Matrix C-S API the following scope is assigned:
|
||||
|
||||
| Scope | Purpose |
|
||||
| - | - |
|
||||
| `urn:matrix:client:api:*` | Grants full access to the Client-Server API |
|
||||
|
||||
In the future, a client would request more specific actions when required. e.g. something like `urn:matrix:client:api:read:*`
|
||||
|
||||
#### Device ID handling
|
||||
|
||||
Presently a device ID is typically generated by the homeserver and is associated with a specific series of access tokens.
|
||||
|
||||
This MSC proposes that the Matrix client is responsible for generating/allocating a device ID.
|
||||
A client can create a new device ID by generating a random string and asking for its associated scope on login.
|
||||
A client can adopt and rehydrate an existing device ID by asking for its associated scope on login.
|
||||
|
||||
The client must then add the requested device ID to the grant by including following token in the requested scope:
|
||||
`urn:matrix:client:device:<device ID>`, where `<device ID>` is the requested device ID.
|
||||
|
||||
There MUST be exactly one `urn:matrix:client:device:<device ID>` token in the requested scope.
|
||||
|
||||
When generating a new device ID, the client SHOULD generate a random string with enough entropy.
|
||||
It SHOULD only use characters from the unreserved character list defined by [RFC3986]:
|
||||
|
||||
> unreserved = a-z / A-Z / 0-9 / "-" / "." / "_" / "~"
|
||||
|
||||
Using this alphabet, a 10 character string is enough to stand a sufficient chance of being unique per user.
|
||||
The homeserver MAY reject a request for a device ID that is not long enough or contains characters outside the unreserved list.
|
||||
|
||||
In any case it MUST only use characters allowed by the OAuth 2.0 scope definition in [RFC6749] section 3.3,
|
||||
which is defined as the following ASCII ranges: `%x21 / %x23-5B / %x5D-7E`, i.e:
|
||||
|
||||
- alphanumeric characters (`A-Z`, `a-z`, `0-9`)
|
||||
- the following characters: `! # $ % & ' ( ) * + , - . / : ; < = > ? @ [ ] ^ _ \` { | } ~`
|
||||
|
||||
### Future scopes
|
||||
|
||||
Exact scopes for the whole API are intentionally not specified in this MSC.
|
||||
|
||||
It is envisioned that the namespace could be further partitioned to support use cases such as read only, write only, limited to one or more rooms etc.
|
||||
|
||||
Some thoughts/ideas for possible scopes are:
|
||||
|
||||
- `urn:matrix:client:api:<permission>` or `urn:matrix:client:api:<permission>:*` - grant limited access to the client API in all rooms. Permissions could be read, write, delete, append.
|
||||
- `urn:matrix:client:api:read:<resource>` - read-only access to the client API for just the named resource. e.g. `urn:matrix:client:api:read:#matrix-auth`
|
||||
|
||||
New MSCs should be created for proposing and discussing such new scopes.
|
||||
|
||||
## Potential issues
|
||||
|
||||
### Device ID collision
|
||||
|
||||
The Device ID handling involves a change in where device IDs are generated.
|
||||
Because the device ID is now generated by the client, it is possible to have a device ID collision.
|
||||
|
||||
Requiring enough entropy on the device ID ensures that the device ID is unique.
|
||||
With a 66 character alphabet and a 10 character device ID, the probability of a collision between 100 million devices is around 0.3%:
|
||||
|
||||
$$N = 66^{10}$$
|
||||
$$K = 10^{8}$$
|
||||
$$P \approx 1 - e^{-\frac{K^2}{2N}}$$
|
||||
$$P \approx 0.00318$$
|
||||
|
||||
This does also restrict the possible alphabet of device IDs, which was not restricted before.
|
||||
|
||||
### Generating the device ID on the client
|
||||
|
||||
This proposal effectively changes where the device ID is generated, from "most of the time on the server" to "every time on the client."
|
||||
|
||||
This doesn't introduce a new mechanism, as clients could already select a device ID instead of letting the server generate one.
|
||||
|
||||
One of the original motivation for this change was to adopt existing OAuth 2.0 mechanisms as much as possible.
|
||||
This meant not introducing Matrix-specific parameters (hence encoding the device ID in the scope) and not relying on non-standard server behaviour (hence the device ID being generated on the client).
|
||||
|
||||
In retrospect, because the whole proposal requires a Matrix-specific implementation anyway, compatibility with existing off-the-shelf OAuth 2.0 server implementations isn't a goal anymore:
|
||||
we could adopt a Matrix-specific parameter to specify the device ID, and let the server generate it if it's not provided.
|
||||
|
||||
As generating the device ID on the client hasn't been a problem in practice, this proposal kept it like that to avoid the cost of aligning the implementations.
|
||||
|
||||
## Alternatives
|
||||
|
||||
### Scopes
|
||||
|
||||
Scope could also have an URL format, e.g. `https://matrix.org/api/*/read`.
|
||||
|
||||
The URL prefix could either be static (`https://matrix.org`) or dependant on the homeserver (`https://matrix.example.com`).
|
||||
In both cases, the URL could be confused with API endpoints and in the second case it would require discovery to know what scopes to ask.
|
||||
|
||||
The actual namespace prefix and subdivisions are open to debate.
|
||||
|
||||
## Security considerations
|
||||
|
||||
As we are just representing existing access models there shouldn't be anything special.
|
||||
|
||||
## Unstable prefix
|
||||
|
||||
While this feature is in development the following unstable scope prefixes should be used:
|
||||
|
||||
- `urn:matrix:client` --> `urn:matrix:org.matrix.msc2967.client`
|
||||
|
||||
[MSC1597]: https://github.com/matrix-org/matrix-spec-proposals/pull/1597
|
||||
[MSC2964]: https://github.com/matrix-org/matrix-spec-proposals/pull/2964
|
||||
[MSC3861]: https://github.com/matrix-org/matrix-spec-proposals/pull/3861
|
||||
[RFC3986]: https://datatracker.ietf.org/doc/html/rfc3986
|
||||
[RFC6749]: https://datatracker.ietf.org/doc/html/rfc6749
|
||||
@ -1,152 +0,0 @@
|
||||
# MSC3061: Sharing room keys for past messages
|
||||
|
||||
In Matrix, rooms can be configured via the `m.room.history_visibility` state
|
||||
event such that historical messages can be visible to all Matrix users
|
||||
(`world_readable`), all room members (`shared`), room members from the time
|
||||
that they are invited to a room (`invited`), or room members from the time that
|
||||
they join a room (`joined`). However, currently in encrypted rooms, rooms with
|
||||
the history visibility set to `world_readable` or `shared` are effectively
|
||||
set to `invited` since other members generally do not send new members the keys
|
||||
to decrypt messages sent before they were invited or joined a room.
|
||||
|
||||
We define a "shared-history" flag that identifies keys for messages that were
|
||||
sent when the room's visibility setting was set to `world_readable` or
|
||||
`shared`. This allows clients to know which keys are "safe" to share with new
|
||||
members so that they can decrypt historical messages. We also give examples of
|
||||
ways in which this flag can be used.
|
||||
|
||||
|
||||
## Proposal
|
||||
|
||||
A room key (such as a megolm session) is flagged as having been used for shared
|
||||
history when it was used to encrypt a message while the room's history
|
||||
visibility setting was set to `world_readable` or `shared`.
|
||||
|
||||
If the client does not have an `m.room.history_visibility` state event for the
|
||||
room, or its value is not understood, the client should treat it as if its
|
||||
value is `joined` for the purposes of determining whether the key is used for
|
||||
shared history. This is in contrast with the normal processing of
|
||||
`m.room.history_visibility` which defaults to `world_readable` when there is no
|
||||
`m.room.history_visibility` state event or its value is not understood. This
|
||||
is done so that, in the event of a bug that causes the client to fail to obtain
|
||||
the state event, the client will fail in a secure manner.
|
||||
|
||||
Internally, a client may use any mechanism it wants to keep track of this flag.
|
||||
When a room key is marked as having been used for shared history:
|
||||
|
||||
- `m.room_key` and `m.forwarded_room_key` messages used to share this key have
|
||||
a `shared_history` property set to `true` e.g.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "m.room_key",
|
||||
"content": {
|
||||
"algorithm": "m.megolm.v1.aes-sha2",
|
||||
"room_id": "!room_id",
|
||||
"session_id": "session_id",
|
||||
"session_key": "session_key",
|
||||
"shared_history": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- the [`SessionData` type](https://spec.matrix.org/unstable/client-server-api/#definition-sessiondata)
|
||||
in key backups (that is, the plaintext object that gets encrypted into the
|
||||
`session_data` field) of this key has a `shared_history` property set to
|
||||
`true` in the decrypted JSON structure e.g.
|
||||
|
||||
```json
|
||||
{
|
||||
"algorithm": "m.megolm.v1.aes-sha2",
|
||||
"forwarding_curve25519_key_chain": [
|
||||
"hPQNcabIABgGnx3/ACv/jmMmiQHoeFfuLB17tzWp6Hw"
|
||||
],
|
||||
"sender_claimed_keys": {
|
||||
"ed25519": "aj40p+aw64yPIdsxoog8jhPu9i7l7NcFRecuOQblE3Y"
|
||||
},
|
||||
"sender_key": "RF3s+E7RkTQTGF2d8Deol0FkQvgII2aJDf3/Jp5mxVU",
|
||||
"session_key": "AgAAAADxKHa9uFxcXzwYoNueL5Xqi69IkD4sni8Llf...",
|
||||
"shared_history": true
|
||||
}
|
||||
```
|
||||
|
||||
and,
|
||||
- the [`SessionData` type](https://spec.matrix.org/unstable/client-server-api/#key-export-format)
|
||||
used in key exports has a `shared_history` property that is set to `true` for
|
||||
this key e.g.
|
||||
|
||||
```json
|
||||
{
|
||||
"algorithm": "m.megolm.v1.aes-sha2",
|
||||
"forwarding_curve25519_key_chain": [
|
||||
"hPQNcabIABgGnx3/ACv/jmMmiQHoeFfuLB17tzWp6Hw"
|
||||
],
|
||||
"sender_claimed_keys": {
|
||||
"ed25519": "aj40p+aw64yPIdsxoog8jhPu9i7l7NcFRecuOQblE3Y"
|
||||
},
|
||||
"sender_key": "RF3s+E7RkTQTGF2d8Deol0FkQvgII2aJDf3/Jp5mxVU",
|
||||
"session_key": "AgAAAADxKHa9uFxcXzwYoNueL5Xqi69IkD4sni8Llf...",
|
||||
"shared_history": true
|
||||
}
|
||||
```
|
||||
|
||||
When a client obtains a key that has the `shared_history` property set to
|
||||
`true`, then it flags the key internally as having been used for shared
|
||||
history. Otherwise, the key should not be flagged as such.
|
||||
|
||||
When the room's history visibility setting changes to `world_readable` or
|
||||
`shared` from `invited` or `joined`, or changes to `invited` or `joined` from
|
||||
`world_readable` or `shared`, senders that support this flag must rotate their
|
||||
megolm sessions.
|
||||
|
||||
Clients may use this flag to modify their behaviour with respect to sharing
|
||||
keys. For example, when the user invites someone to the room, they may
|
||||
preemptively share keys that have this flag with the invited user. Other
|
||||
behaviours may be possible, but must be careful not to guard against malicious
|
||||
homeservers. See the "Security Considerations" section.
|
||||
|
||||
## Potential issues
|
||||
|
||||
Room keys from clients that do not support this proposal will not be eligible
|
||||
for the modified client behaviour.
|
||||
|
||||
The suggested behaviour in this MSC is to only share additional keys when
|
||||
inviting another user. This does not allow users who join the room but were
|
||||
not invited (for example, if membership is restricted to another space, or if
|
||||
the room is publicly joinable) to receive the keys. Also, if the inviter does
|
||||
not have all the keys available for whatever reason, the invitee has no way of
|
||||
receiving the keys. This may be solved in the future when we have a mechanism
|
||||
for verifying room membership.
|
||||
|
||||
## Alternatives
|
||||
|
||||
Rather than having the sender flagging keys, a client can paginate through the
|
||||
room's history to determine the room's history visibility settings when the
|
||||
room key was used. This would not require any changes, but has performance
|
||||
problems. In addition, the server could lie about the room history while the
|
||||
user is paginating through the history. By having the sender flag keys, this
|
||||
ensures that the key is treated in a manner consistent with the sender's view
|
||||
of the room.
|
||||
|
||||
Rather than using a boolean flag, we could include the history visibility
|
||||
setting as-is. For example, a `history_visibility` field could be added, which
|
||||
is set to the history visibility setting (e.g. `world_readable`). This
|
||||
produces an equivalent effect, but it pushes the processing of the history
|
||||
visibility setting to the receiver rather than the sender. For consistency, it
|
||||
is better for as much of the decision-making done by the sender, rather than
|
||||
the receiver.
|
||||
|
||||
## Security considerations
|
||||
|
||||
Clients should still ensure that keys are only shared with authorized users and
|
||||
devices, as a malicious homeserver could inject fake room membership events.
|
||||
One way to ensure that keys are only shared with authorized users is to only
|
||||
share keys with users when the client invites them, as the client is then
|
||||
certain that the user is allowed to be in the room. Another way is to have a
|
||||
mechanism of verifying membership, such as the method proposed in
|
||||
[MSC3917](https://github.com/matrix-org/matrix-spec-proposals/pull/3917).
|
||||
|
||||
## Unstable prefix
|
||||
|
||||
Until this feature lands in the spec, the property name to be used is
|
||||
`org.matrix.msc3061.shared_history` rather than `shared_history`.
|
||||
@ -0,0 +1,312 @@
|
||||
# MSC3266: Room Summary API
|
||||
|
||||
Quite a few clients and tools have a need to preview a room:
|
||||
|
||||
- matrix.to may want to show avatar and name of a room.
|
||||
- Nextcloud may want to list the names and avatars of your `/joined_rooms` when
|
||||
asking where to share the media.
|
||||
- A client may want to preview a room, when hovering a room alias, id or after
|
||||
clicking on it.
|
||||
- A client may want to preview a room, when the user is trying to knock on it or
|
||||
to show pending knocks.
|
||||
- A traveller bot may use that to show a room summary on demand without actually
|
||||
keeping the whole room state around and having to subscribe to /sync (or
|
||||
using the appservice API).
|
||||
- A client can use this to knock on a room instead of joining it when the user
|
||||
tries to join my room alias or link.
|
||||
- External services can use this API to preview rooms like shields.io.
|
||||
|
||||
There are a few ways to request a room summary, but they only support some of
|
||||
the use cases. The [spaces hierarchy API](https://spec.matrix.org/v1.13/client-server-api/#get_matrixclientv1roomsroomidhierarchy) only provides
|
||||
limited control over what rooms to summarize and returns a lot more data than
|
||||
necessary. `{roomid}/initialSync` and `{roomid}/state/{event_type}` don't work
|
||||
over federation and are much heavier than necessary or need a lot of http calls
|
||||
for each room.
|
||||
|
||||
## Proposal
|
||||
|
||||
A new client-server API, which allows you to fetch a summary of a room by id or
|
||||
alias.
|
||||
|
||||
### Client-Server API
|
||||
|
||||
The API returns a summary of the given room, provided the user is either already
|
||||
a member, or has the necessary permissions to join. (For example, the user may
|
||||
be a member of a room mentioned in an `allow` condition in the join rules of a
|
||||
restricted room.)
|
||||
|
||||
For unauthenticated requests a response should only be returned if the room is
|
||||
publicly accessible; specifically, that means either:
|
||||
* the room has `join_rule: public` or `join_rule: knock`, or:
|
||||
* the room has `history_visibility: world_readable`.
|
||||
|
||||
Note that rooms the user has been invited to or knocked at might result in
|
||||
outdated or partial information, or even a 404 `M_NOT_FOUND` response, since
|
||||
the the homeserver may not have access to the current state of the room. (In
|
||||
particular: the federation API does not provide a mechanism to get the current
|
||||
state of a non-publicly-joinable room where the requesting server has no
|
||||
joined members. Improving this is left for a future MSC.)
|
||||
|
||||
A request could look like this:
|
||||
|
||||
```
|
||||
GET /_matrix/client/v1/room_summary/{roomIdOrAlias}?
|
||||
via=matrix.org&
|
||||
via=neko.dev
|
||||
```
|
||||
|
||||
(This is not under `/rooms`, because it can be used with an alias.)
|
||||
|
||||
- `roomIdOrAlias` can be the roomid or an alias to a room.
|
||||
- `via` are servers that should be tried to request a summary from, if it can't
|
||||
be generated locally. These can be from a matrix URI, matrix.to link or a
|
||||
`m.space.child` event for example.
|
||||
|
||||
A successful `200` response should contain a JSON object giving information about the room. For example:
|
||||
|
||||
```json5
|
||||
{
|
||||
room_id: "!ol19s:bleecker.street",
|
||||
avatar_url: "mxc://bleecker.street/CHEDDARandBRIE",
|
||||
guest_can_join: false,
|
||||
name: "CHEESE",
|
||||
num_joined_members: 37,
|
||||
topic: "Tasty tasty cheese",
|
||||
world_readable: true,
|
||||
join_rule: "public",
|
||||
room_type: "m.space",
|
||||
membership: "invite",
|
||||
encryption: "m.megolm.v100",
|
||||
room_version: "9001",
|
||||
}
|
||||
```
|
||||
|
||||
See below for a more detailed description of the response.
|
||||
|
||||
#### Unauthenticated and guest access
|
||||
|
||||
This API may optionally be exposed to unauthenticated users, or guest users, at the choice of
|
||||
server implementations and administrators. Clients MUST NOT rely on being able
|
||||
to use the endpoint without authentication, and should degrade gracefully if
|
||||
access is denied.
|
||||
|
||||
* Rationale: unauthenticated access is beneficial for third-party services such as
|
||||
https://matrix.to. On the other hand, allowing unauthenticated access may leak
|
||||
information about rooms that would otherwise be restricted to registered users (particularly
|
||||
on servers which do not allow public federation), and may lead to unexpected
|
||||
resource usage.
|
||||
|
||||
Servers may rate limit how often they fetch information over federation more heavily, if the
|
||||
user is unauthenticated.
|
||||
|
||||
When the endpoint is called unauthenticated, the `membership` field will be
|
||||
absent in the response.
|
||||
|
||||
As mentioned above, a successful response should only be returned for
|
||||
unauthenticated requests where the room is publicly accessible.
|
||||
|
||||
#### Response format
|
||||
|
||||
If the room cannot be found, the server should return a `404`
|
||||
HTTP status code along with an `M_NOT_FOUND` error code. The server should
|
||||
NOT return `M_UNAUTHORIZED` or otherwise divulge existence of a room, that
|
||||
requires authentication to preview, if the request is unauthenticated or
|
||||
authenticated by a user without access to the room.
|
||||
|
||||
If the request is successful, the server returns a JSON object containing the
|
||||
following properties:
|
||||
|
||||
| property name | description |
|
||||
| ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| avatar_url | Optional. Avatar of the room |
|
||||
| canonical_alias | Optional. The canonical alias of the room, if any. |
|
||||
| guest_can_join | Required. Whether guests can join the room. |
|
||||
| join_rule | Optional. Join rules of the room |
|
||||
| name | Optional. Name of the room |
|
||||
| num_joined_members | Required. Member count of the room |
|
||||
| room_id | Required. Id of the room |
|
||||
| room_type | Optional. Type of the room, if any, i.e. `m.space` |
|
||||
| topic | Optional. Topic of the room |
|
||||
| world_readable | Required. If the room history can be read without joining. |
|
||||
| allowed_room_ids | Optional. If the room is a restricted room, these are the room IDs which are specified by the join rules. Empty or omitted otherwise. |
|
||||
| encryption | Optional. If the room is encrypted, this specifies the algorithm used for this room. Otherwise, omitted. |
|
||||
| membership | Optional (1). The current membership of this user in the room. Usually `leave` if the server has no local users (so fetches the room over federation). |
|
||||
| room_version | Optional (for historical reasons (2)). Version of the room. |
|
||||
|
||||
(1) The `membership` field will not be present when called unauthenticated, but
|
||||
is required when called authenticated.
|
||||
|
||||
(2) Prior to this MSC, `/_matrix/federation/v1/hierarchy/{roomId}` doesn't
|
||||
return the room version, so `room_version` may be unavailable for remote
|
||||
rooms.
|
||||
|
||||
Most of the fields above are the same as those returned by
|
||||
[`/_matrix/client/v3/publicRooms`](https://spec.matrix.org/v1.13/client-server-api/#get_matrixclientv3publicrooms). (Those
|
||||
same fields are also a subset of those returned by
|
||||
[`/_matrix/client/v1/rooms/{roomId}/hierarchy`](https://spec.matrix.org/v1.13/client-server-api/#get_matrixclientv1roomsroomidhierarchy).) The
|
||||
exceptions are:
|
||||
|
||||
* `allowed_room_ids`. This is currently accessible via the federation
|
||||
hierarchy endpoint [`GET
|
||||
/_matrix/federation/v1/hierarchy/{roomId}`](https://spec.matrix.org/v1.13/server-server-api/#get_matrixfederationv1hierarchyroomid),
|
||||
and is necessary
|
||||
to distinguish if the room can be joined or only knocked at.
|
||||
|
||||
* `encryption`. Currently part of the [stripped
|
||||
state](https://spec.matrix.org/v1.13/client-server-api/#stripped-state). Some
|
||||
users may only want to join encrypted rooms; alternatively, clients may want to filter
|
||||
out encrypted rooms, for example if they don't support encryption, or do not
|
||||
support particular encryption algorithms.
|
||||
|
||||
* `membership`. Exposed solely for convenience: a client has many other ways
|
||||
to access this information.
|
||||
|
||||
* `room_version`. Also part of the [stripped
|
||||
state](https://spec.matrix.org/v1.13/client-server-api/#stripped-state).
|
||||
Can be used by clients to show incompatibilities with a room early.
|
||||
|
||||
#### Modifications to `/_matrix/client/v1/rooms/{roomId}/hierarchy`
|
||||
|
||||
For symmetry the `room_version`, `allowed_room_ids` and `encryption` fields are
|
||||
also added to the `/hierarchy` API.
|
||||
|
||||
### Server-Server API
|
||||
|
||||
For fetching room summaries of a room a server is not joined to, the federation API of the
|
||||
[`/hierarchy`](https://spec.matrix.org/v1.13/server-server-api/#get_matrixfederationv1hierarchyroomid)
|
||||
endpoint is reused. This provides (with a few changes) all the information
|
||||
needed in this MSC, but it also provides a few additional fields and one level
|
||||
of children of this room.
|
||||
|
||||
Additionally the `encryption` and `room_version` fields are added to the
|
||||
responses for each room.
|
||||
|
||||
In theory one could also add the `max_depth` parameter with allowed values of 0
|
||||
and 1, so that child rooms are excluded, but this performance optimization does
|
||||
not seem necessary at this time and could be added at any later point while
|
||||
degrading gracefully.
|
||||
|
||||
(Originally there was a separate federation API for this, but it was decided by
|
||||
the author that lowering the duplication on the federation side is the way to
|
||||
go.)
|
||||
|
||||
## Potential issues
|
||||
|
||||
### Performance
|
||||
|
||||
Clients may start calling this API very often instead of using the
|
||||
[`/hierarchy`](https://spec.matrix.org/v1.13/client-server-api/#get_matrixclientv1roomsroomidhierarchy)
|
||||
for spaces or caching the state received via `/sync`.
|
||||
Looking up all the state events required for this API may cause performance
|
||||
issues in that case.
|
||||
|
||||
To mitigate that, servers are recommended to cache the response for this API and
|
||||
apply rate limiting if necessary.
|
||||
|
||||
## Alternatives
|
||||
|
||||
### The Space Summary / `/hierarchy` API
|
||||
|
||||
The
|
||||
[`/hierarchy`](https://spec.matrix.org/v1.13/client-server-api/#get_matrixclientv1roomsroomidhierarchy)
|
||||
API could be used, but it returns more data than necessary by default (but it
|
||||
can be limited to just 1 room) such as all the `m.space.child` events in a
|
||||
space, but also is missing the room version, membership and the encryption
|
||||
field.
|
||||
|
||||
Additionally the `/hierarchy` API doesn't work using aliases. This currently
|
||||
doesn't allow users to preview rooms not known to the local server over
|
||||
federation. While the user can resolve the alias and then call the `/hierarchy`
|
||||
API using the resolved roomid, a roomid is not a routable entity, so the server
|
||||
never receives the information which servers to ask about the requested rooms.
|
||||
This MSC resolves that by providing a way to pass server names to ask for the
|
||||
room as well as the alias directly.
|
||||
|
||||
For server to server communication the efficiency is not as important, which is
|
||||
why we use the same API as the `/hierarchy` API to fetch the data over
|
||||
federation.
|
||||
|
||||
### The `sync` API
|
||||
|
||||
For joined rooms, the `/sync` API can be used to get a summary for all joined
|
||||
rooms. Apart from not working for unjoined rooms, like knocks, invites and space
|
||||
children, `/sync` is very heavy for the server and the client needs to cobble
|
||||
together information from the `state`, `timeline` and
|
||||
[`summary`](https://github.com/matrix-org/matrix-doc/issues/688) sections to
|
||||
calculate the room name, topic and other fields provided in this MSC.
|
||||
|
||||
Furthermore, the membership counts in the summary field are only included, if
|
||||
the client is using lazy loading. This MSC provides similar information as
|
||||
calling `/sync`, but to allow it to work for unjoined rooms it only uses information
|
||||
from the stripped state. Additionally, it excludes `m.heroes` as well as membership
|
||||
events, since those are not included in the stripped state of a room. (A client
|
||||
can call `/joined_members` to receive those if needed. It may still make sense
|
||||
to include heroes so that clients could construct a human-friendly room display
|
||||
name in case both the name and the canonical alias are absent; but solving the
|
||||
security implications with that may better be left to a separate MSC.)
|
||||
|
||||
### The `/state` API
|
||||
|
||||
The `/state` API could be used, but the response is much bigger than needed,
|
||||
can't be cached as easily and may need more requests. This also doesn't work
|
||||
over federation (yet). The variant of this API, which returns the full state of
|
||||
a room, also does not return stripped events, which prevents it from being used
|
||||
by non-members. The event for specific events DOES return stripped events, but
|
||||
could not provide a member count for a room.
|
||||
|
||||
### Proper peeking
|
||||
|
||||
Peeking could solve this too, but with additional overhead and
|
||||
[MSC2753](https://github.com/matrix-org/matrix-doc/pull/2753) is much more
|
||||
complex. You need to add a peek and remember to remove it. For many usecases you
|
||||
just want to do one request to get info about a room, no history and no updates.
|
||||
This MSC solves that by reusing the existing hierarchy APIs, returns a
|
||||
lightweight response and provides a convenient API instead.
|
||||
|
||||
### A more batched API
|
||||
|
||||
This API could take a list of rooms with included `via`s for each room instead
|
||||
of a single room (as a POST request). This may have performance benefits for the
|
||||
federation API and a client could then easily request a summary of all joined
|
||||
rooms. It could still request the summary of a single room by just including
|
||||
only a single room in the POST or a convenience GET could be provided by the
|
||||
server (that looks like this proposal). At the same time, a batched API is inherently
|
||||
more complex to implement for both clients and servers. Additionally, there are no
|
||||
known use cases yet that would benefit from batched access.
|
||||
|
||||
### MSC3429: Individual room preview API (closed)
|
||||
|
||||
[MSC3429](https://github.com/matrix-org/matrix-doc/pull/3429) is an alternative
|
||||
implementation, but it chooses a different layout. While this layout might make
|
||||
sense in the future, it is inconsistent with the APIs already in use, harder to
|
||||
use for clients (iterate array over directly including the interesting fields)
|
||||
and can't reuse the federation API. In my opinion an MSC in the future, that
|
||||
bases all summary APIs on a list of stripped events seems like the more
|
||||
reasonable approach to me and would make the APIs more extensible.
|
||||
|
||||
## Security considerations
|
||||
|
||||
This API may leak data, if implemented incorrectly or malicious servers could
|
||||
return wrong results for a summary.
|
||||
|
||||
Those are the same concerns as on [MSC2946](https://github.com/matrix-org/matrix-doc/pull/2946)
|
||||
or [MSC3173](https://github.com/matrix-org/matrix-doc/pull/3173).
|
||||
|
||||
This API could also be used for denial of service type attacks. Appropriate
|
||||
ratelimiting and caching should be able to mitigate that.
|
||||
|
||||
## Unstable prefix
|
||||
|
||||
This uses the `im.nheko.summary` unstable prefix. As such the paths are prefixed
|
||||
with `unstable/im.nheko.summary`.
|
||||
|
||||
- the client API will be
|
||||
`/_matrix/client/unstable/im.nheko.summary/summary/{roomIdOrAlias}`.
|
||||
|
||||
Some implementations still use
|
||||
`/_matrix/client/unstable/im.nheko.summary/rooms/{roomIdOrAlias}/summary`,
|
||||
but this was a mistake in this MSC. Endpoints using aliases shouldn't be under /rooms.
|
||||
|
||||
Additionally the fields `encryption` and `room_version` in the summaries are
|
||||
prefixed with `im.nheko.summary` as well since it is new. The latter might still
|
||||
be called `im.nheko.summary.version` in some implementations.
|
||||
@ -0,0 +1,80 @@
|
||||
# MSC3823: Account Suspension
|
||||
|
||||
Unlike [account locking](https://spec.matrix.org/v1.12/client-server-api/#account-locking), suspension
|
||||
allows the user to have a (largely) readonly view of their account. Homeserver administrators and
|
||||
moderators may use this functionality to temporarily deactivate an account, or place conditions on
|
||||
the account's experience. Critically, like locking, account suspension is reversible, unlike the
|
||||
deactivation mechanism currently available in Matrix - a destructive, irreversible, action.
|
||||
|
||||
This proposal introduces a concept of suspension to complement locking for server admins to use. Locking
|
||||
is typically more used in narrow scenarios, where the server admin wants to prevent the account from
|
||||
engaging any further. An example of this may be too many failed password attempts. Suspension is more
|
||||
general purpose to create a barrier to further action - a "something weird is going on -> suspend"
|
||||
kind of button.
|
||||
|
||||
The error code introduced by this proposal is accompanied by guidelines on how servers can implement
|
||||
suspension. APIs to invoke or clear suspension are not introduced, and left as an implementation detail.
|
||||
These will typically be done through an administrator-only API.
|
||||
|
||||
## Proposal
|
||||
|
||||
When an account is suspended, any [Client-Server API](https://spec.matrix.org/v1.10/client-server-api/)
|
||||
endpoint MAY return a 403 HTTP status code with `errcode` of `M_USER_SUSPENDED`. This indicates to
|
||||
the user that the associated action is unavailable.
|
||||
|
||||
Clients should note that for more general endpoints, like `/send/:eventType`, suspension MAY only be
|
||||
applied to a subset of request parameters. For example, a user may be allowed to *redact* events but
|
||||
not send messages.
|
||||
|
||||
The specific list of permitted actions during suspension is left as a deliberate implementation
|
||||
detail, however a server SHOULD permit the user to:
|
||||
|
||||
* Log in/create additional sessions (which should also behave as suspended).
|
||||
* See and receive messages, particularly via `/sync` and `/messages`.
|
||||
* [Verify their other devices](https://spec.matrix.org/v1.10/client-server-api/#device-verification)
|
||||
and write associated [cross-signing data](https://spec.matrix.org/v1.10/client-server-api/#cross-signing).
|
||||
* [Populate their key backup](https://spec.matrix.org/v1.10/client-server-api/#server-side-key-backups).
|
||||
* Leave rooms & reject invites.
|
||||
* Redacting their own events.
|
||||
* Log out/delete any device of theirs, including the current session.
|
||||
* Deactivate their account, potentially with a deliberate time delay to discourage making a new
|
||||
account right away.
|
||||
* Change or add [admin contacts](https://spec.matrix.org/v1.10/client-server-api/#adding-account-administrative-contact-information),
|
||||
but not remove. Servers are recommended to only permit this if they keep a changelog on contact information
|
||||
to prevent misuse.
|
||||
|
||||
The recommendation for users to continue receiving/reading messages is largely so the administrator
|
||||
can maintain contact with the user, where applicable. Future MSCs may improve upon the admin<>user
|
||||
communication, and account locking may also be used to prevent access to messages.
|
||||
|
||||
The suggested set of explicitly forbidden actions is:
|
||||
|
||||
* Joining or knocking on rooms, including accepting invites.
|
||||
* Sending messages.
|
||||
* Sending invites.
|
||||
* Changing profile data (display name and avatar).
|
||||
* Redacting other users' events (when a moderator/admin of a room, for example).
|
||||
|
||||
## Potential issues
|
||||
|
||||
This proposal does not communicate *why* a user's account is restricted. The human-readable `error`
|
||||
field may contain some information, though anything comprehensive may not be surfaced to the user.
|
||||
A future MSC is expected to build a system for both informing the user of the action taken against
|
||||
their account and allow the user to appeal that action.
|
||||
|
||||
## Alternatives
|
||||
|
||||
No significant alternatives are plausible. `M_USER_DEACTIVATED` could be expanded with a `permanent`
|
||||
flag, though ideally each error code should provide meaning on its own.
|
||||
|
||||
The related concept of locking, as discussed in places like [MSC3939](https://github.com/matrix-org/matrix-spec-proposals/pull/3939)
|
||||
and [matrix-org/glossary](https://github.com/matrix-org/glossary), is semantically different from
|
||||
suspension. Suspension has the key difference that the user is *not* logged out of their client,
|
||||
typically used by safety teams, while locking *does* log the user out and would primarily be used by
|
||||
security teams. A future MSC may combine or split the two related error codes into a descriptive set
|
||||
of capabilities the user can perform.
|
||||
|
||||
## Unstable prefixes
|
||||
|
||||
Until this proposal is considered stable, implementations must use
|
||||
`ORG.MATRIX.MSC3823.USER_SUSPENDED` instead of `M_USER_SUSPENDED`.
|
||||
@ -0,0 +1,542 @@
|
||||
# MSC3861: Next-generation auth for Matrix, based on OAuth 2.0/OIDC
|
||||
|
||||
The goal of this MSC is to propose a new set of authentication APIs for Matrix, based on the OAuth 2.0 and OpenID Connect (OIDC) specifications.
|
||||
To understand this proposal, it is important to lay out the reasoning behind it.
|
||||
|
||||
## Rationale
|
||||
|
||||
Matrix currently uses a [custom protocol for authentication](https://spec.matrix.org/v1.13/client-server-api/#client-authentication), one that hasn't been significantly updated in many years.
|
||||
This leads to two main problems:
|
||||
|
||||
1. The custom protocol does not follow best practices, nor does it use the collective experience of other authentication protocols.
|
||||
2. While relatively generic, the custom protocol does not currently support many desired features that users and organizations actually want.
|
||||
|
||||
These points could be addressed by iterating on the current protocol; however, using the industry standard OAuth 2.0 allows us to benefit from its experience without having to build a competing (relatively generic) authentication protocol.
|
||||
We also will benefit more easily from any further enhancements or best practice recommendations of OAuth 2.0.
|
||||
|
||||
## Background and motivation
|
||||
|
||||
This section expands on the benefits of moving to OAuth 2.0.
|
||||
It is purely informative and not part of the actual proposal.
|
||||
The proposal itself is high-level, and the technical implications are split into separate, more focused MSCs.
|
||||
|
||||
### Current paradigm
|
||||
|
||||
The Matrix Client-Server API currently has endpoints for [authenticating][spec-auth] and [managing][spec-account] users.
|
||||
This API design is focused on displaying authentication UI as native controls within the Matrix client.
|
||||
It is meant to offer multiple server-defined, multi-staged authentication flows, which the client then uses to build a native UI.
|
||||
|
||||
[spec-auth]: https://spec.matrix.org/v1.13/client-server-api/#client-authentication
|
||||
[spec-account]: https://spec.matrix.org/v1.13/client-server-api/#account-registration-and-management
|
||||
|
||||
As an example, on the Matrix.org homeserver, the user registration flow is gated behind three stages:
|
||||
|
||||
1. A CAPTCHA challenge
|
||||
1. An agreement to the terms of service
|
||||
1. An email verification
|
||||
|
||||
On paper, this lets clients implement their own UI for authentication, but in practice, the dynamic nature of the flows makes it difficult to implement a streamlined UI.
|
||||
Moreover, the fact that those stages are displayed on client-driven UI, and not on a homeserver-specific domain, makes them insecure, impossible to design, or behave poorly in terms of user experience.
|
||||
|
||||
A few issues can be highlighted from this particular example:
|
||||
|
||||
- When setting up a CAPTCHA challenge, CAPTCHA services expect the challenge to be served from a specific domain. Because the client can be on any domain, [Synapse currently advises disabling host verification](https://element-hq.github.io/synapse/latest/CAPTCHA_SETUP.html#getting-api-keys).
|
||||
When this option is disabled, the CAPTCHA service expects the server to verify the domain of the challenge, which is not possible.
|
||||
- The agreement to the terms of service can be completely ignored by the client, as it only requires the client to send a request with no specific data to validate it.
|
||||
This means the server has to trust the goodwill of the client to make sure the user agrees to the terms of service.
|
||||
- The current design of the email verification flow has a confusing user experience.
|
||||
The link sent to the user by email leads to a screen where the user is prompted to return to their client.
|
||||
A better approach would be to send a one-time code by email, which avoids one extra context switch and can sometimes be automatically filled by the operating system.
|
||||
- Because the password field is displayed by the client, any system password manager will save the password as associated with the client domain.
|
||||
This means that if the user chooses to use a different client, they will have to manually find the password in their password manager, as the password will not be associated with the _service_, i.e., the homeserver domain.
|
||||
|
||||
**Note**: Many of these points could be improved with individual improvements to each of those stages, and multiple MSCs already exist to address some of them.
|
||||
|
||||
### Benefits of authenticating end-users through a web browser
|
||||
|
||||
Rather than trying to fix the existing flows, this MSC proposes an alternative approach to authentication.
|
||||
Authenticating end-users through a web browser is a well-established approach for many applications and would help solve most of the UI quirks mentioned above.
|
||||
Though, some applications may wish to retain browser-less authentication, which this proposal supports thanks to the inherited authentication specifications.
|
||||
|
||||
The general idea is simple: to authenticate a user, the client redirects the user to a URL provided by the homeserver to complete the authentication flow and then to redirect the user back to the client.
|
||||
|
||||
This allows the homeserver to implement an authentication (and registration) flow tailored to its requirements.
|
||||
A public service with open registration like Matrix.org could have secure CAPTCHA prompts, email verification, and terms of service agreements, with both password-based and social-based authentication.
|
||||
A private service could have SSO-based authentication with specific 2FA requirements.
|
||||
|
||||
Using the homeserver's domain name in the authentication flow unlocks new kinds of authentication mechanisms and enhances the user experience of existing flows.
|
||||
WebAuthn credentials/Passkeys, as well as client certificate-based authentication, are all bound to the domain they are registered on, making them impractical if the client is directly authenticating the end user.
|
||||
Password managers will also function better if the credentials are bound to the homeserver domain instead of the client itself.
|
||||
|
||||
This makes it possible to design widely different authentication flows for different homeservers, without having to cross an API boundary.
|
||||
Implementers of said flows can focus on the specifics of their deployment without worrying about defining the right API between the client and the homeserver.
|
||||
|
||||
Bouncing between the client and the browser may lead to user confusion, especially on operating systems with limited window management capabilities.
|
||||
Mobile operating systems such as iOS and Android provide a way to embed a secure browser view within an application ([`ASWebAuthenticationSession`](https://developer.apple.com/documentation/authenticationservices/aswebauthenticationsession) on iOS, [Custom Tabs](https://developer.android.com/develop/ui/views/layout/webapps/overview-of-android-custom-tabs) on Android).
|
||||
In those cases the host application cannot control or monitor what is happening within the embedded browser view, but that view shares the same context as the system-wide browser.
|
||||
|
||||
### Concealing the user's credentials
|
||||
|
||||
Another benefit of authenticating outside the client is that the client never has the user's full credentials.
|
||||
This has two important implications:
|
||||
|
||||
- The client can't store the user's credentials, and thus can't use them to gain access without the user's consent.
|
||||
- The user can use different clients without worrying about revealing their account credentials to unknown parties. Only their homeserver ever interacts with their credentials.
|
||||
|
||||
With the current authentication paradigm, sensitive account operations, such as changing passwords or deactivating the account, are protected with authentication steps where the client must present the user's credentials.
|
||||
|
||||
With the current state of the ecosystem, in a password-based account, this means sending the user's password again: nothing prevents the client from storing the password on the initial login and using it to perform these actions.
|
||||
To put that in perspective, this means that if a user on the matrix.org homeserver tries to log in on a new client they want to try out, this client would be able to completely lock them out of their account by logging out other sessions and changing their password without additional confirmation from the user.
|
||||
|
||||
This also effectively widens the attack surface for credential theft, as both the client and the homeserver currently have access to the user's credentials.
|
||||
|
||||
Making it mandatory for the client to go through the system browser to authenticate means there is a part of the login flow that the client can't skip and doesn't have control over.
|
||||
The user has to give their explicit consent during that part of the flow, with no way for the client to bypass it.
|
||||
|
||||
This opens up the possibility of giving more restrictive access to the user's account.
|
||||
It would open up Matrix to a new class of clients with only partial access to the user's account.
|
||||
|
||||
**Note**: This does not change the level of trust that the user places in their homeserver. Their E2EE keys are still controlled by the client and never exposed to the homeserver, keeping the content of their events secret from the homeserver.
|
||||
|
||||
### Limitations of the existing [`m.login.sso`] flow
|
||||
|
||||
The Matrix Client-Server API already has an existing browser-based authentication flow.
|
||||
The [`m.login.sso`] flow is effectively used as a single-staged flow, which works as follows:
|
||||
|
||||
1. The client redirects to the homeserver to start the authentication
|
||||
1. The homeserver authenticates the user
|
||||
1. It redirects back to the client with a single-use "login token"
|
||||
1. The client exchanges that "login token" to get an access token
|
||||
|
||||
This flow design is very similar to the industry-standard OAuth 2.0 authorization code flow as described in [RFC 6749](https://tools.ietf.org/html/rfc6749#section-4.1). However, [`m.login.sso`] is relatively simple and does not incorporate many of the security features commonly found in OAuth 2.0 flows.
|
||||
|
||||
- There is no protection to ensure the client at the end of the flow is the same as the one that started it.
|
||||
- Because of this, clients using custom URI schemes as redirect URLs are vulnerable to interception by other applications.
|
||||
- The login token is passed to the client in the query parameters of the redirect URL, which can be visible to the server hosting a web-based client.
|
||||
- The homeserver has limited metadata about the client, only the redirect URL. This makes it hard to display relevant information about the client to the user during the flow.
|
||||
- There is no way for the server to return an error message to the client.
|
||||
- There is no built-in way to keep state throughout the flow, making it hard for the client to distinguish multiple concurrent flows, and potentially leaking the "login token" to the wrong homeserver.
|
||||
|
||||
### OAuth 2.0 and OpenID Connect as building blocks
|
||||
|
||||
Quoting the [specification](https://spec.matrix.org/v1.13/#introduction-to-the-matrix-apis):
|
||||
|
||||
> Matrix is a set of open APIs for open-federated Instant Messaging (IM), Voice over IP (VoIP) and Internet of Things (IoT) communication, designed to create and support a new global real-time communication ecosystem. The intention is to provide an **open decentralised pubsub layer for the internet for securely persisting and publishing/subscribing JSON objects**.
|
||||
|
||||
Fundamentally, Matrix does not set out to be an authentication protocol.
|
||||
The ecosystem needs authentication to work, but it is not core to the mission.
|
||||
|
||||
This MSC essentially proposes building on top of well-established authentication protocols, defined by OAuth 2.0 RFCs and OpenID Connect specifications.
|
||||
|
||||
[OAuth 2.0](https://oauth.net/2/) is a framework for building authorization systems, defined across multiple RFCs by the IETF.
|
||||
[OpenID Connect](https://openid.net/connect/) is an effort by the OpenID Foundation to standardize on top of OAuth 2.0.
|
||||
|
||||
This set of MSCs is an attempt to build on top of these existing specifications, defining what clients and homeservers must implement to comply with the Matrix specification.
|
||||
|
||||
### Beyond browser-based authentication
|
||||
|
||||
This MSC intentionally does not cover the use of alternative authorization flows that don't rely on a web browser, for automation or other purposes.
|
||||
This does not mean that the Matrix ecosystem should not embrace such flows, but it is rather an attempt to keep this proposal focused on making this a good default flow for most users, ensuring it is treated as a first-class citizen in the ecosystem.
|
||||
|
||||
The goal is to set a new widely-adopted base for authentication in the Matrix ecosystem, eventually replacing the current custom authentication protocol.
|
||||
Solving Matrix-specific problems with this new base could benefit the wider ecosystem of decentralized protocols, rather than staying confined to Matrix.
|
||||
|
||||
### Why not 'just use OpenID Connect'?
|
||||
|
||||
OpenID Connect does a good job at standardizing on top of OAuth 2.0, and it covers most things happening between the client and the server for authentication.
|
||||
It is a great fit for connecting identity providers to other pieces of software, and this is already what homeservers do with the [`m.login.sso`] flow.
|
||||
|
||||
Knowing that, it might seem like fully adopting OpenID Connect would facilitate the use of off-the-shelf identity providers for Matrix homeservers.
|
||||
However, in practice, OpenID Connect does not cover continuous exchanges between the application and the identity providers: there is no well-supported standard to signal new sessions, new users, session endings, user deactivation, etc., from the identity provider to the application.
|
||||
Matrix fundamentally needs those signals, as the state of devices (and, to some extent, users) is propagated to other servers through room memberships and cryptographic devices.
|
||||
Moreover, most identity providers are designed to provide service to a fixed set of applications, which does not fit the Matrix ecosystem, where users can use any number of different clients.
|
||||
|
||||
This means that backfitting Matrix-specific concepts on top of OpenID Connect would be a bad idea, especially as one important goal of this proposal is to keep the current authentication paradigm working for some time.
|
||||
|
||||
**Note**: an earlier version of this MSC focused on 'delegating' authentication to an identity provider, but it showed its limitations and added much confusion over the intent of the proposal.
|
||||
|
||||
### Keeping the ecosystem open
|
||||
|
||||
One common critique of OAuth 2.0 and OpenID Connect is that they are widely used in contexts where the service provider controls which clients are allowed to interact with the service.
|
||||
This usually implies a contractual relationship between the service provider and the client, typically through a developer program, where the client must comply with the service provider's terms of service.
|
||||
|
||||
This has been a notorious problem with [OAuth 2.0 in email protocols][thunderbird-oauth2], where email clients are forced to register their applications with each email provider, giving the email provider the right to reject any application.
|
||||
|
||||
This proposal aims to mitigate this problem by defining a way for clients to dynamically register themselves with the homeserver.
|
||||
|
||||
[thunderbird-oauth2]: https://wiki.mozilla.org/Thunderbird:Autoconfiguration:ConfigFileFormat#OAuth2
|
||||
|
||||
## Proposal
|
||||
|
||||
This proposal introduces a new set of authentication APIs for Matrix, based on OAuth 2.0 and OpenID Connect (OIDC) specifications.
|
||||
|
||||
As a first step, it introduces those APIs as alternatives to the existing authentication mechanisms -- in particular [`/_matrix/client/v3/login`] and [User-Interactive Authentication](https://spec.matrix.org/v1.13/client-server-api/#user-interactive-authentication-api) (UIA).
|
||||
It does not attempt to cover all use cases of the existing APIs at this point.
|
||||
The long-term goal is to deprecate the existing account management APIs and UIA-protected endpoints, providing alternatives where necessary.
|
||||
This deprecation is not done in this MSC.
|
||||
|
||||
While not directly part of this proposal, it paves the way for providing only partial access to the user's account.
|
||||
Therefore, the specification should begin including the scope required to access each endpoint in its description.
|
||||
|
||||
### Core authentication flow
|
||||
|
||||
To cover the most common use case of authenticating an end-user, the following MSCs are necessary:
|
||||
|
||||
- [MSC2964: Usage of OAuth 2.0 authorization code grant and refresh token grant][MSC2964] describes how the main authentication flow works
|
||||
- [MSC2965: OAuth 2.0 Authorization Server Metadata discovery][MSC2965] describes how a client can discover the authentication server metadata of the homeserver
|
||||
- [MSC2966: Usage of OAuth 2.0 Dynamic Client Registration][MSC2966] describes how a client can register itself with the homeserver to get a client identifier
|
||||
- [MSC2967: API scopes][MSC2967] defines the first set of access scopes and the basis for future access scopes
|
||||
- [MSC4254: Usage of RFC7009 Token Revocation for Matrix client logout][MSC4254] describes how a client can end a client session
|
||||
|
||||
### Adjacent proposals
|
||||
|
||||
This set of core proposals doesn't cover everything previously covered by UIA-protected APIs.
|
||||
The following proposals are meant to provide alternative APIs to fill in the gaps.
|
||||
|
||||
#### Account management
|
||||
|
||||
This moves the user-interface for some account management tasks from the client to the homeserver.
|
||||
Existing APIs like [`/_matrix/client/v3/capabilities`] help clients understand which account-management API endpoints are unavailable, but they don't offer alternatives to a homeserver-provided user-interface.
|
||||
To build this bridge between the client user-interface and the homeserver, [MSC4191: Account management deep-linking][MSC4191] proposes a way to deep-link to the account management capabilities of the homeserver.
|
||||
|
||||
#### Transition and existing client support
|
||||
|
||||
To help clients transition to the next-generation auth, this proposal is designed to offer backward-compatible APIs through the [`m.login.sso`] login flow.
|
||||
How this is intended to work and let clients offer reasonable user experience is covered by [MSC3824: OIDC-aware clients][MSC3824].
|
||||
|
||||
#### Application services
|
||||
|
||||
In the longer term, application services could leverage alternative grant types like the [OAuth 2.0 Client Credentials Grant](https://tools.ietf.org/html/rfc6749#section-4.4) to obtain access to the homeserver.
|
||||
In the meantime, homeservers should keep registration through the [`/_matrix/client/v3/register` with the `m.login.application_service` type][register-app-service] endpoint working for application services.
|
||||
[MSC4190: Device management for application services][MSC4190] proposes a simple API to create and delete devices for users managed by application services, to remove the need for keeping the [`m.login.application_service`] login type working.
|
||||
|
||||
[register-app-service]: https://spec.matrix.org/v1.13/application-service-api/#server-admin-style-permissions
|
||||
|
||||
## Sample flow
|
||||
|
||||
This section describes a sample flow, taking together the steps described in more details in the dedicated MSCs.
|
||||
**It is non-normative**, as the different parts of the flow are described in more details in their respective MSCs.
|
||||
It assumes the client already discovered the homeserver's Client-Server API endpoint.
|
||||
|
||||
[areweoidcyet.com](https://areweoidcyet.com/client-implementation-guide/) has an interactive guide on how to use this flow.
|
||||
|
||||
### Discovery [MSC2965]
|
||||
|
||||
First step is to discover the homeserver's authorization server metadata.
|
||||
This is defined by [MSC2965: OAuth 2.0 Authorization Server Metadata discovery][MSC2965] as follows:
|
||||
|
||||
```http
|
||||
GET /_matrix/client/v1/auth_metadata HTTP/1.1
|
||||
Host: matrix.example.com
|
||||
Accept: application/json
|
||||
```
|
||||
|
||||
```http
|
||||
HTTP/1.1 200 OK
|
||||
Content-Type: application/json
|
||||
Cache-Control: public, max-age=3600
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"authorization_endpoint": "https://auth.example.com/oauth2/auth",
|
||||
"token_endpoint": "https://auth.example.com/oauth2/token",
|
||||
"registration_endpoint": "https://auth.example.com/oauth2/clients/register",
|
||||
"revocation_endpoint": "https://auth.example.com/oauth2/revoke",
|
||||
"...": "some fields omitted"
|
||||
}
|
||||
```
|
||||
|
||||
The client must save this document as the "authorization server metadata".
|
||||
It must also check that it contains all the fields it will need for other parts of the flow.
|
||||
|
||||
### Client registration [MSC2966]
|
||||
|
||||
Next step is to register the client with the homeserver.
|
||||
This uses the `registration_endpoint` value from the authorization server metadata.
|
||||
This is defined by [MSC2966: Usage of OAuth 2.0 Dynamic Client Registration][MSC2966] as follows:
|
||||
|
||||
```http
|
||||
POST /oauth2/clients/register HTTP/1.1
|
||||
Content-Type: application/json
|
||||
Accept: application/json
|
||||
Server: auth.example.com
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"client_name": "My App",
|
||||
"client_uri": "https://example.com/",
|
||||
"logo_uri": "https://example.com/logo.png",
|
||||
"tos_uri": "https://example.com/tos.html",
|
||||
"policy_uri": "https://example.com/policy.html",
|
||||
"redirect_uris": ["https://app.example.com/callback"],
|
||||
"token_endpoint_auth_method": "none",
|
||||
"response_types": ["code"],
|
||||
"grant_types": ["authorization_code", "refresh_token"]
|
||||
}
|
||||
```
|
||||
|
||||
The server replies with a JSON object containing the `client_id` allocated, as well as all the metadata values that the server registered.
|
||||
|
||||
With the previous registration request, the server would reply with:
|
||||
|
||||
```http
|
||||
HTTP/1.1 200 OK
|
||||
Content-Type: application/json
|
||||
Cache-Control: no-store
|
||||
Pragma: no-cache
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"client_id": "s6BhdRkqt3",
|
||||
"client_name": "My App",
|
||||
"client_uri": "https://example.com/",
|
||||
"logo_uri": "https://example.com/logo.png",
|
||||
"tos_uri": "https://example.com/tos.html",
|
||||
"policy_uri": "https://example.com/policy.html",
|
||||
"redirect_uris": ["https://app.example.com/callback"],
|
||||
"response_types": ["code"],
|
||||
"grant_types": ["authorization_code", "refresh_token"],
|
||||
"application_type": "web"
|
||||
}
|
||||
```
|
||||
|
||||
The client must store the `client_id` for later use.
|
||||
|
||||
### Authorization request [MSC2964]
|
||||
|
||||
The client is ready to start an authorization request.
|
||||
It needs to determine a few other values:
|
||||
|
||||
- `state`: a usually random string that will be used to associate the response with the authorization request
|
||||
- `code_verifier`: a random string with enough entropy which will be used to ensure the client is the one that initiated the request
|
||||
- The Matrix device ID the client wants to use/create
|
||||
|
||||
In this example, we've picked:
|
||||
|
||||
- `state` to be `To29j0DdKUcc75Rt`
|
||||
- `code_verifier` to be `NXt2S0jiptl4q0m8OYVJFFyuDB5i5aeJSOUJ4NpdmTv`
|
||||
- The device ID to be `EIKO9QUIAL`
|
||||
|
||||
This will help create the authorization request URL, with the following parameters:
|
||||
|
||||
- `response_mode` set to `fragment` for a client-side web client
|
||||
- `response_type` set to `code`
|
||||
- `client_id` got from the registration request above, in this example `s6BhdRkqt3`
|
||||
- `code_challenge_method` set to `S256`
|
||||
- `code_challenge` derived from the `code_verifier` using the `S256` method. In this example, it is `8coMp56MvhmfFtjk0dYd9H9d3jQRV1qjS703hAOVnEk`
|
||||
- `scope`: as defined by [MSC2967]
|
||||
- For full access, it needs to contain:
|
||||
- `urn:matrix:client:api:*`
|
||||
- `urn:matrix:device:XXYYZZ`, where `XXYYZZ` is the device ID
|
||||
- Our example is then using `urn:matrix:client:api:* urn:matrix:device:EIKO9QUIAL`
|
||||
- `redirect_uri`: the client's redirect URI registered. In our example, it is `https://app.example.com/callback`
|
||||
|
||||
Building the full URL gives:
|
||||
|
||||
```
|
||||
https://auth.example.com/oauth2/auth?response_mode=fragment&response_type=code&client_id=s6BhdRkqt3&code_challenge_method=S256&code_challenge=8coMp56MvhmfFtjk0dYd9H9d3jQRV1qjS703hAOVnEk&scope=urn:matrix:client:api:%20urn:matrix:device:EIKO9QUIAL&redirect_uri=https%3A%2F%2Fapp.example.com%2Fcallback&state=To29j0DdKUcc75Rt
|
||||
```
|
||||
|
||||
The client then redirects the user to this URL.
|
||||
|
||||
### Authorization response [MSC2964]
|
||||
|
||||
At the end of the authorization flow, the user is redirected back to the client, with a `code` parameter in the URL fragment, as well as the `state` parameter.
|
||||
|
||||
```
|
||||
https://app.example.com/callback#code=To29j0DdKUcc75Rt&state=To29j0DdKUcc75Rt
|
||||
```
|
||||
|
||||
The client must now exchange the `code` for an access token.
|
||||
|
||||
This is defined by [MSC2964: Usage of OAuth 2.0 authorization code grant and refresh token grant][MSC2964] as follows:
|
||||
|
||||
```http
|
||||
POST /oauth2/token HTTP/1.1
|
||||
Content-Type: application/x-www-form-urlencoded
|
||||
Accept: application/json
|
||||
Server: auth.example.com
|
||||
|
||||
grant_type=authorization_code&code=To29j0DdKUcc75Rt&redirect_uri=https%3A%2F%2Fapp.example.com%2Fcallback&code_verifier=NXt2S0jiptl4q0m8OYVJFFyuDB5i5aeJSOUJ4NpdmTv
|
||||
```
|
||||
|
||||
```http
|
||||
HTTP/1.1 200 OK
|
||||
Content-Type: application/json
|
||||
Cache-Control: no-store
|
||||
Pragma: no-cache
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"access_token": "mat_ooreiPhei2wequu9fohkai3AeBaec9oo",
|
||||
"refresh_token": "mar_Pieyiev3aenahm4atah7aip3eiveizah",
|
||||
"expires_in": 300,
|
||||
"token_type": "Bearer"
|
||||
}
|
||||
```
|
||||
|
||||
The client can now use the access token to make authenticated requests to the homeserver.
|
||||
It will expire after `expires_in` seconds, after which it must be refreshed, using the refresh token.
|
||||
|
||||
```http
|
||||
POST /oauth2/token HTTP/1.1
|
||||
Content-Type: application/x-www-form-urlencoded
|
||||
Accept: application/json
|
||||
Server: auth.example.com
|
||||
|
||||
grant_type=refresh_token&refresh_token=mar_Pieyiev3aenahm4atah7aip3eiveizah
|
||||
```
|
||||
|
||||
```http
|
||||
HTTP/1.1 200 OK
|
||||
Content-Type: application/json
|
||||
Cache-Control: no-store
|
||||
Pragma: no-cache
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"access_token": "mat_ohb2Chei5Ne5yoghohs8voochei1laep",
|
||||
"refresh_token": "mar_eequee6zahsee1quieta8oopoopeeThu",
|
||||
"expires_in": 300,
|
||||
"token_type": "Bearer"
|
||||
}
|
||||
```
|
||||
|
||||
### Token revocation [MSC4254]
|
||||
|
||||
To end a client session, the client must revoke the access token.
|
||||
This is defined by [MSC4254: Usage of RFC7009 Token Revocation for Matrix client logout][MSC4254] as follows:
|
||||
|
||||
```http
|
||||
POST /oauth2/revoke HTTP/1.1
|
||||
Content-Type: application/x-www-form-urlencoded
|
||||
Accept: application/json
|
||||
Server: auth.example.com
|
||||
|
||||
token=mat_ohb2Chei5Ne5yoghohs8voochei1laep&token_type_hint=access_token&client_id=s6BhdRkqt3
|
||||
```
|
||||
|
||||
```http
|
||||
HTTP/1.1 200 OK
|
||||
```
|
||||
|
||||
Both the access token and the refresh token are revoked, and the associated device ID is deleted on the homeserver.
|
||||
|
||||
## Potential issues
|
||||
|
||||
Each individual proposal has its own potential issues section.
|
||||
This section only covers the potential issues that are common to the proposal as a whole.
|
||||
|
||||
### User and ecosystem migration
|
||||
|
||||
This proposal fundamentally changes the way users and ecosystems interact with their accounts on their homeservers.
|
||||
Users might be used to entering their credentials within their client, which means that migrating to this proposal will introduce a new web-based login flow that will be different from what users are used to.
|
||||
|
||||
In the long term, this is beneficial for the ecosystem, as it helps users familiarize themselves with the distinction between their homeserver and their client.
|
||||
Where clients and servers are in a managed environment, branding between the flows can unify the user experience, similar to how many corporate email accounts work.
|
||||
|
||||
This proposal is not yet proposing to deprecate the existing APIs, in an effort to avoid breaking existing clients as much as possible.
|
||||
This adds complexity for homeserver implementers if they want to support both the old and new APIs.
|
||||
|
||||
### Reliance on the system browser
|
||||
|
||||
The main authentication flow of this proposal is a web-based flow that is intended to run in the context of a system browser.
|
||||
There are alternative flows which could help support login on devices where a browser is not available, or for automation purposes.
|
||||
These flows are best implemented through future MSCs.
|
||||
|
||||
Additionally, in some contexts, the system browser can be a security risk, as it has a wide attack surface inherent to its complexity.
|
||||
This can be mitigated to some extent by having homeservers implement authorization flows that don't require JavaScript, but this doesn't completely eliminate the risk.
|
||||
|
||||
### Homeserver implementation complexity
|
||||
|
||||
In practice, to provide a good user experience, homeservers have to implement web views for the authentication flows, which is complex to implement well.
|
||||
This means having proper accessibility, translations, and UX.
|
||||
Those concerns were previously mainly affecting client implementations, and will now also affect homeserver implementations.
|
||||
|
||||
On the other hand, the previous registration flow was notoriously complex to implement both for clients and homeservers, and this proposal removes a lot of that complexity from the client side.
|
||||
|
||||
Moreover, these concerns should, in theory, already apply to the homeserver-side implementation, as the homeserver is supposed to provide a [web-based fallback](https://spec.matrix.org/v1.13/client-server-api/#login-fallback) for the `/login` API, as well as [fallbacks](https://spec.matrix.org/v1.11/client-server-api/#fallback) for all UIA steps.
|
||||
In practice, this is often not the case, with either missing fallbacks for some UIA steps or sub-par user experiences in their implementations.
|
||||
|
||||
## Alternatives
|
||||
|
||||
The primary alternative is to continue to build out the auth capabilities within the Client-Server API.
|
||||
|
||||
For example, UIA (User-Interactive Auth) could be added to the [`/_matrix/client/v3/login`] endpoint and additional capabilities/flows added to UIA.
|
||||
|
||||
Examples of existing proposals include:
|
||||
|
||||
| Proposals | Comments |
|
||||
| ------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| [MSC1998: Two-Factor Authentication Providers][MSC1998]<br>[MSC2271: TOTP 2FA login][MSC2271] | Homeservers are free to implement the authentication flows they want. The [Matrix OIDC Playground](https://github.com/vector-im/oidc-playground) contains a Keycloak configured to demonstrate this |
|
||||
| [MSC2000: Server-side password policies][MSC2000] | Because the UI is served by the homeserver, it is free to implement whatever password policies it sees fit |
|
||||
| [MSC3105: Previewing UIA flows][MSC3105]<br>[MSC3741: Revealing the useful login flows to clients after a soft logout][MSC3741] | These become unnecessary as the burden to implement auth flows is moved away from the client to the homeserver |
|
||||
| [MSC3262: aPAKE authentication][MSC3262]<br>[MSC2957: Cryptographically Concealed Credentials][MSC2957] | This is an interesting one as OAuth 2.0 explicitly discourages a user from trusting their client with credentials. As such there is no existing flow for PAKEs. To achieve this, you would need to implement a custom grant in the Client and homeserver (perhaps an extension of the Resource Owner Password Credentials flow). |
|
||||
| [MSC3782: Matrix public key login spec][MSC3782] | Similar to above |
|
||||
| [MSC3744: Support for flexible authentication][MSC3744] | This proposal would instead be used as the pluggable layer for auth in Matrix |
|
||||
|
||||
## History
|
||||
|
||||
This proposal was originally known as 'OIDC-native' authentication.
|
||||
To avoid the confusion with OIDC as a single sign-on/identity protocol, this proposal removed its dependency on OpenID Connect and was renamed to 'next-generation auth'.
|
||||
|
||||
## Security considerations
|
||||
|
||||
Please refer to individual proposals.
|
||||
|
||||
## Unstable prefix
|
||||
|
||||
Please refer to individual proposals.
|
||||
|
||||
## Dependencies
|
||||
|
||||
The following MSCs map the aforementioned OAuth 2.0/OIDC requirements to Matrix APIs:
|
||||
|
||||
- [MSC2964: Usage of OAuth 2.0 authorization code grant and refresh token grant][MSC2964]
|
||||
- [MSC2965: OAuth 2.0 Authorization Server Metadata discovery][MSC2965]
|
||||
- [MSC2966: Usage of OAuth 2.0 Dynamic Client Registration][MSC2966]
|
||||
- [MSC2967: API scopes][MSC2967]
|
||||
- [MSC4254: Usage of RFC7009 Token Revocation for Matrix client logout][MSC4254]
|
||||
|
||||
The following MSCs are meant to cover less essential parts of the authentication and account management flows.
|
||||
They are not strictly required for this proposal to be accepted, but should be considered shortly afterwards:
|
||||
|
||||
- [MSC3824: OIDC-aware clients][MSC3824]
|
||||
- [MSC4190: Device management for application services][MSC4190]
|
||||
- [MSC4191: Account management deep-linking][MSC4191]
|
||||
- [MSC4198: Usage of OIDC login_hint][MSC4198]
|
||||
|
||||
The following MSCs were prerequisites for implementing this proposal in a sane way, and were accepted in the meantime:
|
||||
|
||||
- [MSC3970: Scope transaction IDs to devices][MSC3970]
|
||||
- [MSC3967: Do not require UIA when first uploading cross signing keys][MSC3967]
|
||||
|
||||
[MSC1998]: https://github.com/matrix-org/matrix-spec-proposals/pull/1998
|
||||
[MSC2000]: https://github.com/matrix-org/matrix-spec-proposals/pull/2000
|
||||
[MSC2271]: https://github.com/matrix-org/matrix-spec-proposals/pull/2271
|
||||
[MSC2957]: https://github.com/matrix-org/matrix-spec-proposals/pull/2957
|
||||
[MSC2964]: https://github.com/matrix-org/matrix-spec-proposals/pull/2964
|
||||
[MSC2965]: https://github.com/matrix-org/matrix-spec-proposals/pull/2965
|
||||
[MSC2966]: https://github.com/matrix-org/matrix-spec-proposals/pull/2966
|
||||
[MSC2967]: https://github.com/matrix-org/matrix-spec-proposals/pull/2967
|
||||
[MSC3105]: https://github.com/matrix-org/matrix-spec-proposals/pull/3105
|
||||
[MSC3262]: https://github.com/matrix-org/matrix-spec-proposals/pull/3262
|
||||
[MSC3741]: https://github.com/matrix-org/matrix-spec-proposals/pull/3741
|
||||
[MSC3744]: https://github.com/matrix-org/matrix-spec-proposals/pull/3744
|
||||
[MSC3782]: https://github.com/matrix-org/matrix-spec-proposals/pull/3782
|
||||
[MSC3824]: https://github.com/matrix-org/matrix-spec-proposals/pull/3824
|
||||
[MSC3967]: https://github.com/matrix-org/matrix-spec-proposals/pull/3967
|
||||
[MSC3970]: https://github.com/matrix-org/matrix-spec-proposals/pull/3970
|
||||
[MSC4190]: https://github.com/matrix-org/matrix-spec-proposals/pull/4190
|
||||
[MSC4191]: https://github.com/matrix-org/matrix-spec-proposals/pull/4191
|
||||
[MSC4198]: https://github.com/matrix-org/matrix-spec-proposals/pull/4198
|
||||
[MSC4254]: https://github.com/matrix-org/matrix-spec-proposals/pull/4254
|
||||
[`m.login.application_service`]: https://spec.matrix.org/v1.13/client-server-api/#appservice-login
|
||||
[`m.login.sso`]: https://spec.matrix.org/v1.13/client-server-api/#sso-client-loginauthentication
|
||||
[`/_matrix/client/v3/capabilities`]: https://spec.matrix.org/v1.13/client-server-api/#get_matrixclientv3capabilities
|
||||
[`/_matrix/client/v3/login`]: https://spec.matrix.org/v1.13/client-server-api/#post_matrixclientv3login
|
||||
@ -0,0 +1,412 @@
|
||||
# MSC3916: Authentication for media access, and new endpoint names
|
||||
|
||||
Currently, access to media in Matrix has a number of problems including the following:
|
||||
|
||||
* The only protection for media is the obscurity of the URL, and URLs are
|
||||
easily leaked (eg accidental sharing, access
|
||||
logs). [synapse#2150](https://github.com/matrix-org/synapse/issues/2150)
|
||||
* Anybody (including non-matrix users) can cause a homeserver to copy media
|
||||
into its local
|
||||
store. [synapse#2133](https://github.com/matrix-org/synapse/issues/2133)
|
||||
* When a media event is redacted, the media it used remains visible to all.
|
||||
[synapse#1263](https://github.com/matrix-org/synapse/issues/1263)
|
||||
* There is currently no way to delete
|
||||
media. [matrix-spec#226](https://github.com/matrix-org/matrix-spec/issues/226)
|
||||
* If a user requests GDPR erasure, their media remains visible to all.
|
||||
* When all users leave a room, their media is not deleted from the server.
|
||||
|
||||
These problems are all difficult to address currently, because access to media
|
||||
is entirely unauthenticated. The first step for a solution is to require user
|
||||
authentication. Once that is done, it will be possible to impose authorization
|
||||
requirements to address the problems mentioned above. (See, for example,
|
||||
[MSC3911](https://github.com/matrix-org/matrix-spec-proposals/pull/3911) which
|
||||
builds on top of this MSC.)
|
||||
|
||||
This proposal supersedes [MSC1902](https://github.com/matrix-org/matrix-spec-proposals/pull/1902).
|
||||
|
||||
## Proposal
|
||||
|
||||
1. New endpoints
|
||||
|
||||
The existing `/_matrix/media/v3/` endpoints become deprecated, and new
|
||||
endpoints under the `/_matrix/client` and `/_matrix/federation`
|
||||
hierarchies are introduced. Removal of the deprecated endpoints would be a
|
||||
later MSC under [the deprecation policy](https://spec.matrix.org/v1.10/#deprecation-policy).
|
||||
|
||||
The following table below shows a mapping between deprecated and new endpoint:
|
||||
|
||||
| Deprecated | Client-Server | Federation |
|
||||
| ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------- | ------------------------------------------------------------------- |
|
||||
| [`GET /_matrix/media/v3/preview_url`](https://spec.matrix.org/v1.6/client-server-api/#get_matrixmediav3preview_url) | `GET /_matrix/client/v1/media/preview_url` | - |
|
||||
| [`GET /_matrix/media/v3/config`](https://spec.matrix.org/v1.6/client-server-api/#get_matrixmediav3config) | `GET /_matrix/client/v1/media/config` | - |
|
||||
| [`GET /_matrix/media/v3/download/{serverName}/{mediaId}`](https://spec.matrix.org/v1.6/client-server-api/#get_matrixmediav3downloadservernamemediaid) | `GET /_matrix/client/v1/media/download/{serverName}/{mediaId}` | `GET /_matrix/federation/v1/media/download/{mediaId}` |
|
||||
| [`GET /_matrix/media/v3/download/{serverName}/{mediaId}/{fileName}`](https://spec.matrix.org/v1.6/client-server-api/#get_matrixmediav3downloadservernamemediaidfilename) | `GET /_matrix/client/v1/media/download/{serverName}/{mediaId}/{fileName}` | - |
|
||||
| [`GET /_matrix/media/v3/thumbnail/{serverName}/{mediaId}`](https://spec.matrix.org/v1.6/client-server-api/#get_matrixmediav3thumbnailservernamemediaid) | `GET /_matrix/client/v1/media/thumbnail/{serverName}/{mediaId}` | `GET /_matrix/federation/v1/media/thumbnail/{mediaId}` |
|
||||
|
||||
**Note**: [`POST /_matrix/media/v3/upload`](https://spec.matrix.org/v1.6/client-server-api/#post_matrixmediav3upload)
|
||||
and [`POST /_matrix/media/v1/create`](https://spec.matrix.org/v1.10/client-server-api/#post_matrixmediav1create)
|
||||
are **not** modified or deprecated by this MSC: it is intended that they be brought into line with the other
|
||||
endpoints by a future MSC, such as [MSC3911](https://github.com/matrix-org/matrix-spec-proposals/pull/3911).
|
||||
|
||||
2. Removal of `allow_remote` parameter from `/download` and `/thumbnail`
|
||||
|
||||
The current
|
||||
[`/download`](https://spec.matrix.org/v1.6/client-server-api/#get_matrixmediav3downloadservernamemediaid)
|
||||
and
|
||||
[`/thumbnail`](https://spec.matrix.org/v1.6/client-server-api/#get_matrixmediav3thumbnailservernamemediaid)
|
||||
endpoints take an `allow_remote` query parameter, indicating whether the
|
||||
server should request remote media from other servers. This is redundant
|
||||
with the new endpoints, so will not be supported.
|
||||
|
||||
Servers MUST NOT return remote media from `GET /_matrix/federation/v1/media/download` or
|
||||
`GET /_matrix/federation/v1/media/thumbnail`. The `serverName` is omitted from
|
||||
the endpoint's path to strongly enforce this - the `mediaId` in a request is
|
||||
assumed to be scoped to the target server.
|
||||
|
||||
`/_matrix/client/v1/media/download` and
|
||||
`/_matrix/client/v1/media/thumbnail` return remote media as normal.
|
||||
|
||||
3. Authentication on all endpoints
|
||||
|
||||
Currently, the `/download` and `/thumbnail` endpoints have no authentication
|
||||
requirements. Under this proposal, the new endpoints will be authenticated
|
||||
the same way as other endpoints: they will require an `Authorization` header
|
||||
which must be `Bearer {accessToken}` for `/_matrix/client`, or the signature
|
||||
for `/_matrix/federation`.
|
||||
|
||||
Clients SHOULD NOT use the [deprecated](https://github.com/matrix-org/matrix-spec-proposals/blob/main/proposals/4126-deprecate-query-string-auth.md)
|
||||
`?access_token` query string authentication mechanism. The method is [pending removal](https://github.com/matrix-org/matrix-spec-proposals/pull/4127)
|
||||
and is generally unsafe. See those MSCs for further details.
|
||||
|
||||
**Note**: This fixes [matrix-spec#313](https://github.com/matrix-org/matrix-spec/issues/313).
|
||||
|
||||
4. Updated response format
|
||||
|
||||
* For the new `/_matrix/client` endpoints, the response format is the same as
|
||||
the corresponding original endpoints.
|
||||
|
||||
* To enable future expansion, for the new `/_matrix/federation` endpoints,
|
||||
the response is
|
||||
[`multipart/mixed`](https://www.w3.org/Protocols/rfc1341/7_2_Multipart.html)
|
||||
content with exactly two parts: the first MUST be a JSON object (and should have a
|
||||
`Content-type: application/json` header), and the second MUST be the media item.
|
||||
The media item may be served inline, as shown in the first example below, or
|
||||
be a pointer to a URL containing the media item's bytes instead, represented
|
||||
by the `Location` header described further below.
|
||||
|
||||
No properties are yet specified for the JSON object to be returned. One
|
||||
possible use is described by [MSC3911](https://github.com/matrix-org/matrix-spec-proposals/pull/3911).
|
||||
|
||||
An example response:
|
||||
|
||||
```
|
||||
Content-Type: multipart/mixed; boundary=gc0p4Jq0M2Yt08jU534c0p
|
||||
|
||||
--gc0p4Jq0M2Yt08jU534c0p
|
||||
Content-Type: application/json
|
||||
|
||||
{}
|
||||
|
||||
--gc0p4Jq0M2Yt08jU534c0p
|
||||
Content-Type: text/plain
|
||||
|
||||
This media is plain text. Maybe somebody used it as a paste bin.
|
||||
|
||||
--gc0p4Jq0M2Yt08jU534c0p
|
||||
```
|
||||
|
||||
The second part (media item bytes) MAY include a [`Location` header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Location)
|
||||
to point to the raw media object instead of having bytes itself. Servers
|
||||
SHOULD NOT cache the `Location` header's value as the responding server may
|
||||
have applied time limits on its validity. Servers which don't immediately
|
||||
download the media from the provided URL should re-request the media and
|
||||
metadata from the `/download` endpoint when ready for the media bytes.
|
||||
|
||||
The `Location` header's URL does *not* require authentication, as it will
|
||||
typically be served by a CDN or other non-matrix server (thus being unable
|
||||
to verify any `X-Matrix` signatures, for example).
|
||||
|
||||
Note that all other headers besides `Location` for the media item part are
|
||||
ignored when `Location` is present. The `Content-Type`, `Content-Disposition`,
|
||||
etc headers will be served from the `Location`'s URL instead. Similarly,
|
||||
the body for the media item part is ignored and SHOULD be empty.
|
||||
|
||||
An example response with a `Location` redirect would be:
|
||||
|
||||
```
|
||||
Content-Type: multipart/mixed; boundary=gc0p4Jq0M2Yt08jU534c0p
|
||||
|
||||
--gc0p4Jq0M2Yt08jU534c0p
|
||||
Content-Type: application/json
|
||||
|
||||
{}
|
||||
|
||||
--gc0p4Jq0M2Yt08jU534c0p
|
||||
Location: https://cdn.example.org/ab/c1/2345.txt
|
||||
|
||||
--gc0p4Jq0M2Yt08jU534c0p
|
||||
```
|
||||
|
||||
If the server were to `curl https://cdn.example.org/ab/c1/2345.txt`, it'd
|
||||
get something similar to the following:
|
||||
|
||||
```
|
||||
Content-Type: text/plain
|
||||
|
||||
This media is plain text. Maybe somebody used it as a paste bin.
|
||||
```
|
||||
|
||||
**Note**: For clarity, the above applies to the federation `/thumbnail` endpoint
|
||||
as well as `/download`.
|
||||
|
||||
5. Backwards compatibility mechanisms
|
||||
|
||||
Servers SHOULD *stop* serving new media as unauthenticated within 1 spec release
|
||||
of this proposal being released itself using a standard `404 M_NOT_FOUND` response.
|
||||
Existing media should continue to be served from the unauthenticated endpoints
|
||||
indefinitely for backwards compatibility. For example, if this proposal is
|
||||
released in Matrix 1.11, then by Matrix 1.12 servers should freeze the old
|
||||
unauthenticated endpoints by only serving media known to exist from before the
|
||||
freeze.
|
||||
|
||||
"New media" is any media which local users upload after the freeze is put in
|
||||
place, and any remote media which becomes cached after the freeze as well. This
|
||||
could be marked by a configuration option within the server software, or as part
|
||||
of a scheduled/dedicated release which enacts the freeze for everyone who updates
|
||||
to that version.
|
||||
|
||||
This freeze schedule will have some undesirable side effects, particularly for
|
||||
clients and servers which are slow to update or support the new endpoints. Newly
|
||||
uploaded images, files, avatars, etc may appear "broken" or missing to users on
|
||||
older software. Existing media should continue to work, however, reducing the
|
||||
impact from 100% of media to a smaller percentage.
|
||||
|
||||
Servers SHOULD consider whether their users' typical clients will break as
|
||||
part of the freeze before enacting the freeze. Clients SHOULD update as soon
|
||||
as reasonably possible to support authenticated media, particularly following
|
||||
the spec release containing this MSC. Other considerations may include bridges,
|
||||
deployment-specific use cases, and patch availability.
|
||||
|
||||
It is worth noting that the matrix.org homeserver plans to freeze media relatively
|
||||
quickly following this proposal's release in the specification. Details will be
|
||||
published to the matrix.org blog closer to the spec release date.
|
||||
|
||||
The following are specific backwards compatibility cases:
|
||||
|
||||
a. New clients & servers with older servers: The [`M_UNRECOGNIZED`](https://spec.matrix.org/v1.10/client-server-api/#common-error-codes)
|
||||
error behaviour should be followed to indicate that the server does not
|
||||
support the new endpoints, particularly when partnered with a 404 HTTP status
|
||||
code. Clients and servers should use the unauthenticated endpoints in this
|
||||
case. The endpoints will not be frozen by the server, so should work for
|
||||
'new' media.
|
||||
|
||||
b. Older clients & servers with newer servers: Mentioned above, servers are
|
||||
strongly encouraged to freeze unauthenticated media access within a relatively
|
||||
quick timeframe. Though media before the freeze should remain accessible,
|
||||
clients and older federating servers may still see errors when accessing
|
||||
new media, leading to client UI feeling "broken" or missing avatars. The
|
||||
various considerations above are meant to reduce the impact of this case.
|
||||
|
||||
6. Removal of `allow_redirect` parameter from `/download` and `/thumbnail`
|
||||
|
||||
Clients MUST expect a 307 or 308 redirect when calling the new `/download`
|
||||
and `/thumbnail` Client-Server API endpoints.
|
||||
|
||||
Servers MUST expect the `Location` header in the media part of the new Server-Server
|
||||
API `/download` and `/thumbnail` endpoints. Servers MUST NOT respond with a 307 or 308 redirect at
|
||||
the top level for the endpoint - they can only redirect within the media part
|
||||
itself.
|
||||
|
||||
See [this comment on MSC3860](https://github.com/matrix-org/matrix-spec-proposals/pull/3860/files#r1005176480)
|
||||
for further context on this change.
|
||||
|
||||
### Effects on client applications
|
||||
|
||||
Naturally, implementations will be required to provide `Authorization` headers
|
||||
when accessing the new endpoints. This will be simple in some cases, but rather
|
||||
more involved in others. This section considers some of those cases.
|
||||
|
||||
#### IRC/XMPP bridges
|
||||
|
||||
Possibly the largest impact will be on IRC and XMPP bridges. Since IRC and
|
||||
XMPP have no media repository of their own, these bridges currently transform
|
||||
`mxc:` URIs into `https://<server>/_matrix/media/v3/download/` URIs and forward
|
||||
those links to the remote platform. This will no longer be a viable option.
|
||||
|
||||
One potential solution is for the bridges to provide a proxy.
|
||||
|
||||
In this scenario, the bridge would have a secret HMAC key. When it
|
||||
receives a matrix event referencing a piece of media, it should create a new URI
|
||||
referencing the media, include an HMAC to prevent tampering. For example:
|
||||
|
||||
```
|
||||
https://<bridge_server>/media/{originServerName}/{mediaId}?mac={hmac}
|
||||
```
|
||||
|
||||
When the bridge later receives a request to that URI, it checks the hmac,
|
||||
and proxies the request to the homeserver, using its AS access
|
||||
token in the `Authorization` header.
|
||||
|
||||
The bridge might also choose to embed information such as the room that
|
||||
referenced the media, and the time that the link was generated, in the URL.
|
||||
Such mechanisms would allow the bridge to impose controls such as:
|
||||
|
||||
* Limiting the time a media link is valid for. Doing so would help prevent
|
||||
visibility to users who weren't participating in the chat.
|
||||
|
||||
* Rate-limiting the amount of media being shared in a particular room (in other
|
||||
words, avoiding the use of Matrix as a Warez distribution system).
|
||||
|
||||
#### Icons for "social login" flows
|
||||
|
||||
When a server supports multiple login providers, it provides the client with
|
||||
icons for the login providers as `mxc:` media URIs. These must be accessible
|
||||
without authentication (because the client has no access token at the time the
|
||||
icons are displayed).
|
||||
|
||||
Servers MAY flag the media as exceptions to the freeze described in part 5 of
|
||||
this proposal ("Backwards compatibility mechanisms"). Clients SHOULD continue to
|
||||
use the unauthenticated media download/thumbnail endpoints to access these icons
|
||||
until a future MSC can improve the situation.
|
||||
|
||||
The proposal author expects that the spec's transition to OIDC will ultimately
|
||||
replace this mechanism, or that an MSC could be opened to allow HTTP(S) URLs in
|
||||
place of `mxc:` URIs.
|
||||
|
||||
(This was previously discussed in
|
||||
[MSC2858](https://github.com/matrix-org/matrix-spec-proposals/pull/2858#discussion_r543513811).)
|
||||
|
||||
## Potential issues
|
||||
|
||||
* Setting the `Authorization` header is particularly annoying for web clients.
|
||||
Service workers are seemingly the best option, though other options include
|
||||
locally-cached `blob:` URIs. Clients should note that caching media can lead
|
||||
to significant memory usage, particularly for large media. Service workers by
|
||||
comparison allow for proxy-like behaviour.
|
||||
|
||||
Cookies are a plausible mechanism for sharing session information between
|
||||
requests without having to set headers, though would be a relatively bespoke
|
||||
authentication method for Matrix. Additionally, many Matrix users have cookies
|
||||
disabled due to the advertising and tracking use cases common across the web.
|
||||
|
||||
* Users will be unable to copy links to media from web clients to share out of
|
||||
band. This is considered a feature, not a bug.
|
||||
|
||||
* Over federation, the use of the `Range` request header on the federation endpoints becomes
|
||||
unclear as it could affect either or both parts of the response. There does not
|
||||
appear to be formal guidance in [RFC 9110](https://www.rfc-editor.org/rfc/rfc9110#field.range)
|
||||
either. There are arguments for affecting both and either part equally. Typically,
|
||||
such a header would be used to resume failed downloads, though servers are
|
||||
already likely to discard received data and fail the associated client requests
|
||||
when the federation request fails. Therefore, servers are unlikely to use `Range`
|
||||
at all. As such, this proposal does not make a determination on how `Range`
|
||||
should be handled, and leaves it as an HTTP specification interpretation problem
|
||||
instead.
|
||||
|
||||
* The `Location` header support on the new federation endpoints could add a bit
|
||||
of complexity to servers, though given the alternative of supporting CDNs and
|
||||
similar is to place complexity into "edge workers" to mutate the response value.
|
||||
Though the Matrix spec would be "simpler", the edge worker setup would be
|
||||
fragmented where we have an opportunity for a common standard.
|
||||
|
||||
## Alternatives
|
||||
|
||||
* Allow clients to upload media which does not require authentication (for
|
||||
example via a `public=true` query parameter). This might be particularly
|
||||
useful for IRC/XMPP bridges, which could upload any media they encounter to
|
||||
the homeserver's repository.
|
||||
|
||||
The danger with this is that is that there's little stopping clients
|
||||
continuing to upload media as "public", negating all of the benefits in this
|
||||
MSC. It might be ok if media upload it was restricted to certain privileged
|
||||
users, or applied after the fact by a server administrator.
|
||||
|
||||
* We could simply require that `Authorization` headers be given when calling
|
||||
the existing endpoints. However, doing so would make it harder to evaluate
|
||||
the proportion of clients which have been updated, and it is a good
|
||||
opportunity to bring these endpoints into line with the rest of the
|
||||
client-server and federation APIs.
|
||||
|
||||
* There's no real need to rename `GET /_matrix/media/v3/preview_url` and `GET
|
||||
/_matrix/media/v3/config` at present, and we could just leave them in
|
||||
place. However, changing them at the same time makes the API more consistent.
|
||||
|
||||
Conversely, we should make sure to rename `POST /_matrix/media/v3/upload`
|
||||
and `GET /_matrix/media/v3/create`. The reason to
|
||||
delay doing so is because MSC3911 will make more substantial changes to these
|
||||
endpoints, requiring another rename, and it is expected that both proposals
|
||||
will be merged near to the same time as each other (so a double rename will
|
||||
be confusing and unnecessary). However, if MSC3911 is delayed or rejected, we
|
||||
should reconsider this.
|
||||
|
||||
* Rather than messing with multipart content, have a separate endpoint for
|
||||
servers to get the metadata for a media item. That would mean two requests,
|
||||
but might make more sense than the federation endpoints providing the info directly.
|
||||
|
||||
This is a plausible approach with no significant upsides or downsides when
|
||||
compared to multipart responses.
|
||||
|
||||
Similarly, custom headers could be used to carry the metadata on the response,
|
||||
though again, there are no significant upsides or downsides to doing so.
|
||||
|
||||
Readers may wish to refer to [this thread](https://github.com/matrix-org/matrix-spec-proposals/pull/3916/files#r1586878787)
|
||||
on the MSC which covers the majority of the pros and cons for all 3 approaches.
|
||||
|
||||
### Compared to MSC3796 (MSC701)
|
||||
|
||||
[MSC701/3796](https://github.com/matrix-org/matrix-spec-proposals/issues/3796)
|
||||
introduces a concept of "content tokens" which have authentication tie-in to
|
||||
prevent anonymous users from accessing media. This is a similar problem space
|
||||
to this proposal, though deals more in the event-to-media linking space instead.
|
||||
Although the MSC is an early sketch, it's unclear if the problems noted on the
|
||||
MSC itself are feasibly resolvable.
|
||||
|
||||
### Compared to MSC2461
|
||||
|
||||
[MSC2461](https://github.com/matrix-org/matrix-spec-proposals/pull/2461) adds
|
||||
authentication to the existing media endpoints, which as noted here in the
|
||||
Alternatives is not likely to roll out quickly and leaves an inconsistency in
|
||||
the spec. MSC2461 also introduces a client-visible flag for which kinds of media
|
||||
may require authentication, making it similar to the alternative listed above
|
||||
where on the federation side we could have two endpoints: one for information
|
||||
and one for the media itself. MSC2461 simply makes the information client-visible
|
||||
instead of server-visible.
|
||||
|
||||
## Unstable prefix
|
||||
|
||||
While this proposal is in development, the new endpoints should be named as follows:
|
||||
|
||||
* `GET /_matrix/client/unstable/org.matrix.msc3916/media/preview_url`
|
||||
* `GET /_matrix/client/unstable/org.matrix.msc3916/media/config`
|
||||
* `GET /_matrix/client/unstable/org.matrix.msc3916/media/download/{serverName}/{mediaId}`
|
||||
* `GET /_matrix/client/unstable/org.matrix.msc3916/media/download/{serverName}/{mediaId}/{fileName}`
|
||||
* `GET /_matrix/client/unstable/org.matrix.msc3916/media/thumbnail/{serverName}/{mediaId}`
|
||||
* `GET /_matrix/federation/unstable/org.matrix.msc3916.v2/media/download/{mediaId}`
|
||||
* **Note**: This endpoint has a `.v2` in its unstable identifier due to the MSC changing after
|
||||
initial implementation. The original unstable endpoint has a `serverName` and may still be
|
||||
supported by some servers: `GET /_matrix/federation/unstable/org.matrix.msc3916/media/download/{serverName}/{mediaId}`
|
||||
|
||||
The `serverName` was later dropped in favour of explicit scoping. See `allow_remote` details
|
||||
in the MSC body for details.
|
||||
* `GET /_matrix/federation/unstable/org.matrix.msc3916.v2/media/thumbnail/{mediaId}`
|
||||
* **Note**: This endpoint has a `.v2` in its unstable identifier due to the MSC changing after
|
||||
initial implementation. The original unstable endpoint has a `serverName` and may still be
|
||||
supported by some servers: `GET /_matrix/federation/unstable/org.matrix.msc3916/media/thumbnail/{serverName}/{mediaId}`
|
||||
|
||||
The `serverName` was later dropped in favour of explicit scoping. See `allow_remote` details
|
||||
in the MSC body for details.
|
||||
|
||||
## Stable flag
|
||||
|
||||
After the proposal is accepted servers may advertise support for the stable
|
||||
endpoints by setting `org.matrix.msc3916.stable` to `true` in the
|
||||
`unstable_features` section of the
|
||||
[versions endpoint](https://spec.matrix.org/v1.11/client-server-api/#get_matrixclientversions)
|
||||
in addition to the usual version-based feature support. This option is provided
|
||||
to encourage a faster rollout in the wider Matrix ecosystem until servers
|
||||
support the full feature set of the respective version of the Matrix
|
||||
specification.
|
||||
|
||||
## Dependencies
|
||||
|
||||
None.
|
||||
@ -0,0 +1,91 @@
|
||||
# MSC3939: Account locking
|
||||
|
||||
Account locking is a common safety and security tool where server administrators
|
||||
can prevent a user from usefully using their account. For example, too many failed
|
||||
login attempts, escalation in moderation action, or out of band verification
|
||||
needing to be completed.
|
||||
|
||||
Currently, Matrix only supports deactivating an account. This is a destructive
|
||||
action which often leads to the account leaving all joined rooms, among other
|
||||
details. With account locking, the effect of making the user unable to access
|
||||
their account is achieved without destroying that same account - the account
|
||||
can always be unlocked.
|
||||
|
||||
This proposal covers account locking, though leaves the specifics of use as an
|
||||
implementation detail. APIs for administration of locking are also not provided.
|
||||
|
||||
## Proposal
|
||||
|
||||
When an account is locked, clients receive a `401 Unauthorized` error response
|
||||
to most APIs with an `M_USER_LOCKED` error code and `soft_logout` set to `true`.
|
||||
Excluded APIs are described below. We enable `soft_logout` to encourage clients
|
||||
to make use of the [soft logout](https://spec.matrix.org/v1.9/client-server-api/#soft-logout)
|
||||
semantics: keep encryption state, but otherwise render the account unusable. 401
|
||||
is used to support legacy clients by giving the user a semantically meaningful
|
||||
experience: they may need to try logging in again, and when they do they may get
|
||||
a more useful error message about their account status, though their session data
|
||||
may be deleted by the client if it doesn't recognize the error code. Soft logout
|
||||
aims to prevent total destruction of this data, however.
|
||||
|
||||
Upon receiving the `M_USER_LOCKED` error, clients SHOULD retain session information
|
||||
including encryption state and inform the user that their account has been locked.
|
||||
Details about *why* the user's account is locked are not formally described by
|
||||
this proposal, though future MSCs which cover informing users about actions taken
|
||||
against their account should have such details. Clients may wish to make use of
|
||||
[server contact discovery](https://spec.matrix.org/v1.10/client-server-api/#getwell-knownmatrixsupport)
|
||||
in the meantime.
|
||||
|
||||
Clients SHOULD hide the normal UI from the user when informing them that their
|
||||
account is locked, preventing general use of the account.
|
||||
|
||||
Clients SHOULD continue to `/sync` and make other API calls to more quickly detect
|
||||
when the lock has been lifted. However, clients should rate-limit their requests. If unlocked, the APIs will either return a different
|
||||
error code or a normal 200 OK/successful response. For example, `/sync` will return
|
||||
to working as though nothing ever happened. If the error code changes to
|
||||
`M_UNKNOWN_TOKEN`, the client should delete local session data as it normally
|
||||
would when seeing the error code (and use soft logout as it normally would). This
|
||||
is typically expected if the server admin logged the user out or the user logged
|
||||
themselves out.
|
||||
|
||||
Locked accounts are still permitted to access the following API endpoints:
|
||||
|
||||
* [`POST /logout`](https://spec.matrix.org/v1.9/client-server-api/#post_matrixclientv3logout)
|
||||
* [`POST /logout/all`](https://spec.matrix.org/v1.9/client-server-api/#post_matrixclientv3logoutall)
|
||||
|
||||
When a user's account is locked, servers SHOULD NOT invalidate an account's access tokens in case the account becomes
|
||||
unlocked: the user should be able to retain their sessions without having to log
|
||||
back in. However, if a client requests a logout (using the above endpoints), the
|
||||
associated access tokens should be invalidated as normal.
|
||||
|
||||
## Potential issues
|
||||
|
||||
This proposal does not communicate *why* a user's account is restricted. The human-readable `error`
|
||||
field may contain some information, though anything comprehensive may not be surfaced to the user.
|
||||
A future MSC is expected to build a system for both informing the user of the action taken against
|
||||
their account and allow the user to appeal that action.
|
||||
|
||||
## Alternatives
|
||||
|
||||
[MSC3823](https://github.com/matrix-org/matrix-spec-proposals/pull/3823) covers
|
||||
a similar concept, though is semantically different. See [matrix-org/glossary](https://github.com/matrix-org/glossary)
|
||||
for details.
|
||||
|
||||
Another similar concept would be "shadow banning", though this only applies to
|
||||
moderation use cases.
|
||||
|
||||
A 403 HTTP status code was considered instead of 401 with a `soft_logout`. A 403
|
||||
would indicate that the given action is denied, but otherwise keep the user logged
|
||||
in. This could wrongly indicate [suspension](https://github.com/matrix-org/matrix-spec-proposals/pull/3823),
|
||||
confusing the user. Instead, we provide a semantically similar experience where
|
||||
the user gets soft logged out on legacy clients, preserving encryption and related
|
||||
session data (assuming the client also supports soft logout). This can result in
|
||||
some loss of other session data however, like device-specific settings. Users may
|
||||
also be differently confused when they try to log back in and get cryptic error
|
||||
messages (indicating wrong username/password), however as mentioned above in the
|
||||
Potential Issues section, communicating actions taken against an account is a
|
||||
concern for a future MSC.
|
||||
|
||||
## Unstable prefix
|
||||
|
||||
Until this proposal is considered stable, implementations must use
|
||||
`ORG_MATRIX_MSC3939_USER_LOCKED` instead of `M_USER_LOCKED`.
|
||||
@ -0,0 +1,122 @@
|
||||
# MSC3967: Do not require UIA when first uploading cross signing keys
|
||||
|
||||
When a user first sets up end-to-end encryption cross-signing, their client
|
||||
uploads their cross-signing keys to the server.
|
||||
|
||||
This [upload operation](https://spec.matrix.org/v1.6/client-server-api/#post_matrixclientv3keysdevice_signingupload)
|
||||
requires a higher level of security by applying User-Interactive Auth (UIA) to
|
||||
the endpoint.
|
||||
|
||||
This creates a usability issue at the point of user registration where a client
|
||||
will typically want to immediately set up cross-signing for a new user.
|
||||
|
||||
The issue is that the client will immediately need the user to re-authenticate
|
||||
even though the user just authenticated.
|
||||
|
||||
This usability issue has given rise to workarounds such as a
|
||||
[configurable grace period](https://matrix-org.github.io/synapse/v1.98/usage/configuration/config_documentation.html#ui_auth)
|
||||
(`ui_auth`.`session_timeout`) in Synapse whereby UIA will not be required for
|
||||
uploading cross-signing keys where authentication has taken place recently.
|
||||
|
||||
This proposal aims to provide for a standard way to address this UIA usability
|
||||
issue with respect to setting up cross-signing.
|
||||
|
||||
## Proposal
|
||||
|
||||
For the `POST /_matrix/client/v3/keys/device_signing/upload` endpoint, the
|
||||
Homeserver MUST require User-Interactive Authentication (UIA) _unless_:
|
||||
- there is no existing cross-signing master key uploaded to the Homeserver, OR
|
||||
- there is an existing cross-signing master key and it exactly matches the
|
||||
cross-signing master key provided in the request body. If there are any additional
|
||||
keys provided in the request (self signing key, user signing key) they MUST also
|
||||
match the existing keys stored on the server. In other words, the request contains
|
||||
no new keys. If there are new keys, UIA MUST be performed.
|
||||
|
||||
In these scenarios, this endpoint is not protected by UIA. This means the client does not
|
||||
need to send an `auth` JSON object with their request.
|
||||
|
||||
This change allows clients to freely upload 1 set of keys, but not modify/overwrite keys if
|
||||
they already exist. By allowing clients to upload the same set of keys more than once, this
|
||||
makes this endpoint idempotent in the case where the response is lost over the network, which
|
||||
would otherwise cause a UIA challenge upon retry.
|
||||
|
||||
## Potential issues
|
||||
|
||||
See security considerations below.
|
||||
|
||||
|
||||
## Alternatives
|
||||
|
||||
There has been some discussion around how to improve the usability of
|
||||
cross-signing more generally. It may be that an alternative solution is to
|
||||
provide a way to set up cross-signing in a single request.
|
||||
|
||||
## Security considerations
|
||||
|
||||
This change could be viewed as a degradation of security at the point of setting
|
||||
up cross-signing in that it requires less authentication to upload cross-signing
|
||||
keys on first use.
|
||||
|
||||
However, this degradation needs to be weighed against the typical real world
|
||||
situation where a Homeserver will be applying a grace period and so allow a
|
||||
malicious actor to bypass UIA for a period of time after each authentication.
|
||||
|
||||
### Existing users without E2EE keys
|
||||
|
||||
Existing user accounts who do not already have cross-signing keys set up will
|
||||
now be able to upload keys without UIA. If such a user has their access token
|
||||
compromised, an attacker will be able to upload a `master_key`, `self_signing_key`
|
||||
and `user_signing_key`. This is a similar threat model to a malicious server admin
|
||||
replacing these keys in the homeserver database.
|
||||
|
||||
This does not mean:
|
||||
- the attacker can "take over the account". It does not allow the attacker to
|
||||
[login](https://spec.matrix.org/v1.10/client-server-api/#login) as they need to
|
||||
know the password to the account. Likewise, an attacker cannot [logout all devices](https://spec.matrix.org/v1.10/client-server-api/#post_matrixclientv3logoutall)
|
||||
nor can they [logout specific devices](https://spec.matrix.org/v1.10/client-server-api/#delete_matrixclientv3devicesdeviceid)
|
||||
as these also go through UIA prompts.
|
||||
- the device will appear as verified to other users. Other users need to verify the
|
||||
public key [out-of-band](https://spec.matrix.org/v1.10/client-server-api/#short-authentication-string-sas-verification).
|
||||
As the true owner of the account is not performing this verification, if an attacker
|
||||
physically met up with other users it would become obvious that this is not the true owner,
|
||||
and hence no verification would be performed.
|
||||
|
||||
The main usability issue around this endpoint is requiring UIA, so it is critical
|
||||
that we only require UIA when absolutely necessary for the security of the account.
|
||||
In practice, this means requiring UIA when keys are _replaced_. There have been
|
||||
suggestions to reintroduce a grace period (e.g after initial device login) or just
|
||||
mandate it entirely for these old existing accounts. This would negatively impact
|
||||
usability because:
|
||||
- it introduces temporal variability which becomes difficult to debug. Not all users
|
||||
would be subject to these timers/mandates. As a result, it needs to be possible
|
||||
to detect in a bug report if the client is one of these special cases, and this is hard to do
|
||||
reliably, particularly when bug reports from other servers are involved. The kinds of
|
||||
bugs being debugged are typically around encryption, where there are complex interactions
|
||||
between different devices and continually changing server-side state. These kinds of bugs
|
||||
are incredibly time-sensitive as it is, and adding more temporal variability makes it even
|
||||
harder to debug correctly.
|
||||
- it introduces configuration variability which becomes difficult to debug. It's not
|
||||
clear what the grace period should actually be. Anything less than 1 hour risks
|
||||
catching initial x-signing requests from users who are on particularly awful networks.
|
||||
However, even increasing this to 1 hour poses the risk that we incorrectly catch the
|
||||
initial upload (e.g the client logs in on a bad GSM connection, then give up waiting
|
||||
for it to login and close the app, only reopening it the next day). This becomes
|
||||
difficult to debug in bug reports, as they just report HTTP 401s and it is unknown what
|
||||
the HS configuration is for the time delay. This is seen already due to the use (or non-use)
|
||||
of `ui_auth.session_timeout`. A spec-mandated grace period would mitigate some of these
|
||||
concerns, which could be further improved by adding special error codes indicating that
|
||||
the grace period had expired. However, this adds extra API surface that will likely be
|
||||
poorly tested in clients, as it's unreasonable to wait 1+ hours in a test, hence some
|
||||
configuration would be likely included for testing purposes anyway.
|
||||
|
||||
For these reasons, this MSC does not specify a grace period or treat some user accounts
|
||||
without existing cross-signing keys as special.
|
||||
|
||||
|
||||
## Unstable prefix
|
||||
|
||||
Not applicable as client behaviour need not change.
|
||||
|
||||
## Dependencies
|
||||
|
||||
None.
|
||||
@ -0,0 +1,80 @@
|
||||
# MSC4010: Push rules and account data
|
||||
|
||||
Push rules have a [bespoke API](https://spec.matrix.org/v1.6/client-server-api/#push-rules-api)
|
||||
which clients use to retrieve, add, modify, and remove push rules. Any modifications
|
||||
made using this API are sent to all clients via a `m.push_rules` event in the
|
||||
`account_data` section in the
|
||||
[the next `/sync` response](https://spec.matrix.org/v1.6/client-server-api/#push-rules-events).
|
||||
|
||||
The client-server API does not have any special behavior around using the
|
||||
[account data APIs](https://spec.matrix.org/v1.6/client-server-api/#client-behaviour-17)
|
||||
with the `m.push_rules` type leading to different behavior on different homeservers:
|
||||
|
||||
* Synapse will accept the data and shadow the real push rules in `/sync`, but
|
||||
*won't use the data when evaluating push rules*.
|
||||
* Dendrite will return an HTTP 403 if you attempt to set `m.push_rules` via
|
||||
`/account_data`.
|
||||
* Conduit has no protections for special account data. It will accept `m.push_rules` via
|
||||
`/account_data` *and* use those when evaluating push rules.
|
||||
|
||||
The [fully read marker](https://spec.matrix.org/v1.6/client-server-api/#fully-read-markers)
|
||||
operates in a similar way and
|
||||
[servers must reject updating `m.fully_read` via `/account_data`](https://spec.matrix.org/v1.6/client-server-api/#server-behaviour-10).
|
||||
|
||||
Note that when attempting to set `m.fully_read` via `/account_data` the following
|
||||
behavior is observed:
|
||||
|
||||
* Synapse will reject it with a 405 error (only for room account data).
|
||||
* Dendrite will reject it with an HTTP 403 error.
|
||||
|
||||
## Proposal
|
||||
|
||||
To make push rules data consistent with fully read markers, the following
|
||||
clarifications are offered:
|
||||
|
||||
* The `m.push_rules` account data type becomes protected and cannot be set using
|
||||
the `/account_data` API, similarly to `m.fully_read`.
|
||||
* "Rejected" means to use the 405 error response as
|
||||
[documented](https://spec.matrix.org/v1.6/client-server-api/#put_matrixclientv3useruseridaccount_datatype):
|
||||
|
||||
> This `type` of account data is controlled by the server; it cannot be modified
|
||||
> by clients. Errcode: `M_BAD_JSON`.
|
||||
* `m.push_rules` and `m.fully_read` should be rejected for both global and room
|
||||
account data.
|
||||
* Reading `m.push_rules` and `m.fully_read` should be allowed (although note that
|
||||
currently `m.push_rules` only makes sense for global account data and `m.fully_read`
|
||||
only makes sense for room account data). The format should match what is currently
|
||||
[returned via `/sync`](https://spec.matrix.org/v1.6/client-server-api/#push-rules-events).
|
||||
|
||||
The above rules shall also apply when deleting account data if [MSC3391](https://github.com/matrix-org/matrix-spec-proposals/pull/3391)
|
||||
is merged before this MSC.
|
||||
|
||||
## Potential issues
|
||||
|
||||
It is possible that a client is currently storing data in the `m.push_rules`
|
||||
(or global `m.fully_read`) account data. After this change it could no longer
|
||||
be updated, deleted, or retrieved. It seems unlikely that the data stored here
|
||||
is done purposefully (and is likely the result of undefined behavior that this
|
||||
MSC is attempting to fix).
|
||||
|
||||
## Alternatives
|
||||
|
||||
An alternative would be to remove the current push rules API and have clients
|
||||
store all push rules in bulk. This would be subject to race conditions between
|
||||
clients.
|
||||
|
||||
A slight variation of the above would be to *additionally* define the `/account_data/m.push_rules`
|
||||
endpoint as bulk modifying the push rules data. This could be seen as an alternative
|
||||
to [MSC3934](https://github.com/matrix-org/matrix-spec-proposals/pull/3934).
|
||||
|
||||
## Security considerations
|
||||
|
||||
None foreseen.
|
||||
|
||||
## Unstable prefix
|
||||
|
||||
This is mostly clarifications and does not add any event types or new endpoints.
|
||||
|
||||
## Dependencies
|
||||
|
||||
N/A
|
||||
@ -0,0 +1,50 @@
|
||||
# MSC4041: Use http header Retry-After to enable library-assisted retry handling
|
||||
|
||||
The current Matrix Client-Server API (v1.7) recommends that homeservers should protect themselves from
|
||||
being overloaded by enforcing rate-limits to selected API calls.
|
||||
If homeservers limit access to an API they respond with an http error code 429 and a response body
|
||||
that includes a property `retry_after_ms` to indicate how long a client has to wait before retrying.
|
||||
|
||||
Some http libraries (like [Ky](https://github.com/sindresorhus/ky), [got](https://github.com/sindresorhus/got)
|
||||
and [urllib3](https://urllib3.readthedocs.io/en/stable/reference/urllib3.util.html#urllib3.util.Retry)) ease
|
||||
the burden of handling retries by honoring the http header `Retry-After`. As explained in
|
||||
[RFC 9119 - HTTP Semantics](https://www.rfc-editor.org/rfc/rfc9110#field.retry-after) this header is optional
|
||||
and contains either a (relative) value for the delay in seconds or an (absolute) date.
|
||||
|
||||
The current Matrix Client Server API specification does not take this header into account. This wastes the
|
||||
potential that current http libraries offer in terms of automated retry handling.
|
||||
|
||||
## Proposal
|
||||
|
||||
In order to allow developers to make use of the automated retry handling capabilities of http libraries
|
||||
homeservers shall use the http header `Retry-After` in case they respond with an http error 429.
|
||||
The value of `Retry-After` (in __seconds__) is meant to be a delay after receiving the response and must be
|
||||
calculated in order to comply with the specification in [RFC 9119 - HTTP Semantics](https://www.rfc-editor.org/rfc/rfc9110#field.retry-after).
|
||||
|
||||
With the introduction of the http header `Retry-After` the usage of the existing `retry_after_ms` property in the response body becomes deprecated.
|
||||
|
||||
## Potential issues
|
||||
|
||||
In order to maintain backward compatibility with existing client libraries homeservers shall use both the `Retry-After` header and the
|
||||
`retry_after_ms` property in the response body.
|
||||
|
||||
Client libraries shall use the values in this order:
|
||||
|
||||
1) `Retry-After` http header.
|
||||
2) `retry_after_ms` property in the response body.
|
||||
|
||||
## Alternatives
|
||||
|
||||
N/A
|
||||
|
||||
## Security considerations
|
||||
|
||||
N/A
|
||||
|
||||
## Unstable prefix
|
||||
|
||||
Since this MSC is using a standard HTTP header, it will not use a unstable prefix.
|
||||
|
||||
## Dependencies
|
||||
|
||||
N/A
|
||||
@ -0,0 +1,58 @@
|
||||
# MSC4077: Improved process for handling deprecated HTML features
|
||||
|
||||
The Matrix specification [defines](https://spec.matrix.org/v1.8/client-server-api/#mroommessage-msgtypes)
|
||||
a subset of HTML which clients *should* use when rendering messages, limiting the possibility for
|
||||
Cross-Site Scripting (XSS) and similar attacks. Clients are always welcome to use a different subset
|
||||
in both their send and receive paths, however in practice the recommended set of HTML has become the
|
||||
baseline standard for support among Matrix client developers.
|
||||
|
||||
Additionally, to fix issues like [tags being deprecated](https://github.com/matrix-org/matrix-spec/issues/1492),
|
||||
the existing spec process would require an entire MSC to add or remove the tag. This has precedent
|
||||
through [MSC2422](https://github.com/matrix-org/matrix-spec-proposals/pull/2422) and
|
||||
[MSC2184](https://github.com/matrix-org/matrix-spec-proposals/pull/2184), where additional HTML
|
||||
features are analyzed from a security perspective. For example, whether XSS attacks are more probable
|
||||
or flooding/disruption attempts are made easier.
|
||||
|
||||
This proposal adjusts the MSC process to explicitly allow changes to the supported HTML tags where
|
||||
the WHATWG has deprecated a feature in favour of another, enabling more rapid iteration and reducing
|
||||
paperwork for everyone involved.
|
||||
|
||||
## Proposal
|
||||
|
||||
Where the WHATWG has deprecated a feature of the HTML specification, a Matrix spec PR *may* bypass the
|
||||
MSC process to use the modern feature instead. In the case of [issue#1492](https://github.com/matrix-org/matrix-spec/issues/1492),
|
||||
the spec PR is explicitly able to add the `s` tag and remove the `strike` tag. Note that such changes
|
||||
can also bypass the [deprecation policy](https://spec.matrix.org/v1.8/#deprecation-policy) in this way.
|
||||
|
||||
It is left to the discretion of the spec PR reviewer as to whether an MSC is required. In general, an
|
||||
MSC should be requested when the replacement HTML feature is not quite the same as the old feature.
|
||||
The reviewer *may* also decide whether to keep supporting the old, deprecated, feature for some time.
|
||||
For example, replacing `strike` with `s` may mean that both tags are supported for 1-2 Matrix spec
|
||||
versions before `strike` can be dropped.
|
||||
|
||||
For clarity, an MSC is always required to add net-new features to the HTML subset, or to remove a
|
||||
feature entirely. An example of this is [MSC2398](https://github.com/matrix-org/matrix-spec-proposals/pull/2398).
|
||||
These changes are subject to interoperability and security review, and cannot bypass the MSC process.
|
||||
|
||||
## Potential issues
|
||||
|
||||
The author notes that this MSC might not need to exist under the banner of pragmatism, however for all
|
||||
the effort to *not* write an MSC, an MSC has been written for review.
|
||||
|
||||
## Alternatives
|
||||
|
||||
Critically, without agreement that replacing deprecated HTML features can happen outside the MSC process,
|
||||
changes to the HTML subset become slow and burdensome for no apparent gain.
|
||||
|
||||
## Security considerations
|
||||
|
||||
Special care and attention is expected to be taken by spec PR reviewers to ensure that changes are
|
||||
safe and in line with the semantics of this proposal's guidance.
|
||||
|
||||
## Unstable prefix
|
||||
|
||||
Not applicable. This is a process MSC.
|
||||
|
||||
## Dependencies
|
||||
|
||||
None applicable.
|
||||
@ -0,0 +1,157 @@
|
||||
# MSC4115: membership metadata on events
|
||||
|
||||
## Background
|
||||
|
||||
Consider the following Event DAG:
|
||||
|
||||
```mermaid
|
||||
graph BT;
|
||||
B[Bob joins];
|
||||
B-->A;
|
||||
C-->A;
|
||||
D-->B;
|
||||
D-->C;
|
||||
```
|
||||
|
||||
Bob has joined a room, but at the same time, another user has sent a message
|
||||
`C`.
|
||||
|
||||
Depending on the configuration of the room, Bob's server may serve the event
|
||||
`C` to Bob's client. However, if the room is encrypted, Bob will not be on the
|
||||
recipient list for `C` and the sender will not share the message key with Bob,
|
||||
even though, in an absolute time reference, `C` may have been sent at a later
|
||||
timestamp than Bob's join.
|
||||
|
||||
Unfortunately, there is no way for Bob's client to reliably distinguish events
|
||||
such as `A` and `C` that were sent "before" he joined (and he should therefore
|
||||
not expect to decrypt) from those such as `D` that were sent later.
|
||||
|
||||
(Aside: there are two parts to a complete resolution of this "forked-DAG"
|
||||
problem. The first part is making sure that the *sender* of an encrypted event
|
||||
has a clear idea of who was a member at the point of the event; the second part
|
||||
is making sure that the *recipient* knows whether or not they were a member at
|
||||
the point of the event and should therefore expect to receive keys for it. This
|
||||
MSC deals only with the second part. The whole situation is discussed in more
|
||||
detail at https://github.com/element-hq/element-meta/issues/2268.)
|
||||
|
||||
A similar scenario can arise even in the absence of a forked DAG: clients
|
||||
see events sent when the user was not in the room if the room has [History
|
||||
Visibility](https://spec.matrix.org/v1.10/client-server-api/#room-history-visibility)
|
||||
set to `shared`. (This is fairly common even in encrypted rooms, partly because
|
||||
that is the default state for new rooms even using the `private_chat` preset
|
||||
for the [`/createRoom`](https://spec.matrix.org/v1.10/client-server-api/#post_matrixclientv3createroom)
|
||||
request, and also because history-sharing solutions such as
|
||||
[MSC3061](https://github.com/matrix-org/matrix-spec-proposals/pull/3061) rely
|
||||
on it.)
|
||||
|
||||
As a partial solution to the forked-DAG problem, which will also solve the
|
||||
problem of historical message visibility, we propose a mechanism for servers to
|
||||
inform clients of their room membership at each event.
|
||||
|
||||
## Proposal
|
||||
|
||||
The `unsigned` structure contains data added to an event by a homeserver when
|
||||
serving an event over the client-server API. (See
|
||||
[specification](https://spec.matrix.org/v1.9/client-server-api/#definition-clientevent)).
|
||||
|
||||
We propose adding a new optional property, `membership`. If returned by the
|
||||
server, it MUST contain the membership of the user making the request,
|
||||
according to the state of the room at the time of the event being returned. If
|
||||
the user had no membership at that point (ie, they had yet to join or be
|
||||
invited), `membership` is set to `leave`. Any changes caused by the event
|
||||
itself (ie, if the event itself is a `m.room.member` event for the requesting
|
||||
user) are *included*.
|
||||
|
||||
In other words: servers MUST follow the following algorithm when populating
|
||||
the `unsigned.membership` property on an event E and serving it to a user Alice:
|
||||
|
||||
1. Consider the room state just *after* event E landed (accounting for E
|
||||
itself, but not any other events in the DAG which are not ancestors of E).
|
||||
2. Within the state, find the event M with type `m.room.member` and `state_key`
|
||||
set to Alice's user ID.
|
||||
3. * If no such event exists, set `membership` to `leave`.
|
||||
* Otherwise, set `membership` to the value of the `membership` property of
|
||||
the content of M.
|
||||
|
||||
It is recommended that homeservers SHOULD populate the new property wherever
|
||||
practical, but they MAY omit it if necessary (for example, if calculating the
|
||||
value is expensive, servers might choose to only implement it in encrypted
|
||||
rooms). Clients MUST in any case treat the new property as optional.
|
||||
|
||||
For the avoidance of doubt, the new `membership` property is added to all
|
||||
Client-Server API endpoints that return events, including, but not limited to,
|
||||
[`/sync`](https://spec.matrix.org/v1.9/client-server-api/#get_matrixclientv3sync),
|
||||
[`/messages`](https://spec.matrix.org/v1.9/client-server-api/#get_matrixclientv3roomsroomidmessages),
|
||||
[`/state`](https://spec.matrix.org/v1.9/client-server-api/#get_matrixclientv3roomsroomidstate),
|
||||
and deprecated endpoints such as
|
||||
[`/events`](https://spec.matrix.org/v1.9/client-server-api/#get_matrixclientv3events)
|
||||
and
|
||||
[`/initialSync`](https://spec.matrix.org/v1.9/client-server-api/#get_matrixclientv3events).
|
||||
|
||||
|
||||
Example event including the new property, as seen in the response to a request made by `@user:example.org`:
|
||||
|
||||
```json5
|
||||
{
|
||||
"content": {
|
||||
"membership": "join"
|
||||
},
|
||||
"event_id": "$26RqwJMLw-yds1GAH_QxjHRC1Da9oasK0e5VLnck_45",
|
||||
"origin_server_ts": 1632489532305,
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||
"sender": "@example:example.org",
|
||||
"state_key": "@example:example.org",
|
||||
"type": "m.room.member",
|
||||
"unsigned": {
|
||||
"age": 1567437,
|
||||
// @user:example.org's membership at the time this event was sent
|
||||
"membership": "leave",
|
||||
"redacted_because": {
|
||||
"content": {
|
||||
"reason": "spam"
|
||||
},
|
||||
"event_id": "$Nhl3rsgHMjk-DjMJANawr9HHAhLg4GcoTYrSiYYGqEE",
|
||||
"origin_server_ts": 1632491098485,
|
||||
"redacts": "$26RqwJMLw-yds1GAH_QxjHRC1Da9oasK0e5VLnck_45",
|
||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||
"sender": "@moderator:example.org",
|
||||
"type": "m.room.redaction",
|
||||
"unsigned": {
|
||||
// @user:example.org's membership at the time the redaction was sent
|
||||
"membership": "join",
|
||||
"age": 1257
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Potential issues
|
||||
|
||||
None foreseen.
|
||||
|
||||
## Alternatives
|
||||
|
||||
1. https://github.com/element-hq/element-meta/issues/2268#issuecomment-1904069895
|
||||
proposes use of a Bloom filter — or possibly several Bloom filters — to
|
||||
mitigate this problem in a more general way. It is the opinion of the author of
|
||||
this MSC that there is room for both approaches.
|
||||
|
||||
2. We could attempt to calculate the membership state on the client side. This
|
||||
might help in a majority of cases, but it will be unreliable in the presence
|
||||
of forked DAGs. It would require clients to implement the [state resolution
|
||||
algorithm](https://spec.matrix.org/v1.10/rooms/v11/#state-resolution), which
|
||||
would be prohibitively complicated for most clients.
|
||||
|
||||
## Security considerations
|
||||
|
||||
None foreseen.
|
||||
|
||||
## Unstable prefix
|
||||
|
||||
While this proposal is in development, the name `io.element.msc4115.membership`
|
||||
MUST be used in place of `membership`.
|
||||
|
||||
## Dependencies
|
||||
|
||||
None.
|
||||
@ -0,0 +1,74 @@
|
||||
# MSC4126: Deprecation of query string auth
|
||||
|
||||
Presently, the Client-Server API allows clients to provide their access token via the `Authorization`
|
||||
request header or via an `access_token` query string parameter, described [here](https://spec.matrix.org/v1.10/client-server-api/#using-access-tokens).
|
||||
Clients are already encouraged to use the header approach, though the query string option exists for
|
||||
largely backwards compatibility reasons.
|
||||
|
||||
The query string approach is subject a number of security, usability, and practical concerns, discussed
|
||||
on [matrix-spec#1780](https://github.com/matrix-org/matrix-spec/issues/1780):
|
||||
|
||||
* The query string of an HTTP request is often logged by the client itself, middleware reverse proxy,
|
||||
and application/homeserver as well. Though some of these layers may be aware of this issue, they
|
||||
can trivially accidentally break to log sensitive credentials again. By contrast, headers are not
|
||||
typically logged by default.
|
||||
|
||||
* Users often copy and paste URLs from their clients to either get support or provide direct links
|
||||
to content/media. While the media angle is largely expected to be resolved with [MSC3916](https://github.com/matrix-org/matrix-spec-proposals/pull/3916),
|
||||
users are currently able to right click images in their client and copy the URL - if this URL
|
||||
includes authentication in the query string, the user will likely end up disclosing their access
|
||||
token. The same scenario applies when copy/pasting request logs out of a client when getting
|
||||
support.
|
||||
|
||||
* Having two ways of doing things could lead to compatibility issues, where a client using the query
|
||||
string approach is tried against a server which only supports the header. The client ends up not
|
||||
working, leading to subpar user experience.
|
||||
|
||||
* Most clients have already adopted the header approach, largely forgetting that the query string
|
||||
even exists. Continuing to support the query string option leaves some maintenance burden for what
|
||||
is effectively unused code.
|
||||
|
||||
* Matrix has [decided](https://matrix.org/blog/2023/09/matrix-2-0/) to adopt OIDC for authentication,
|
||||
which is based on OAuth 2.0, which [advises against](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-security-topics#section-4.3.2)
|
||||
the query string approach.
|
||||
|
||||
With these conditions in mind, this proposal sets the query string approach on a path towards removal
|
||||
from the Matrix specification. This affects the Client-Server API and [Identity Service API](https://spec.matrix.org/v1.10/identity-service-api/#authentication)
|
||||
as both support the approaches described above.
|
||||
|
||||
## Proposal
|
||||
|
||||
For both the Client-Server API and Identity Service API, the `access_token` query string authentication
|
||||
parameter becomes *deprecated*, and SHOULD NOT be used by clients (as already stated in the specification).
|
||||
Deprecation is required for at least 1 spec version before removal under the [deprecation policy](https://spec.matrix.org/v1.10/#deprecation-policy).
|
||||
|
||||
Removal from the specification requires a second MSC and at least 1 specification release to pass. This
|
||||
is currently described as [MSC4127](https://github.com/matrix-org/matrix-spec-proposals/pull/4127).
|
||||
|
||||
## Potential issues
|
||||
|
||||
Clients which rely on the query string approach may stop working. This is considered acceptable for
|
||||
the purposes of this MSC.
|
||||
|
||||
## Alternatives
|
||||
|
||||
Most alternatives are not practical as they would maintain the security risk described in the introduction
|
||||
for this proposal.
|
||||
|
||||
Alterations to the deprecation policy may be discussed in a future MSC to make this sort of removal
|
||||
easier.
|
||||
|
||||
## Security considerations
|
||||
|
||||
Security considerations are described throughout this proposal.
|
||||
|
||||
## Unstable prefix
|
||||
|
||||
This proposal cannot feasibly have an unstable prefix. Clients are already discouraged from using
|
||||
query string authentication and should switch to `Authorization` as soon as possible, regardless of
|
||||
this MSC.
|
||||
|
||||
## Dependencies
|
||||
|
||||
This MSC has no direct dependencies itself. [MSC4127](https://github.com/matrix-org/matrix-spec-proposals/pull/4127)
|
||||
requires this MSC to land first.
|
||||
@ -0,0 +1,58 @@
|
||||
# MSC4132: Deprecate Linking to an Event Against a Room Alias.
|
||||
|
||||
## Introduction
|
||||
|
||||
The spec supports 2 types of URI, the [Matrix scheme](https://spec.matrix.org/v1.10/appendices/#matrix-uri-scheme)
|
||||
and [matrix.to](https://spec.matrix.org/v1.10/appendices/#matrixto-navigation) links which allow deep linking to
|
||||
Matrix users, rooms and events. Event URIs can be constructed against either a room ID or a room alias the latter of
|
||||
which is fragile issue as a room's alias is mutable and so event links may be broken by changes to the alias. Users
|
||||
expect deep links to continue working so that older links continue to show the correct content. Therefore it is proposed
|
||||
to deprecate event links against a room alias.
|
||||
|
||||
|
||||
## Proposal
|
||||
|
||||
As room IDs are immutable, event URIs built against these will continue to work for as long as the room is reachable by
|
||||
the homeserver. In contrast, event URIs built against a room alias can break under the following circumstances:
|
||||
- The room is upgraded, resulting in the alias pointing to the new room, which won't contain any events from the
|
||||
ancestor.
|
||||
- The alias is removed/changed resulting in a dead link that can't be resolved.
|
||||
|
||||
The proposal would [deprecate](https://spec.matrix.org/v1.10/#deprecation-policy) the 2 following URIs:
|
||||
- Link to `$event` in `#somewhere:example.org`: `matrix:r/somewhere:example.org/e/event`
|
||||
- Link to `$event` in `#somewhere:example.org`: `https://matrix.to/#/%23somewhere:example.org/%24event%3Aexample.org`
|
||||
|
||||
Specifically this means it would be marked in the spec as not to be used in future and clients should:
|
||||
1. Stop making new event URIs with room aliases, generating the examples above as the following respectively:
|
||||
- `matrix:roomid/opaqueid:example.org/e/event?via=example.com`
|
||||
- `https://matrix.to/#/!opaqueid%3Aexample.org/%24event%3Aexample.org?via=example.com`
|
||||
2. Continue to accept them as it will take time for other clients to update and legacy events will continue to exist.
|
||||
|
||||
It is worth nothing that this change would require clients to always add the `via=` fields when building event URIs as
|
||||
these are expected for URIs that reference a room ID.
|
||||
|
||||
|
||||
## Potential issues
|
||||
|
||||
Whilst most clients do take the sensible route and generate event URIs against a room ID (even when it has an alias), as
|
||||
it is part of the spec these kinds of links likely exist somewhere in room history and on the World Wide Web. This would
|
||||
mean that after deprecation clients may still want to handle these URIs when received.
|
||||
|
||||
Additionally, whilst not a new problem some clients don't always update the `via` fields, which poses a problem for
|
||||
rooms that have lots of single user homeservers: A single user leaving can result in the `via` to become non functional
|
||||
which over time can result in unreachable room IDs (this is essentially the equivalent of the alias being removed).
|
||||
|
||||
|
||||
## Alternatives
|
||||
|
||||
An alternative would be to leave things as they are, although this wouldn't be the best choice for the user.
|
||||
|
||||
|
||||
## Security considerations
|
||||
|
||||
It is unlikely that accepting this change would introduce any security considerations.
|
||||
|
||||
|
||||
## Dependencies
|
||||
|
||||
N/A
|
||||
@ -0,0 +1,427 @@
|
||||
# MSC4133: Extending User Profile API with Custom Key:Value Pairs
|
||||
|
||||
This proposal aims to enhance user profiles in the Matrix ecosystem by introducing customisable
|
||||
key:value pairs to global profiles. By allowing users to add arbitrary public information
|
||||
(such as preferred languages, organisational roles, or other relevant details) we can enrich
|
||||
user interactions without impacting existing functionality.
|
||||
|
||||
## Proposal Overview
|
||||
|
||||
Currently, the Matrix protocol supports limited user profile fields: `avatar_url` and `displayname`.
|
||||
This proposal is modelled on the [current API endpoints](https://spec.matrix.org/v1.12/client-server-api/#profiles),
|
||||
extending the profile API to include extra fields, enabling users and servers to publish key:value
|
||||
pairs to their global profiles. This extension provides a flexible framework for users to share
|
||||
additional public information.
|
||||
|
||||
The proposal is designed to be straightforward and compatible with existing clients and servers,
|
||||
requiring minimal changes to facilitate quick adoption. It complements, rather than replaces,
|
||||
[MSC1769](https://github.com/matrix-org/matrix-spec-proposals/pull/1769) (Extensible Profiles as
|
||||
Rooms) by focusing on global profile data without the complexity of per-room profile management.
|
||||
|
||||
## Authentication and Rate Limiting
|
||||
|
||||
All endpoints in this proposal follow the standard client-server API authentication rules. Specifically:
|
||||
|
||||
- All endpoints require authentication except for GET requests which may be accessed without
|
||||
authentication
|
||||
- Servers MUST verify the access token has permission to modify the requested userId's profile
|
||||
- Rate limiting SHOULD be applied as per the homeserver's normal profile endpoint limits
|
||||
- Guest access follows the same rules as existing profile endpoints - guests may view profiles but
|
||||
not modify them
|
||||
|
||||
## Client-Server API Changes
|
||||
|
||||
### Get a Profile Field
|
||||
|
||||
- **Endpoint**: `GET /_matrix/client/v3/profile/{userId}/{key_name}`
|
||||
- **Description**: Retrieve the value of a specified `key_name` from a user's profile.
|
||||
- **Pagination**: Not applicable, returns a single bounded key-value pair
|
||||
- **Response**:
|
||||
|
||||
```json
|
||||
{
|
||||
"key_name": "field_value"
|
||||
}
|
||||
```
|
||||
|
||||
*Example*: Requesting `GET /_matrix/client/v3/profile/@alice:matrix.org/displayname` returns:
|
||||
|
||||
```json
|
||||
{
|
||||
"displayname": "Alice"
|
||||
}
|
||||
```
|
||||
|
||||
### Set a Profile Field
|
||||
|
||||
- **Endpoint**: `PUT /_matrix/client/v3/profile/{userId}/{key_name}`
|
||||
- **Description**: Set or update the value of a specified `key_name` in the user's profile,
|
||||
if permitted by the homeserver.
|
||||
- **Request Body**:
|
||||
|
||||
```json
|
||||
{
|
||||
"key_name": "new_value"
|
||||
}
|
||||
```
|
||||
|
||||
*Example*: Setting `PUT /_matrix/client/v3/profile/@alice:matrix.org/displayname` with:
|
||||
|
||||
```json
|
||||
{
|
||||
"displayname": "Alice Wonderland"
|
||||
}
|
||||
```
|
||||
|
||||
**Note**: As a `DELETE` endpoint exists to remove a key, setting a `null` value with the `PUT`
|
||||
method SHOULD NOT delete the key but rather retain it with a `null` value. Servers MAY forbid a
|
||||
`null` request if their policy does not allow keys to exist with a `null` value.
|
||||
|
||||
### Delete a Profile Field
|
||||
|
||||
- **Endpoint**: `DELETE /_matrix/client/v3/profile/{userId}/{key_name}`
|
||||
- **Description**: Remove a specified `key_name` (and its value) from the user's profile,
|
||||
if permitted by the homeserver.
|
||||
|
||||
### Get All Profile Fields
|
||||
|
||||
- **Endpoint**: `GET /_matrix/client/v3/profile/{userId}`
|
||||
- **Description**: Retrieve all profile fields for a user, identical to the
|
||||
[current API](https://spec.matrix.org/latest/client-server-api/#get_matrixclientv3profileuserid).
|
||||
- **Pagination**: Not applicable, the full profile is bounded at 64 KiB total size
|
||||
- **Response**:
|
||||
|
||||
```json
|
||||
{
|
||||
"avatar_url": "mxc://matrix.org/MyC00lAvatar",
|
||||
"displayname": "John Doe",
|
||||
"m.example_field": "value1",
|
||||
"org.example.job_title": "Software Engineer"
|
||||
}
|
||||
```
|
||||
|
||||
## Server-Server API Changes
|
||||
|
||||
The federation endpoint [`GET /_matrix/federation/v1/query/profile`](https://spec.matrix.org/v1.13/server-server-api/#get_matrixfederationv1queryprofile)
|
||||
will mirror the client-server API changes to facilitate profile information consistency between
|
||||
local and federated users, though homeservers MAY decide specific fields are not published over
|
||||
federation.
|
||||
|
||||
As per the current stable endpoint, it accepts an optional `field` query string parameter to
|
||||
request a single field. At the time of writing, the Matrix specification says:
|
||||
|
||||
> If no `field` was specified, the response should include the fields of the user's profile that
|
||||
> can be made public, such as the display name and avatar.
|
||||
|
||||
Given this wording, homeservers currently have the flexibility to decide whether some fields are
|
||||
published over federation, and this proposal continues to allow this behaviour.
|
||||
|
||||
## Capabilities
|
||||
|
||||
A new capability `m.profile_fields` controls the ability to *set* profile fields and is advertised
|
||||
on the `GET /_matrix/client/v3/capabilities` endpoint.
|
||||
|
||||
This capability deprecates the use of `m.set_displayname` and `m.set_avatar_url`, which are not
|
||||
required when this capability is present.
|
||||
|
||||
Clients MAY check for this capability before attempting to create or modify a profile field.
|
||||
|
||||
### Capability Structure
|
||||
|
||||
```json
|
||||
{
|
||||
"capabilities": {
|
||||
"m.profile_fields": {
|
||||
"enabled": true,
|
||||
"allowed": ["m.example_field", "org.example.job_title"],
|
||||
"disallowed": ["org.example.secret_field"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Behaviour
|
||||
|
||||
- **When capability is missing**: Clients SHOULD assume extended profiles are supported and that
|
||||
they can be created or modified, provided the response from [`/versions`](https://spec.matrix.org/v1.13/client-server-api/#get_matrixclientversions)
|
||||
indicates support for a spec version that includes this proposal. If a server intends to deny some
|
||||
(or all) changes, it SHOULD use the capability to advertise this, improving the client experience.
|
||||
|
||||
- **When `enabled` is `false`**: Clients SHOULD expect to display profiles but NOT create or update
|
||||
fields. Any attempt to do so SHOULD result in a `403 Forbidden` error.
|
||||
|
||||
- **When `enabled` is `true`**: Clients SHOULD allow users to create or update fields, except those
|
||||
keys listed in the `disallowed` array. Servers MAY specify an `allowed` array to allowlist fields
|
||||
that users can set. If both `allowed` and `disallowed` keys are provided, the `disallowed` one
|
||||
should be ignored. Clients SHOULD receive `400 Bad Request` or `403 Forbidden` responses if
|
||||
server-side policies prevent them.
|
||||
|
||||
## Key and Namespace Requirements
|
||||
|
||||
Profiles MUST be at most 64 KiB (65,536 bytes) in size, as measured in
|
||||
[Canonical JSON](https://spec.matrix.org/v1.13/appendices/#canonical-json), including the
|
||||
`avatar_url` and `displayname` fields.
|
||||
|
||||
Keys MUST follow the [Common Namespaced Identifier Grammar](https://spec.matrix.org/v1.13/appendices/#common-namespaced-identifier-grammar),
|
||||
with the following considerations:
|
||||
|
||||
- **Namespace `m.*`**: Reserved for fields explicitly defined in the Matrix specification:
|
||||
- Servers SHOULD NOT check whether a key is known to be in the Matrix specification, as future
|
||||
expansions may be unknown to it.
|
||||
- Clients that do not recognise a field in this namespace MAY attempt to display it but
|
||||
SHOULD NOT attempt to update the content unless they understand its formatting and validation
|
||||
requirements.
|
||||
|
||||
- **Namespace `tld.name.*`**: For client-specific or unstable fields, using Java package naming
|
||||
convention (e.g. `com.example.custom_field`).
|
||||
|
||||
Following this change, clients could use `m.example_field` if that field is defined by the Matrix
|
||||
specification, or `org.example.job_title` for organisation, client-specific fields, or MSC-backed
|
||||
unstable features. Proposal [MSC4175](https://github.com/matrix-org/matrix-spec-proposals/pull/4175)
|
||||
demonstrates the process of defining new fields in the `m.*` namespace.
|
||||
|
||||
## Error Handling
|
||||
|
||||
### 400 Bad Request: Request Exceeds Limits or Is Malformed
|
||||
|
||||
- **`M_BAD_JSON`**: Malformed request.
|
||||
|
||||
```json
|
||||
{
|
||||
"errcode": "M_BAD_JSON",
|
||||
"error": "The provided JSON is malformed."
|
||||
}
|
||||
```
|
||||
|
||||
- **`M_MISSING_PARAM`**: Required parameter is missing, e.g. if a client attempts to set a profile
|
||||
field, but neglects to include that named field in the request body.
|
||||
|
||||
```json
|
||||
{
|
||||
"errcode": "M_MISSING_PARAM",
|
||||
"error": "A required parameter is missing: {parameter_name}."
|
||||
}
|
||||
```
|
||||
|
||||
- **`M_PROFILE_TOO_LARGE`**: Exceeds total profile size limits.
|
||||
|
||||
```json
|
||||
{
|
||||
"errcode": "M_PROFILE_TOO_LARGE",
|
||||
"error": "The profile data exceeds the maximum allowed size of 64 KiB."
|
||||
}
|
||||
```
|
||||
|
||||
- **`M_KEY_TOO_LARGE`**: Exceeds individual key length limits.
|
||||
|
||||
```json
|
||||
{
|
||||
"errcode": "M_KEY_TOO_LARGE",
|
||||
"error": "The key name exceeds the maximum allowed length of 255 characters."
|
||||
}
|
||||
```
|
||||
|
||||
### 403 Forbidden: User Lacks Permission
|
||||
|
||||
A server may return this error in several scenarios:
|
||||
|
||||
- When the user lacks permission to modify another user's profile
|
||||
- When the capability `m.profile_fields` is disabled (`enabled: false`)
|
||||
- When the server denies setting/creating a specific field value, even if the capability allows it
|
||||
(for example, due to content policy violations or server-side validation rules)
|
||||
- When the user is not allowed to modify profiles at all
|
||||
|
||||
```json
|
||||
{
|
||||
"errcode": "M_FORBIDDEN",
|
||||
"error": "You do not have permission to perform this operation"
|
||||
}
|
||||
```
|
||||
|
||||
### 404 Not Found: Target Cannot Be Found
|
||||
|
||||
- **`M_NOT_FOUND`**: Profile key does not exist (this is unchanged, just expanded to
|
||||
apply to arbitrary keys).
|
||||
|
||||
```json
|
||||
{
|
||||
"errcode": "M_NOT_FOUND",
|
||||
"error": "The requested profile key does not exist."
|
||||
}
|
||||
```
|
||||
|
||||
### Applicability of Error Codes
|
||||
|
||||
Unless explicitly stated otherwise, all error codes described in this section apply to all
|
||||
Client-Server and Server-Server endpoints introduced by this MSC. For example:
|
||||
|
||||
1. `M_NOT_FOUND` applies to any attempt to retrieve a non-existent profile field.
|
||||
2. `M_PROFILE_TOO_LARGE` applies to any attempt to create or update profile data exceeding the
|
||||
allowed size.
|
||||
|
||||
The Server-Server endpoints introduced in this MSC adhere to the existing error structure for
|
||||
federation, as the federation access remains read-only in this proposal. This means no new error
|
||||
codes or status code combinations are introduced for Server-Server endpoints beyond what is already
|
||||
documented in the specification.
|
||||
|
||||
## Propagation of Profile Fields
|
||||
|
||||
The existing fields, `avatar_url` and `displayname`, will continue to trigger state events in each
|
||||
room. These fields are replicated per-room via member events.
|
||||
|
||||
All other fields (unless a future proposal specifies otherwise) WILL NOT trigger state events in
|
||||
rooms and will exist solely at the global level for storing metadata about the user.
|
||||
|
||||
Clients SHOULD consider the increased traffic implications when displaying values (e.g. timezones)
|
||||
outside of the profile. Servers MAY wish to optimise and relax rate limits on these endpoints in
|
||||
consideration of this.
|
||||
|
||||
## Implementation Details
|
||||
|
||||
- Custom fields MUST NOT trigger state events in rooms; their data MUST NOT be replicated to
|
||||
`m.room.member` events unless a future proposal creates exceptions for specific fields.
|
||||
|
||||
- Servers MAY cache remote profiles to optimise performance. Servers which prefer to cache details
|
||||
should do so for a short period of time to avoid stale data being presented to users.
|
||||
A future MSC may propose a mechanism for servers to notify each other of profile updates.
|
||||
|
||||
- Clients MAY provide a UI for users to view and enter custom fields, respecting the appropriate
|
||||
namespaces.
|
||||
|
||||
- Clients SHOULD only display profiles of users in the current room whose membership status is
|
||||
`join`, `invite`, or `knock`. If a client offers an option for any free-text fields to always be
|
||||
available in the UI, an option SHOULD be provided to hide or minimise them automatically.
|
||||
|
||||
- Servers MAY add, remove, or modify fields in their own users' global profile data, whether for
|
||||
moderation purposes or for other policy reasons (e.g., to automatically populate a job title
|
||||
based on the user's organisation).
|
||||
|
||||
## Potential Issues
|
||||
|
||||
There is no method to verify the history of global profile fields over federation. This proposal
|
||||
updates the global profile only, while other more complex proposals, such as
|
||||
[MSC1769](https://github.com/matrix-org/matrix-spec-proposals/pull/1769) (Extensible Profiles as
|
||||
Rooms), offer additional mechanisms for users to track changes to their profile data over time.
|
||||
|
||||
Ensuring uniform support across different servers and clients during the rollout phase is crucial.
|
||||
We do not want users to expect that others will check their profile (e.g. languages) before
|
||||
communicating with them unless most clients and servers support this feature.
|
||||
|
||||
As such, this MSC is designed to be as simple as possible to get initial functionality and data
|
||||
structures implemented widely, so further extensions can be debated, implemented, and tested with
|
||||
due care over time.
|
||||
|
||||
As this data is stored only at the global level, it won't allow users to modify fields per-room or
|
||||
track historical changes in profile fields. This proposal recommends that future MSCs only add
|
||||
certain fields to per-room member events when there is explicit value in doing so, and the current
|
||||
functionality added by this proposal is not anticipated to have this value.
|
||||
|
||||
This proposal also does not offer a method to "broadcast" to other users or homeservers that
|
||||
changes have occurred. This is intentional to keep the scope of this change narrow and maximise
|
||||
compatibility with existing servers. A future proposal may wish to use an EDU (such as Presence)
|
||||
to notify users and homeservers that these custom fields have been updated. This would allow
|
||||
servers to cache profile data more effectively without compromising on user experience.
|
||||
|
||||
This proposal does not directly address reporting of user profiles over federation, but
|
||||
[MSC4202](https://github.com/matrix-org/matrix-spec-proposals/pull/4202) offers a facility for
|
||||
users to report offensive content to the homeserver that account belongs to. This proposal is not
|
||||
dependent on MSC4202 but encourages the use of moderation options to allow users to report
|
||||
offensive content.
|
||||
|
||||
## Security Considerations
|
||||
|
||||
Since profile fields are public, the server is not directly responsible for the privacy of the data;
|
||||
however, clients SHOULD make users aware that any information published in their profile will be
|
||||
visible to others on the federated network.
|
||||
|
||||
Likewise, if a server automatically publishes data in user profile fields (e.g. setting a job title
|
||||
based on an organisation's internal user database), then they SHOULD have consent to do so, and
|
||||
users SHOULD be made aware that data is published on their behalf.
|
||||
|
||||
To minimise the impact of abuse, clients should carefully consider when and how to display
|
||||
user-entered profile content. While some clients may choose to show profile fields globally, others
|
||||
may restrict visibility based on room membership or other trust signals. Clients should be aware
|
||||
that profile fields may contain abusive content and implement appropriate safety measures based on
|
||||
their risk assessment. For example, a client could hide a user's custom profile fields in the
|
||||
context of a room if the user in question's latest `m.room.member` state event has been redacted.
|
||||
This gives room moderators the power to quickly hide abusive content in profile fields from other
|
||||
users.
|
||||
|
||||
Proposal [MSC4202](https://github.com/matrix-org/matrix-spec-proposals/pull/4202) adds reporting of
|
||||
user profiles over federation, which offers a facility for users to report offensive content to the
|
||||
homeserver that account is registered on.
|
||||
|
||||
Homeservers and clients SHOULD comply with relevant privacy regulations, particularly regarding
|
||||
data deletion and retention. Profile data SHOULD be cleared when a user is deactivated, and while
|
||||
homeservers SHOULD cache remote profiles, they SHOULD avoid caching beyond 24 hours to minimise the
|
||||
risk of unintended data persistence.
|
||||
|
||||
## Alternatives
|
||||
|
||||
An alternative approach could involve introducing a completely new API for extended profile
|
||||
information. However, this may lead to increased complexity for client and server implementations.
|
||||
|
||||
At the time of writing, Extensible Profiles as Rooms
|
||||
([MSC1769](https://github.com/matrix-org/matrix-spec-proposals/pull/1769) and variant
|
||||
[MSC4201](https://github.com/matrix-org/matrix-spec-proposals/pull/4201)) is under development for
|
||||
richer and more granular content and privacy controls, which this proposal does not intend to
|
||||
replace. This proposal focuses on basic global profile data without the complexity of per-room
|
||||
profile management.
|
||||
|
||||
## Unstable Prefixes
|
||||
|
||||
### Unstable Profile Fields
|
||||
|
||||
Until this proposal is stable, fields SHOULD use an unstable prefix:
|
||||
|
||||
```json
|
||||
{
|
||||
"avatar_url": "mxc://matrix.org/MyC00lAvatar",
|
||||
"displayname": "John Doe",
|
||||
"uk.tcpip.msc4133.m.example_field": "field_value"
|
||||
}
|
||||
```
|
||||
|
||||
### Unstable Endpoints
|
||||
|
||||
Use unstable endpoints when the capability is not yet stable:
|
||||
|
||||
- **Get/Set/Delete Profile Fields**:
|
||||
- `/_matrix/client/unstable/uk.tcpip.msc4133/profile/{userId}/{key_name}`
|
||||
|
||||
### Unstable Capability
|
||||
|
||||
Advertise the capability with an unstable prefix:
|
||||
|
||||
```json
|
||||
{
|
||||
"capabilities": {
|
||||
"uk.tcpip.msc4133.profile_fields": {
|
||||
"enabled": true,
|
||||
"disallowed": ["org.example.secret_field"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Unstable Client Features
|
||||
|
||||
The client feature `uk.tcpip.msc4133` SHOULD be advertised on the `/_matrix/client/versions`
|
||||
endpoint when the unstable endpoints for managing profile fields are supported at
|
||||
`/_matrix/client/unstable/uk.tcpip.msc4133/profile/{userId}/{key_name}`.
|
||||
|
||||
Once this MSC is merged, the client feature `uk.tcpip.msc4133.stable` SHOULD be advertised when
|
||||
these endpoints are accepted at `/_matrix/client/v3/profile/{userId}/{key_name}` until the next
|
||||
spec version where these endpoints are officially written into the spec, e.g.
|
||||
|
||||
```json
|
||||
{
|
||||
"unstable_features": {
|
||||
"uk.tcpip.msc4133": true,
|
||||
"uk.tcpip.msc4133.stable": true
|
||||
},
|
||||
"versions": [
|
||||
"v1.11"
|
||||
]
|
||||
}
|
||||
```
|
||||
@ -0,0 +1,51 @@
|
||||
# MSC4138: Update allowed HTTP methods in CORS responses
|
||||
|
||||
The [specification](https://spec.matrix.org/v1.10/client-server-api/#web-browser-clients) suggests
|
||||
that servers allow a limited subset of the available [HTTP methods](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods)
|
||||
available in [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) responses. However, it's
|
||||
reasonable to expect the specification to use other methods in the future or as part of feature
|
||||
detection. To permit these use cases early, this MSC proposes adding a few more allowable values to
|
||||
the `Access-Control-Allow-Methods` header.
|
||||
|
||||
## Proposal
|
||||
|
||||
The [`Access-Control-Allow-Methods` header's recommended value](https://spec.matrix.org/v1.10/client-server-api/#web-browser-clients)
|
||||
is updated to note that the HTTP methods described cover existing specified endpoints. Servers which
|
||||
support additional endpoints or methods should add those methods as well. The specification will be
|
||||
updated whenever a new method is supported by an endpoint.
|
||||
|
||||
Examples of possible future-use methods include:
|
||||
|
||||
* `PATCH` - A plausibly useful HTTP method for future use.
|
||||
* `HEAD` - Similar to `PATCH`, `HEAD` is plausibly useful for feature detection and cases like
|
||||
[MSC4120](https://github.com/matrix-org/matrix-spec-proposals/pull/4120).
|
||||
|
||||
The following methods are *not* included because they don't have foreseeable use in Matrix:
|
||||
|
||||
* `CONNECT`
|
||||
* `TRACE`
|
||||
|
||||
## Potential issues
|
||||
|
||||
None anticipated.
|
||||
|
||||
## Alternatives
|
||||
|
||||
No significant alternatives.
|
||||
|
||||
## Security considerations
|
||||
|
||||
CORS is meant to help ensure requests made by the client are properly scoped in the client. If the
|
||||
client wishes to use an HTTP method not allowed by the server, the web browser will mask the
|
||||
response with an error before the application can inspect it. Therefore, to increase future
|
||||
compatibility, we append a few useful HTTP methods while still excluding ones which are (currently)
|
||||
nonsensical.
|
||||
|
||||
## Unstable prefix
|
||||
|
||||
This proposal cannot have an unstable prefix due to the nature of CORS. Servers are already able to
|
||||
go off-spec and serve different headers because the spec is merely a recommendation.
|
||||
|
||||
## Dependencies
|
||||
|
||||
This proposal has no dependencies.
|
||||
@ -0,0 +1,51 @@
|
||||
# MSC4142: Remove unintentional intentional mentions in replies
|
||||
|
||||
Currently, the reply spec has a section called [Mentioning the replied to user](https://spec.matrix.org/v1.10/client-server-api/#mentioning-the-replied-to-user)
|
||||
which says
|
||||
|
||||
> In order to notify users of the reply, it may be desirable to include the
|
||||
> sender of the replied to event and any users mentioned in that event. See
|
||||
> [user and room mentions](https://spec.matrix.org/v1.10/client-server-api/#user-and-room-mentions)
|
||||
> for additional information.
|
||||
|
||||
The "*any users mentioned in that event*" part is particularly problematic, as
|
||||
it effectively means all mentions will be propagated forever through a reply
|
||||
chain, causing lots of unintentional pings.
|
||||
|
||||
The propagation was originally added to preserve the old reply fallback mention
|
||||
behavior where explicit mentions in the replied-to message were be copied to
|
||||
the reply fallback and therefore caused pings. However, the current spec copies
|
||||
far more than just explicit pings from the replied-to message. Additionally, no
|
||||
other chat application that I know of propagates mentions like that.
|
||||
|
||||
## Proposal
|
||||
The proposed fix is to stop propagating mentions entirely. The `m.mentions`
|
||||
object of replies should only contain explicit mentions in the new message,
|
||||
plus the sender of the replied-to message. The mentions in the replied-to
|
||||
message are ignored.
|
||||
|
||||
Clients are still free to add other mentions to the list as they see fit. For
|
||||
example, a client could offer a button to mention all users in a reply chain.
|
||||
This proposal simply changes the default behavior recommended in the spec.
|
||||
|
||||
## Potential issues
|
||||
Users who have already got used to the new behavior may be surprised when they
|
||||
don't get mentioned by reply chains.
|
||||
|
||||
## Alternatives
|
||||
### Split `m.mentions`
|
||||
To preserve the old reply fallback behavior, `m.mentions` could be split into
|
||||
"explicit" and "implicit", so that replies copy explicit mentions into the
|
||||
implicit list. Future replies would then only copy new explicit pings and
|
||||
wouldn't cause an infinite chain.
|
||||
|
||||
Since other chat applications don't copy pings at all, having a weird feature
|
||||
like that doesn't seem worth the additional complexity.
|
||||
|
||||
## Security considerations
|
||||
This proposal doesn't touch anything security-sensitive.
|
||||
|
||||
## Unstable prefix
|
||||
Not applicable, this proposal only changes how the existing `m.mentions` object
|
||||
is filled for replies.
|
||||
|
||||
@ -0,0 +1,183 @@
|
||||
# MSC4147: Including device keys with Olm-encrypted to-device messages
|
||||
|
||||
Summary: a proposal to ensure that messages sent from a short-lived (but
|
||||
genuine) device can be securely distinguished from those sent from a spoofed
|
||||
device.
|
||||
|
||||
## Background
|
||||
|
||||
When a Matrix client receives an encrypted message, it is necessary to
|
||||
establish whether that message was sent from a device genuinely belonging to
|
||||
the apparent sender, or from a spoofed device (for example, a device created by
|
||||
an attacker with access to the sender's account such as a malicious server
|
||||
admin, or a man-in-the-middle).
|
||||
|
||||
In short, this is done by requiring a signature on the sending device's device
|
||||
keys from the sending user's [self-signing cross-signing
|
||||
key](https://spec.matrix.org/v1.12/client-server-api/#cross-signing). Such a
|
||||
signature proves that the sending device was genuine.
|
||||
|
||||
Current client implementations check for such a signature by
|
||||
[querying](https://spec.matrix.org/v1.12/client-server-api/#post_matrixclientv3keysquery)
|
||||
the sender's device keys when an encrypted message is received.
|
||||
|
||||
However, this does not work if the sending device logged out in the time
|
||||
between sending the message and it being received. This is particularly likely
|
||||
if the recipient is offline for a long time. In such a case, the sending server
|
||||
will have forgotten the sending device (and any cross-signing signatures) by
|
||||
the time the recipient queries for it. This makes the received message
|
||||
indistinguishable from one sent from a spoofed device.
|
||||
|
||||
Current implementations work around this by displaying a warning such as "sent
|
||||
by a deleted or unknown device" against the received message, but such
|
||||
messaging is unsatisfactory: a message should be either trusted or not.
|
||||
|
||||
We propose to solve this by including a copy of the device keys in the
|
||||
Olm-encrypted message, along with the cross-signing signatures, so that the
|
||||
recipient does not have to try to query the sender's keys.
|
||||
|
||||
## Proposal
|
||||
|
||||
The plaintext payload of to-device messages encrypted with the [`m.olm.v1.curve25519-aes-sha2` encryption
|
||||
algorithm](https://spec.matrix.org/v1.12/client-server-api/#molmv1curve25519-aes-sha2)
|
||||
is currently of the form:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "<type of the plaintext event>",
|
||||
"content": "<content for the plaintext event>",
|
||||
"sender": "<sender_user_id>",
|
||||
"recipient": "<recipient_user_id>",
|
||||
"recipient_keys": {
|
||||
"ed25519": "<our_ed25519_key>"
|
||||
},
|
||||
"keys": {
|
||||
"ed25519": "<sender_ed25519_key>"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
We propose to add a new property: `sender_device_keys`, which is a copy of what
|
||||
the server would return in response to a
|
||||
[`/keys/query`](https://spec.matrix.org/v1.12/client-server-api/#post_matrixclientv3keysquery)
|
||||
request, as the device keys for the sender's device. In other words, the
|
||||
plaintext payload will now look something like:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "<type of the plaintext event>",
|
||||
"content": "<content for the plaintext event>",
|
||||
"sender": "<sender_user_id>",
|
||||
"recipient": "<recipient_user_id>",
|
||||
"recipient_keys": {
|
||||
"ed25519": "<our_ed25519_key>"
|
||||
},
|
||||
"keys": {
|
||||
"ed25519": "<sender_ed25519_key>"
|
||||
},
|
||||
"sender_device_keys": {
|
||||
"algorithms": ["<supported>", "<algorithms>"],
|
||||
"user_id": "<user_id>",
|
||||
"device_id": "<device_id>",
|
||||
"keys": {
|
||||
"ed25519:<device_id>": "<sender_ed25519_key>",
|
||||
"curve25519:<device_id>": "<sender_curve25519_key>"
|
||||
},
|
||||
"signatures": {
|
||||
"<user_id>": {
|
||||
"ed25519:<device_id>": "<device_signature>",
|
||||
"ed25519:<ssk_id>": "<ssk_signature>",
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
If this property is present, the `keys`.`ed25519` property of the plaintext
|
||||
payload must be the same as the `sender_device_keys`.`keys`.`ed25519:<DEVICEID>`
|
||||
property. If they differ, the recipient should discard the event.
|
||||
|
||||
As the `keys` property is now redundant, it may be removed in a future version
|
||||
of the Matrix specification.
|
||||
|
||||
## Potential issues
|
||||
|
||||
Adding this property will increase the size of the to-device message. We found it
|
||||
increased the length of a typical encrypted `m.room_key` message from about 1400 to 2400
|
||||
bytes (a 70% increase). This will require increased storage on the recipient
|
||||
homeserver, and increase bandwidth for both senders and recipients. See
|
||||
[Alternatives](#alternatives) for discussion of mitigation strategies.
|
||||
|
||||
This proposal is not a complete solution. In particular, if the sender resets
|
||||
their cross-signing keys, and also logs out the sending device, the recipient
|
||||
still has no way to verify the sending device. The device signature in the Olm
|
||||
message is meaningless. A full solution would require the recipient to be able
|
||||
to obtain a history of cross-signing key changes, and to expose that
|
||||
information to the user; that is left for the future.
|
||||
|
||||
## Alternatives
|
||||
|
||||
### Minor variations
|
||||
|
||||
The `sender_device_keys` property could be added to the cleartext. That is, it could
|
||||
be added as a property to the `m.room.encrypted` event. This information is
|
||||
already public, as it is accessible from `/keys/query` (while the device is
|
||||
logged in), and does not need to be authenticated as it is protected by the
|
||||
self-signing signature, so it does not seem to need to be encrypted. However,
|
||||
there seems to be little reason not to encrypt the information. In addition, by
|
||||
including it in the encrypted payload, it leaves open the possibility of
|
||||
it replacing the `keys` property, which must be part of the encrypted payload
|
||||
to prevent an [unknown key-share attack](https://github.com/element-hq/element-web/issues/2215).
|
||||
|
||||
The `sender_device_keys` property could be added to the cleartext by the sender's
|
||||
homeserver, rather than by the sending client. Possibly within an `unsigned`
|
||||
property, as that is where properties added by homeservers are customarily
|
||||
added. It is not clear what advantage there would be to having this
|
||||
information being added by the client.
|
||||
|
||||
To mitigate the increased size of to-device events under this proposal, the
|
||||
`sender_device_keys` could be sent only in pre-key messages (Olm messages
|
||||
with `type: 0` in the `m.room.encrypted` event) — with the rationale that if
|
||||
the Olm message is a normal (non-pre-key) message, this means that the
|
||||
recipient has already decrypted a pre-key message that contains the
|
||||
information, and so does not need to be re-sent the information), or if the
|
||||
signatures change (for example, if the sender resets their cross-signing keys),
|
||||
or if the sender has not yet sent their `device_keys`. However, this requires
|
||||
additional bookkeeping, and it is not clear whether this extra complexity is
|
||||
worth the reduction in bandwidth.
|
||||
|
||||
### Alternative approach
|
||||
|
||||
A more radical proposal to decrease the overhead in to-device messages is to
|
||||
instead specify that `/keys/query` must include deleted devices as well as
|
||||
active ones, so that they can be reliably queried. Since the origin server
|
||||
might be unreachable at the time the recipient receives the message, such
|
||||
device lists would need to be cached on the recipient homeserver.
|
||||
|
||||
In other words, this approach would require all homeservers to keep a permanent
|
||||
record of all devices observed anywhere in the federation, at least for as long
|
||||
as there are undelivered to-device events from such devices.
|
||||
|
||||
Transparently: we have not significantly explored this approach. We have a
|
||||
working solution, and it is unclear that the advantages of this alternative
|
||||
approach outweigh the opportunity cost and delay in rollout of an important
|
||||
security feature. If, in future, the overhead of including the device keys
|
||||
in the to-device messages is found to be significant, it would be worth
|
||||
revisiting this.
|
||||
|
||||
## Security considerations
|
||||
|
||||
If a device is logged out, there is no indication why it was logged out. For
|
||||
example, an attacker could steal a device and use it send a message. The user,
|
||||
upon realizing that the device has been stolen, could log out the device, but
|
||||
the message may still be sent, if the user does not notice the message and
|
||||
redact it.
|
||||
|
||||
## Unstable prefix
|
||||
|
||||
Until this MSC is accepted, the new property should be named
|
||||
`org.matrix.msc4147.device_keys`.
|
||||
|
||||
## Dependencies
|
||||
|
||||
None
|
||||
@ -0,0 +1,117 @@
|
||||
# MSC4151: Reporting rooms (Client-Server API)
|
||||
|
||||
The specification [already contains](https://spec.matrix.org/v1.10/client-server-api/#reporting-content)
|
||||
a module for being able to report events, though this functionality does not extend to rooms. Being
|
||||
able to report rooms is important for user safety: clients have room directories, invite lists,
|
||||
links to rooms, etc which all don't have an event ID to reference. If the client has *any* event ID
|
||||
for the room, it can use the existing 'report event' API to report the room instead. However, this
|
||||
only works if the user has visibility on the event ID being reported too.
|
||||
|
||||
These constraints are in addition to the legal obligations of clients to provide a safe user experience.
|
||||
In some countries, such as the UK, it is required that users be able to report *any* kind of content
|
||||
they see, and some app stores require similar reporting functionality for mobile apps. These obligations
|
||||
impose further obligations not discussed in this proposal. For example, actually handling the reports
|
||||
and informing the reporter how long it will take to process their request. These obligations are
|
||||
expected to be discussed in a future, larger, MSC series which revamps reporting in Matrix.
|
||||
|
||||
This proposal introduces an endpoint for reporting rooms, expanding the capabilities of the reporting
|
||||
module. The scope of this proposal is intentionally narrow to ensure quick traversal of the MSC process.
|
||||
Other, future, MSCs may further expand the suite of endpoints available to clients (like reporting
|
||||
users, media, etc).
|
||||
|
||||
## Proposal
|
||||
|
||||
Taking inspiration from [`POST /rooms/:roomId/report/:eventId`](https://spec.matrix.org/v1.10/client-server-api/#post_matrixclientv3roomsroomidreporteventid),
|
||||
a new endpoint is introduced:
|
||||
|
||||
```
|
||||
POST /_matrix/client/v3/rooms/:roomId/report
|
||||
{
|
||||
"reason": "<user-supplied, optional>"
|
||||
}
|
||||
```
|
||||
|
||||
`reason` is a human-readable string describing the reason for the report. The string may be blank,
|
||||
but *must* be provided (to align with `/report/:eventId`).
|
||||
|
||||
**Note**: `score` is not carried over from `/report/:eventId` because it has not proven useful. A
|
||||
future MSC may introduce it.
|
||||
|
||||
There are no restictions on who can report a room: knowing the room ID is sufficient. This is to
|
||||
ensure that results from the room directory, invites, links, etc can all be reported. If the room
|
||||
does not exist on the server, the endpoint returns `404 M_NOT_FOUND`. Otherwise, `200` with `{}` as
|
||||
a response body.
|
||||
|
||||
Like `/report/:eventId`, handling of the report is left as a deliberate implementation detail.
|
||||
|
||||
## Safety considerations
|
||||
|
||||
* Server admins may be exposed to harmful content through `reason`. This is an existing issue with
|
||||
the reporting module, and difficult to fix. Applications which expose report reasons of any kind
|
||||
are encouraged to place disclosures in the user experience path. For example, a page explaining
|
||||
that the tool may contain harmful content before allowing the user temporary access, or the use of
|
||||
spoiler tags on report reasons/content.
|
||||
|
||||
* Clients should hide rooms the user reports by default to both discourage duplicate reports and to
|
||||
remove the harmful content from the user's view, where possible. This may require filtering room
|
||||
directory responses and room lists for the user, or an "ignore room API" like [MSC3840](https://github.com/matrix-org/matrix-doc/pull/3840).
|
||||
|
||||
If the user is joined to a room, the client may wish to offer the user an option to leave the room.
|
||||
|
||||
* Users may report whole rooms instead of events in that room, particularly during a harmful content
|
||||
spam wave. Administrators and safety teams should be cautious to avoid shutting down or banning
|
||||
whole rooms, as the room may be legitimate otherwise. Automated decision making is not suggested
|
||||
for a similar reason.
|
||||
|
||||
* 'Report flooding' is more easily possible with this new endpoint, where many users report a room
|
||||
with the hope of getting it shut down/banned. Mentioned a few times in this proposal, automated
|
||||
decision making is not recommended for this endpoint to prevent consequences like this from
|
||||
happening.
|
||||
|
||||
## Potential issues
|
||||
|
||||
* Within the Trust & Safety environment, it is well known that `reason` alone is insufficient for an
|
||||
informed report. Self-triage categories and mandatory `reason` for some of those categories help
|
||||
improve a safety team's ability to handle a report. These features are not included in this proposal
|
||||
as they require further thought and consideration - a future MSC may expand (or even deprecate) the
|
||||
report endpoints to support this added information.
|
||||
|
||||
* Reports are not federated. This is considered an issue for another MSC, like [MSC3843](https://github.com/matrix-org/matrix-spec-proposals/pull/3843).
|
||||
|
||||
* Whether the local server is participating in a room is revealed through the new endpoint. The endpoint
|
||||
is only available to local users however, and other ways of finding out the same information may
|
||||
already be possible in Matrix (not verified). It is not immediately clear that disclosing this
|
||||
information to local clients would cause harm to the server or its users. A future reporting over
|
||||
federation proposal may wish to consider hiding the server's participation state, however.
|
||||
|
||||
## Alternatives
|
||||
|
||||
* Mentioned in the introduction, if a client has an event ID for something in the room, it can typically
|
||||
use the existing event report endpoint to report the room. For example, using the creation event,
|
||||
the user's own join event, or the most recent message in the room. This only works if the user is
|
||||
able to see that event in the room, and further only if the client even has an event ID. Areas of
|
||||
the client like the room directory do not expose an event ID the client could use. If they did, the
|
||||
user may not have sufficient visibility on the event to be able to report it.
|
||||
|
||||
* The event report API could be relaxed to support an empty string for the event ID, though this feels
|
||||
effectively like a new endpoint anyways. This MSC introduces such an endpoint.
|
||||
|
||||
* The event report API's history visibility check could also be removed, though, as per
|
||||
[MSC2249](https://github.com/matrix-org/matrix-spec-proposals/blob/main/proposals/2249-report-require-joined.md),
|
||||
this is intentional behaviour.
|
||||
|
||||
## Security considerations
|
||||
|
||||
* Rate limiting is strongly recommended for this new endpoint.
|
||||
|
||||
* Authentication is required for this new endpoint.
|
||||
|
||||
## Unstable prefix
|
||||
|
||||
While this proposal is not considered stable, implementations should use `/_matrix/client/unstable/org.matrix.msc4151/rooms/:roomId/report`
|
||||
instead. Clients should note the [`M_UNRECOGNIZED` behaviour](https://spec.matrix.org/v1.10/client-server-api/#common-error-codes)
|
||||
for servers which do not support the (un)stable endpoint.
|
||||
|
||||
## Dependencies
|
||||
|
||||
This MSC has no direct dependencies.
|
||||
@ -0,0 +1,64 @@
|
||||
# MSC4156: Migrate `server_name` to `via`
|
||||
|
||||
Room IDs in Matrix are generally not routable on their own. In the [room ID grammar] `!opaque_id:domain`,
|
||||
the `domain` is the server that created the room. There is, however, no guarantee that this server is
|
||||
still joined to the room at a later time. Therefore, room IDs don't provide a reliable resident server
|
||||
to send requests to. Critically, the `domain` is not to be used as a routing server. It is purely a namespace.
|
||||
|
||||
The spec partially addresses this issue by defining a [`via`] query parameter on room URIs that can be
|
||||
used to list servers that have a high probability of being in the room in the distant future. Additionally,
|
||||
some APIs such as [`/_matrix/client/v3/join/{roomIdOrAlias}`] can take a `server_name` query parameter
|
||||
that has the same effect as `via`.
|
||||
|
||||
The terminology difference between `server_name` and `via` can be slightly confusing which is why this
|
||||
proposal attempts to standardize on `via`.
|
||||
|
||||
|
||||
## Proposal
|
||||
|
||||
The `server_name` query parameter on [`/_matrix/client/v3/join/{roomIdOrAlias}`] and
|
||||
[`/_matrix/client/v3/knock/{roomIdOrAlias}`] is deprecated and a new parameter `via: [string]` is
|
||||
introduced.
|
||||
|
||||
Clients SHOULD use `via` when the homeserver they're talking to supports it. To do this, they MAY either
|
||||
detect server support through the supported spec versions in [`/_matrix/client/versions`] or always include
|
||||
both parameters (with identical values).
|
||||
|
||||
Homeservers MUST ignore all `server_name` parameters if any `via` parameters are supplied.
|
||||
|
||||
|
||||
## Potential issues
|
||||
|
||||
As with any migration, some effort will be required to update client and server implementations. Additionally,
|
||||
while the transitions isn't completed, the concurrent existence of both query parameters might lead to further
|
||||
confusion.
|
||||
|
||||
|
||||
## Alternatives
|
||||
|
||||
None other than accepting status quo.
|
||||
|
||||
|
||||
## Security considerations
|
||||
|
||||
A client that supplies different `via` and `server_name` parameters could be served a different room depending
|
||||
on which set of parameters the server uses to resolve the room ID. Tricking a client into doing this seems very
|
||||
difficult though because [Matrix URIs], for instance, only have a single documented `via` parameter.
|
||||
|
||||
|
||||
## Unstable prefix
|
||||
|
||||
Until this proposal is accepted into the spec, implementations SHOULD refer to `via` as `org.matrix.msc4156.via`.
|
||||
|
||||
|
||||
## Dependencies
|
||||
|
||||
None.
|
||||
|
||||
|
||||
[Matrix URIs]: https://spec.matrix.org/v1.11/appendices/#matrix-uri-scheme
|
||||
[room ID grammar]: https://spec.matrix.org/v1.10/appendices/#room-ids
|
||||
[`via`]: https://spec.matrix.org/v1.10/appendices/#routing
|
||||
[`/_matrix/client/v3/join/{roomIdOrAlias}`]: https://spec.matrix.org/v1.10/client-server-api/#post_matrixclientv3joinroomidoralias
|
||||
[`/_matrix/client/v3/knock/{roomIdOrAlias}`]: https://spec.matrix.org/v1.10/client-server-api/#post_matrixclientv3knockroomidoralias
|
||||
[`/_matrix/client/versions`]: https://spec.matrix.org/v1.10/client-server-api/#get_matrixclientversions
|
||||
@ -0,0 +1,73 @@
|
||||
# MSC4159: Remove the deprecated name attribute on HTML anchor elements
|
||||
|
||||
Some message types in `m.room.message`, such as `m.text`, permit including HTML in the event content.
|
||||
The spec [recommends] that clients limit the HTML they render to prevent attacks and provides a list
|
||||
of permitted HTML tags and attributes. In particular, it allows using the `name` attribute on `a` tags.
|
||||
This attribute is obsolete according to the [WHATWG HTML Living Standard] which is why this proposal
|
||||
attempts to remove it from the spec.
|
||||
|
||||
|
||||
## Proposal
|
||||
|
||||
The `name` attribute was originally introduced to define targets for linking to specific parts of a
|
||||
webpage. As an example, including the named anchor `<a name="foo">bar</a>` on a site allows you to append
|
||||
the fragment `#foo` to the URL to cause your browser to scroll the anchor into view after loading the page.
|
||||
|
||||
In modern versions of HTML this feature has been superseded by the `id` attribute which extends targeted
|
||||
linking to more than just `a` tags. As a result, the `name` attribute is marked deprecated in [MDN].
|
||||
|
||||
> Was required to define a possible target location in a page. In HTML 4.01, `id` and `name` could
|
||||
> both be used on `<a>`, as long as they had identical values.
|
||||
>
|
||||
> Note: Use the global attribute `id` instead.
|
||||
|
||||
Furthermore, it is also tracked as [obsolete but conforming] in WHATWG.
|
||||
|
||||
> Authors should not specify the `name` attribute on `a` elements. If the attribute is present, its value
|
||||
> must not be the empty string and must neither be equal to the value of any of the IDs in the element's
|
||||
> tree other than the element's own ID, if any, nor be equal to the value of any of the other `name`
|
||||
> attributes on `a` elements in the element's tree. If this attribute is present and the element has an ID,
|
||||
> then the attribute's value must be equal to the element's ID. In earlier versions of the language, this
|
||||
> attribute was intended as a way to specify possible targets for fragments in URLs. The `id` attribute
|
||||
> should be used instead.
|
||||
|
||||
On top of the deprecation of the `name` attribute in HTML, it is unclear what this feature would ever have
|
||||
been used for in the context of Matrix. It appears highly undesirable to let events define targeted links
|
||||
into a client's UI, not least because the value of the `name` attribute would need to be unique on the
|
||||
entire page. Additionally, linking to specific events is already possible via [matrix.to URIs].
|
||||
|
||||
Therefore, the `name` attributed is removed from the list of permitted attributes on `a` tags without a
|
||||
replacement.
|
||||
|
||||
|
||||
## Potential issues
|
||||
|
||||
Use cases that currently depend on the `name` attribute will be broken once the attribute is removed from
|
||||
the allowed list. No concrete use cases are known as of writing, however.
|
||||
|
||||
|
||||
## Alternatives
|
||||
|
||||
None.
|
||||
|
||||
|
||||
## Security considerations
|
||||
|
||||
None.
|
||||
|
||||
|
||||
## Unstable prefix
|
||||
|
||||
None.
|
||||
|
||||
|
||||
## Dependencies
|
||||
|
||||
None.
|
||||
|
||||
|
||||
[MDN]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#name
|
||||
[WHATWG HTML Living Standard]: https://html.spec.whatwg.org/
|
||||
[matrix.to URIs]: https://spec.matrix.org/v1.10/appendices/#matrixto-navigation
|
||||
[obsolete but conforming]: https://html.spec.whatwg.org/#obsolete-but-conforming-features
|
||||
[recommends]: https://spec.matrix.org/v1.10/client-server-api/#mroommessage-msgtypes
|
||||
@ -0,0 +1,46 @@
|
||||
# MSC4163: Make ACLs apply to EDUs
|
||||
|
||||
[Access Control Lists](https://spec.matrix.org/v1.11/client-server-api/#server-access-control-lists-acls-for-rooms)
|
||||
(also known as ACLs) are used to prevent other servers from participating in a room at a federation level,
|
||||
covering many federation API endpoints, including
|
||||
[`/send`](https://spec.matrix.org/v1.11/server-server-api/#put_matrixfederationv1sendtxnid). However, while ACLs
|
||||
are applied on a per-PDU basis on this endpoint, they are not applied to EDUs at all. Considering that some EDUs
|
||||
are specific to certain rooms (e.g. read receipts & typing indicators), it makes sense to apply ACLs to them as well.
|
||||
|
||||
|
||||
## Proposal
|
||||
|
||||
All EDUs which are local to a specific room MUST have ACLs applied to them. This means that for the EDUs currently
|
||||
in the spec, ACLs would only apply to receipts and typing notifications. Examples of how ACLs should be enforced
|
||||
at the point of receiving a transaction for those two types of EDUs are as follows:
|
||||
- For
|
||||
[typing notifications (`m.typing`)](https://spec.matrix.org/v1.11/server-server-api/#typing-notifications),
|
||||
the `room_id` field inside `content` should be checked, with the typing notification ignored if the `origin`
|
||||
of the request is a server which is forbidden by the room's ACL. Ignoring the typing notification means that the EDU
|
||||
MUST be dropped upon receipt.
|
||||
- For [read receipts (`m.receipt`)](https://spec.matrix.org/v1.11/server-server-api/#receipts), all receipts
|
||||
inside a `room_id` inside `content` should be ignored if the `origin` of the request is forbidden by the
|
||||
room's ACL.
|
||||
|
||||
## Potential issues
|
||||
|
||||
None considered.
|
||||
|
||||
## Alternatives
|
||||
|
||||
Leave things as-is, which wouldn't be that big of a deal when you consider that this would only apply
|
||||
to typing notifications and read receipts currently, which don't allow for very significant disruption inside
|
||||
a room. However, as ACLs are meant to prevent certain servers from participating in a room at all, it makes
|
||||
sense to apply ACLs to EDUs which are local to certain rooms, as they are a form of participation.
|
||||
|
||||
## Security considerations
|
||||
|
||||
None considered.
|
||||
|
||||
## Unstable prefix
|
||||
|
||||
None required, as no new fields or endpoints are added.
|
||||
|
||||
## Dependencies
|
||||
|
||||
None.
|
||||
@ -0,0 +1,133 @@
|
||||
# MSC4170: 403 error responses for profile APIs
|
||||
|
||||
Matrix currently defines the following [client-server APIs] for profile look-ups:
|
||||
|
||||
- [`GET /_matrix/client/v3/profile/{userId}`]
|
||||
- [`GET /_matrix/client/v3/profile/{userId}/avatar_url`]
|
||||
- [`GET /_matrix/client/v3/profile/{userId}/displayname`]
|
||||
|
||||
These endpoints also support look-up over federation via the accompanying
|
||||
[server-server API]:
|
||||
|
||||
- [`GET /_matrix/federation/v1/query/profile`]
|
||||
|
||||
Each of these endpoints has a documented 404 response for the case that no profile
|
||||
information is available.
|
||||
|
||||
> 404 There is no profile information for this user or this user does not exist.
|
||||
>
|
||||
> 404 There is no avatar URL for this user or this user does not exist.
|
||||
>
|
||||
> 404 There is no display name for this user or this user does not exist.
|
||||
>
|
||||
> 404 The user does not exist or does not have a profile.
|
||||
|
||||
However, `GET /_matrix/client/v3/profile/{userId}` additionally reserves a 403
|
||||
status code that is not available on the other endpoints and can be used to deny
|
||||
profile look-ups.
|
||||
|
||||
> 403 The server is unwilling to disclose whether the user exists and/or has profile information.
|
||||
|
||||
Unfortunately, the concrete semantics of when to respond with 403 are not fully
|
||||
spelled out in the spec and understanding prior proposals' intention requires some
|
||||
archeology (see the history section below).
|
||||
|
||||
The current proposal aims to restore consistency among the profile endpoints
|
||||
by standardizing their 403 error response format and behaviour.
|
||||
|
||||
|
||||
## Proposal
|
||||
|
||||
For the endpoints in the client-server API
|
||||
|
||||
- [`GET /_matrix/client/v3/profile/{userId}`]
|
||||
- [`GET /_matrix/client/v3/profile/{userId}/avatar_url`]
|
||||
- [`GET /_matrix/client/v3/profile/{userId}/displayname`]
|
||||
|
||||
homeservers MUST at a minimum allow profile look-up for users that either share a room
|
||||
with the requester or reside in a public room known to the homeserver (i.e, the same
|
||||
requirements as [`POST /_matrix/client/v3/user_directory/search`])[^3]. In all other
|
||||
cases, homeservers MAY deny profile look-up by responding with 403 `M_FORBIDDEN`.
|
||||
|
||||
If a remote user is queried through the client-server endpoints and the query is not
|
||||
denied per the preceding paragraph, homeservers SHOULD query the remote server for the
|
||||
user's profile information.
|
||||
|
||||
Homeservers MAY deny profile look-up over federation by responding with 403 `M_FORBIDDEN`
|
||||
to [`GET /_matrix/federation/v1/query/profile`]. To be clear: there is no requirement to return
|
||||
profiles of users in public or shared rooms over the federation API.
|
||||
|
||||
Homeservers MAY choose whether to respond with 403 or 404 when the requested user does
|
||||
not exist. If the server denies profile look-up in all but the required cases, 403 is
|
||||
RECOMMENDED.
|
||||
|
||||
|
||||
## Potential issues
|
||||
|
||||
Synapse already complies with this proposal in its default configuration. However,
|
||||
its `limit_profile_requests_to_users_who_share_rooms` config setting is only partially
|
||||
compatible with this proposal because it disallows profile look-up for users in public
|
||||
rooms that the requester does not share a room with. This inconsistency would need to
|
||||
be fixed if this proposal is accepted into the spec.
|
||||
|
||||
|
||||
## Alternatives
|
||||
|
||||
None.
|
||||
|
||||
|
||||
## Security considerations
|
||||
|
||||
This proposal allows server administrators to lock down profile look-ups via the
|
||||
client-server API for all situations except those in which the profile information
|
||||
is already available to the requester via room membership. This complements the
|
||||
existing ability to deny profile look-ups on the server-server API and, if configured
|
||||
accordingly, increases privacy for users.
|
||||
|
||||
|
||||
## History
|
||||
|
||||
In [2017], the user directory API, [`POST /_matrix/client/v3/user_directory/search`],
|
||||
which closely relates to the profile APIs, was introduced into the spec. Since its
|
||||
inception, it contained the requirement for servers to consider (at least) users from
|
||||
shared and public rooms in the search.
|
||||
|
||||
Later, [MSC1301] proposed a 403 `M_USER_NOT_PUBLIC` response on all four profile
|
||||
endpoints to optionally disallow profile look-up for users that the requester does
|
||||
not share a room with. This MSC was never accepted, but in 2019
|
||||
was partially implemented by Synapse[^1]: it was only implemented for the client-server
|
||||
endpoints, and an error code of `M_FORBIDDEN` was used rather than `M_USER_NOT_PUBLIC`.
|
||||
|
||||
In 2021, Synapse implemented[^2] a switchable feature to disable profile look-up
|
||||
over federation via a 403 `M_FORBIDDEN` response. [MSC3550] picked up on this
|
||||
feature and introduced this response type in the spec though only on the
|
||||
`GET /_matrix/client/v3/profile/{userId}` endpoint in the client-server API.
|
||||
|
||||
|
||||
## Unstable prefix
|
||||
|
||||
None because this proposal only affects HTTP status codes and Matrix error codes.
|
||||
|
||||
|
||||
## Dependencies
|
||||
|
||||
None.
|
||||
|
||||
|
||||
[^1]: https://github.com/element-hq/synapse/commit/c0e0740bef0db661abce352afaf6c958e276f11d
|
||||
[^2]: https://github.com/matrix-org/synapse/pull/9203/files#diff-2f70c35b9dd342bfdaaed445847e0ccabbad63aa9a208d80d38fb248cbf57602L311
|
||||
[^3]: As stated in https://github.com/matrix-org/matrix-spec/issues/633, the spec currently
|
||||
doesn't clearly define what a public room is. This proposal does not aim to solve this
|
||||
problem and instead only requires that the user directory and profile APIs use the same
|
||||
definition.
|
||||
|
||||
[`GET /_matrix/client/v3/profile/{userId}`]: https://spec.matrix.org/v1.11/client-server-api/#get_matrixclientv3profileuserid
|
||||
[`GET /_matrix/client/v3/profile/{userId}/avatar_url`]: https://spec.matrix.org/v1.11/client-server-api/#get_matrixclientv3profileuseridavatar_url
|
||||
[`GET /_matrix/client/v3/profile/{userId}/displayname`]: https://spec.matrix.org/v1.11/client-server-api/#get_matrixclientv3profileuseriddisplayname
|
||||
[`GET /_matrix/federation/v1/query/profile`]: https://spec.matrix.org/v1.11/server-server-api/#get_matrixfederationv1queryprofile
|
||||
[`POST /_matrix/client/v3/user_directory/search`]: https://spec.matrix.org/v1.11/client-server-api/#post_matrixclientv3user_directorysearch
|
||||
[2017]: https://github.com/matrix-org/matrix-spec-proposals/pull/1096/files#diff-332ce28a7277b9375050644632f99c0e606acb751adc54c64c5faabf981ac7edR35
|
||||
[MSC1301]: https://github.com/matrix-org/matrix-spec-proposals/issues/1301
|
||||
[MSC3550]: https://github.com/matrix-org/matrix-spec-proposals/pull/3550
|
||||
[client-server APIs]: https://spec.matrix.org/v1.11/client-server-api/#profiles
|
||||
[server-server API]: https://spec.matrix.org/v1.11/server-server-api/#get_matrixfederationv1queryprofile
|
||||
@ -0,0 +1,148 @@
|
||||
# MSC4175: Profile field for user time zone
|
||||
|
||||
Knowing another user's time zone is useful for knowing whether they are likely
|
||||
to respond or not. Example uses include:
|
||||
|
||||
* Showing a user's time zone or time zone offset directly.
|
||||
* Showing a user's local time (with hints of whether it is day or night there).
|
||||
|
||||
|
||||
## Proposal
|
||||
|
||||
Profiles can provide an optional `m.tz` field with values equal to names from the
|
||||
[IANA Time Zone Database](https://www.iana.org/time-zones).
|
||||
Clients can set and fetch this via the [normal API endpoints](https://spec.matrix.org/v1.14/client-server-api/#profiles).
|
||||
|
||||
* Servers MAY validate that the value is a valid IANA time zone. If deemed invalid
|
||||
they MUST return a 400 error with error code `M_INVALID_PARAM`.
|
||||
* Clients MUST handle invalid or unknown values. One approach may be processing the value as though it was never set.
|
||||
|
||||
The rationale for somewhat loose validation is that different clients/servers may have
|
||||
different understanding of valid time zones, e.g. different versions of the time zone
|
||||
database.
|
||||
|
||||
If the field is not provided, it SHOULD be interpreted as having no time zone information
|
||||
for that user.
|
||||
|
||||
An example request to set the time zone would be:
|
||||
|
||||
```
|
||||
PUT /_matrix/client/v3/profile/@alice:example.org/m.tz
|
||||
|
||||
{
|
||||
"m.tz": "America/New_York"
|
||||
}
|
||||
```
|
||||
|
||||
Similarly when retrieving a user's profile:
|
||||
|
||||
```
|
||||
GET /_matrix/client/v3/profile/@alice:example.org
|
||||
|
||||
{
|
||||
"displayname": "Alice",
|
||||
"m.tz": "Europe/Paris"
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Potential issues
|
||||
|
||||
Clients may need to understand IANA time zone names to show useful information to users.
|
||||
Some languages make this easy, e.g. JavaScript can handle this using
|
||||
[`Date.toLocaleString()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toLocaleString).
|
||||
This may cause clients to bundle the IANA time zone database (and thus also keep it
|
||||
up to date).
|
||||
|
||||
Using the IANA time zone name has the downside that it does now allow arbitrary offsets,
|
||||
which may be required for time zones which are not internationally recognized.
|
||||
|
||||
Clients will need to manually update the profile field when the user changes time zone.
|
||||
This could be automated by clients based on location, or left as a manual change to
|
||||
users.
|
||||
|
||||
Clients may wish to periodically fetch the time zone of other users as it is
|
||||
liable to change somewhat frequently. Currently, profile data isn't propagated/synchronized
|
||||
between servers, but that's left to a future MSC to solve. It is recommended that
|
||||
clients cache the value for 12 - 24 hours.
|
||||
|
||||
There should not be backwards compatibility concerns since clients should be ignoring
|
||||
unknown profile fields.
|
||||
|
||||
|
||||
## Alternatives
|
||||
|
||||
The time zone offset could be included directly (in minutes/seconds or in `[+-]HH:MM` form).
|
||||
This would require clients to manually update the profile field during daylight
|
||||
savings. Using the IANA time zone name is robust against this.
|
||||
|
||||
|
||||
### Delegate profile fields
|
||||
|
||||
There are several standards related to storing of contact information electronically,
|
||||
notably vCard and its derivatives (see below). It is unclear if Matrix profile
|
||||
information is similar enough to the contact information found in vCard to warrant using
|
||||
that format directly, although there is certainly some overlap.
|
||||
|
||||
Some of the JSON formats for vCard which include time zone information are detailed below:
|
||||
|
||||
[RFC7095: jCard The JSON Format for vCard](https://datatracker.ietf.org/doc/html/rfc7095)
|
||||
format could be used instead, but this doesn't make much sense unless the entire
|
||||
profile was replaced.
|
||||
|
||||
[RFC9553](https://datatracker.ietf.org/doc/html/rfc9553) offers an alternative
|
||||
representation for contacts (which is not backwards compatible with vCard). There
|
||||
exists `timeZone` field under the `addresses` field which uses an time zone name
|
||||
from the IANA Time Zone Database.
|
||||
|
||||
Note there's an alternative [jCard](https://microformats.org/wiki/jCard) format
|
||||
which is a non-standard derivative of [hCard](https://microformats.org/wiki/hcard).
|
||||
|
||||
|
||||
### Competitive analysis
|
||||
|
||||
Slack's [`users.info` API call](https://api.slack.com/methods/users.info) includes
|
||||
3 separate fields:
|
||||
|
||||
* `tz`: the time zone database name (e.g. `"America/New_York"`)
|
||||
* `tz_label`: a friendly name (e.g. `"Eastern Daylight Time"`)
|
||||
* `tz_offset`: offset in seconds as an integer (e.g. `-14400`)
|
||||
|
||||
XMPP uses either:
|
||||
|
||||
* [XEP-054](https://xmpp.org/extensions/xep-0054.html) uses vCard
|
||||
([RFC2426](https://datatracker.ietf.org/doc/html/rfc2426)) converted to XML via
|
||||
[draft-dawson-vcard-xml-dtd-01](https://datatracker.ietf.org/doc/html/draft-dawson-vcard-xml-dtd-01)
|
||||
* [XEP-0292](https://xmpp.org/extensions/xep-0292.html) uses xCard: vCard XML Representation
|
||||
([RFC6351](https://datatracker.ietf.org/doc/html/rfc6351)), see also vCard4
|
||||
([RFC6351](https://datatracker.ietf.org/doc/html/rfc6351))
|
||||
|
||||
Rocket.Chat provides a user's [time zone offset](https://developer.rocket.chat/docs/user)
|
||||
in the `utcOffset` field.
|
||||
|
||||
Mattermost [returns an object](https://api.mattermost.com/#tag/users/operation/GetUser)
|
||||
with the user's manual and/or automatic IANA time zone name.
|
||||
|
||||
Discord, Twitter, and IRC don't provide a user's time zone.
|
||||
|
||||
|
||||
## Security considerations
|
||||
|
||||
Showing a user's time zone gives some information to their location. There is currently
|
||||
no way to limit what profile fields other users can see.
|
||||
|
||||
Clients may wish to warn users when providing a time zone and give
|
||||
the option to not include it in their profile.
|
||||
|
||||
|
||||
## Unstable prefix
|
||||
|
||||
`us.cloke.msc4175.tz` should be used in place of `m.tz`.
|
||||
|
||||
Clients may immediately use the stable profile field once this MSC is accepted. This is
|
||||
a client-to-client protocol and no feature negotiation is necessary.
|
||||
|
||||
|
||||
## Dependencies
|
||||
|
||||
Requires [MSC4133](https://github.com/matrix-org/matrix-spec-proposals/pull/4133).
|
||||
@ -0,0 +1,46 @@
|
||||
# MSC4178: Error codes for requestToken
|
||||
|
||||
There are a number of ways that sending a token to validate a third party identifier can go wrong.
|
||||
The requestToken API, however, has a very limited number of error codes that it can return.
|
||||
|
||||
Firstly, homeservers may not always support adding email addresses or phone numbers to a user's account,
|
||||
however, there is no error code to signal this situation. Synapse currently returns `M_UNKNOWN`
|
||||
which leads to bad, untranslatable error messages.
|
||||
|
||||
Secondly, the supplied third party identifier may be invalid.
|
||||
|
||||
## Proposal
|
||||
|
||||
Firstly, Add the `M_THREEPID_MEDIUM_NOT_SUPPORTED` code to be returned by both
|
||||
[`POST /account/3pid/email/requestToken`](https://spec.matrix.org/v1.11/client-server-api/#post_matrixclientv3account3pidemailrequesttoken)
|
||||
and
|
||||
[`POST /account/3pid/msisdn/requestToken`](https://spec.matrix.org/v1.11/client-server-api/#post_matrixclientv3account3pidmsisdnrequesttoken),
|
||||
defined to mean that the homeserver does not support adding a third party identifier of that medium.
|
||||
|
||||
Secondly, allow these endpoints to also return `M_INVALID_PARAM`, to indicate that the third party address
|
||||
was not valid for that medium (eg. not a valid phone number).
|
||||
|
||||
For both of these codes, HTTP status code 400 should be used.
|
||||
|
||||
## Potential issues
|
||||
|
||||
None foreseen.
|
||||
|
||||
## Alternatives
|
||||
|
||||
A better UX would be for servers to advertise what third party identifiers they support adding so that clients can
|
||||
inform users before they try to do so. This should be in addition rather than as alternative though: the clearest
|
||||
possible API will come from having both.
|
||||
|
||||
## Security considerations
|
||||
|
||||
None foreseen.
|
||||
|
||||
## Unstable prefix
|
||||
|
||||
This is sufficiently simple that proving it on a large scale is unnecessary. The code should not be used in the open
|
||||
before the MSC has been accepted.
|
||||
|
||||
## Dependencies
|
||||
|
||||
None
|
||||
@ -0,0 +1,81 @@
|
||||
# MSC4183: Additional Error Codes for submitToken endpoints
|
||||
|
||||
The [`POST
|
||||
/_matrix/identity/v2/validate/email/submitToken`](https://spec.matrix.org/v1.11/identity-service-api/#post_matrixidentityv2validateemailsubmittoken)
|
||||
and [`POST
|
||||
/_matrix/identity/v2/validate/msisdn/submitToken`](https://spec.matrix.org/v1.11/identity-service-api/#post_matrixidentityv2validatemsisdnsubmittoken)
|
||||
endpoints do not specify any specific error codes, instead relying on the common error codes defined in the identity
|
||||
service API.
|
||||
|
||||
However, these common error codes don't have any codes to signal many errors that can occur in these APIs: most
|
||||
obviously, that the token the user entered was incorrect.
|
||||
|
||||
This MSC can be considered similar to [MSC4178](https://github.com/matrix-org/matrix-spec-proposals/pull/4178) although
|
||||
that MSC is for `requestToken` on the C/S API only.
|
||||
|
||||
The numerous `requestToken` endpoints (enumerated in the proposal section) in the C/S API also specify a `submit_url`
|
||||
response parameter, defining their parameters to be the same as the Identity API's `submitToken` endpoints. Everything
|
||||
this MSC specifies applies to these endpoint in the same way.
|
||||
|
||||
Note that the `POST` version of the email `submitToken` endpoint ([`POST
|
||||
/_matrix/identity/v2/validate/email/submitToken`](https://spec.matrix.org/v1.11/identity-service-api/#post_matrixidentityv2validateemailsubmittoken))
|
||||
is not generally used in practice: Sydent's emails include a link to click instead of the `submit_url` response field and
|
||||
therefore use the `GET` version. Synapse does not implement the `POST` API for email validation for this reason. This
|
||||
proposal updates both `POST` and `GET` versions for consistency.
|
||||
|
||||
## Proposal
|
||||
|
||||
Add the following specific error code as a code that can be returned by both
|
||||
[`POST
|
||||
/_matrix/identity/v2/validate/email/submitToken`](https://spec.matrix.org/v1.11/identity-service-api/#post_matrixidentityv2validateemailsubmittoken)
|
||||
and [`POST
|
||||
/_matrix/identity/v2/validate/msisdn/submitToken`](https://spec.matrix.org/v1.11/identity-service-api/#post_matrixidentityv2validatemsisdnsubmittoken):
|
||||
* `M_TOKEN_INCORRECT`: Indicates that the token that the user entered to validate the session is incorrect.
|
||||
|
||||
Note that we deliberately chose not to re-use `M_UNKNOWN_TOKEN` since that refers to an access token, whereas this
|
||||
refers to a token that the user enters.
|
||||
|
||||
HTTP status code 400 should be used for this error.
|
||||
|
||||
Additionally specify that the following common error codes can be returned:
|
||||
* `M_INVALID_PARAM`: One of the supplied parameters in not valid.
|
||||
* `M_SESSION_EXPIRED`: The validation session is question has expired.
|
||||
|
||||
HTTP status code 400 should also be used for both of these errors.
|
||||
|
||||
Also apply the same change to the endpoints returned in the `submit_url` fields in the response to the various `POST requestToken` endpoints in the client-server API, i.e.:
|
||||
|
||||
* [`POST /_matrix/client/v3/register/email/requestToken`](https://spec.matrix.org/v1.11/client-server-api/#post_matrixclientv3registeremailrequesttoken)
|
||||
* [`POST /_matrix/client/v3/register/msisdn/requestToken`](https://spec.matrix.org/v1.11/client-server-api/#post_matrixclientv3registerrequesttoken)
|
||||
* [`POST /_matrix/client/v3/account/3pid/email/requestToken`](https://spec.matrix.org/v1.11/client-server-api/#post_matrixclientv3account3pidemailrequesttoken)
|
||||
* [`POST /_matrix/client/v3/account/3pid/msisdn/requestToken`](https://spec.matrix.org/v1.11/client-server-api/#post_matrixclientv3account3pidmsisdnrequesttoken)
|
||||
* [`POST /_matrix/client/v3/account/password/email/requestToken`](https://spec.matrix.org/v1.11/client-server-api/#post_matrixclientv3accountpasswordemailrequesttoken)
|
||||
* [`POST /_matrix/client/v3/account/password/msisdn/requestToken`](https://spec.matrix.org/v1.11/client-server-api/#post_matrixclientv3accountpasswordmsisdnrequesttoken)
|
||||
|
||||
...to specify that response parameters and error codes are the same as the I/S API version, as well as request parameters.
|
||||
|
||||
## Potential issues
|
||||
|
||||
None foreseen.
|
||||
|
||||
## Alternatives
|
||||
|
||||
None considered.
|
||||
|
||||
## Security considerations
|
||||
|
||||
None foreseen.
|
||||
|
||||
## Unstable prefix
|
||||
|
||||
No unstable prefix is deemed necessary. Sydent already sends the common error codes and also sends
|
||||
`M_NO_VALID_SESSION` if the code is incorrect. Once an identity server (or homeserver) switches to
|
||||
use the new error code, clients (including homeservers proxying the IS API) may not recognise the
|
||||
error condition correctly until updated to support the new code. We say that this is acceptable in
|
||||
favour of avoiding the complexity of negotiating error codes with API versions. Since the identity
|
||||
server is generally used via the homeserver now, most users of this API will not currently receive
|
||||
a sensible error code in this situation anyway.
|
||||
|
||||
## Dependencies
|
||||
|
||||
None
|
||||
@ -0,0 +1,53 @@
|
||||
# MSC4189: Allowing guests to access uploaded media
|
||||
|
||||
[MSC3916](https://github.com/matrix-org/matrix-spec-proposals/blob/main/proposals/3916-authentication-for-media.md)
|
||||
introduced new endpoints which require clients to provide a valid access token in order to access
|
||||
media. The MSC failed to specify [guest access](https://spec.matrix.org/v1.11/client-server-api/#guest-access)
|
||||
requirements for the new endpoints.
|
||||
|
||||
This MSC specifies the missing guest access requirements on the new endpoints.
|
||||
|
||||
## Proposal
|
||||
|
||||
The following endpoints explicitly permit guest access, joining the
|
||||
[list of other endpoints](https://spec.matrix.org/v1.11/client-server-api/#client-behaviour-13)
|
||||
already in the specification:
|
||||
|
||||
* [`GET /_matrix/client/v1/media/download/{serverName}/{mediaId}`](https://spec.matrix.org/v1.11/client-server-api/#get_matrixclientv1mediadownloadservernamemediaid)
|
||||
* [`GET /_matrix/client/v1/media/download/{serverName}/{mediaId}/{fileName}`](https://spec.matrix.org/v1.11/client-server-api/#get_matrixclientv1mediadownloadservernamemediaidfilename)
|
||||
* [`GET /_matrix/client/v1/media/thumbnail/{serverName}/{mediaId}`](https://spec.matrix.org/v1.11/client-server-api/#get_matrixclientv1mediathumbnailservernamemediaid)
|
||||
|
||||
The rationale for the above endpoints is that being able to see events without the associated media
|
||||
isn't very useful.
|
||||
|
||||
For clarity, the following endpoints are *not* added to the guest access list, as their prior (now
|
||||
deprecated) versions are not already included. A future MSC may change this with sufficient rationale.
|
||||
Note that guests cannot currently *upload* files, but can send messages/events.
|
||||
|
||||
* [`GET /_matrix/client/v1/media/config`](https://spec.matrix.org/v1.11/client-server-api/#get_matrixclientv1mediaconfig)
|
||||
* [`GET /_matrix/client/v1/media/preview_url`](https://spec.matrix.org/v1.11/client-server-api/#get_matrixclientv1mediapreview_url)
|
||||
|
||||
## Potential issues
|
||||
|
||||
This MSC fixes an issue where guests cannot download images/files.
|
||||
|
||||
## Alternatives
|
||||
|
||||
None applicable.
|
||||
|
||||
## Security considerations
|
||||
|
||||
This MSC does not materially increase the threat profile for guests: guests could already download
|
||||
media using the unauthenticated endpoints.
|
||||
|
||||
## Unstable prefix
|
||||
|
||||
Prefixed endpoints are excessive for this MSC. Implementations can enable guest access on the existing
|
||||
endpoints safely, or continue to respond with "guest access forbidden" errors. No `/versions` flag
|
||||
is specified for feature detection: clients with guest access tokens should expect failure until a
|
||||
server advertises a specification version containing this MSC. Clients should continue trying to make
|
||||
requests for the best user experience.
|
||||
|
||||
## Dependencies
|
||||
|
||||
This MSC has no dependencies.
|
||||
@ -0,0 +1,124 @@
|
||||
# MSC4190: Device management for application services
|
||||
|
||||
[MSC4326] gives appservices the ability to masquerade devices using the
|
||||
`device_id` query parameter on C-S API requests, which eliminates the need to
|
||||
maintain individual access tokens for each application service user.
|
||||
|
||||
However, application services don't have an endpoint to create devices for their
|
||||
users, which means that, in practice, encrypted application services still use
|
||||
`/login` with the `m.login.application_service` login type to create devices for
|
||||
their users.
|
||||
|
||||
Consequently, such application services leave many unused but active access
|
||||
tokens for those users.
|
||||
|
||||
Furthermore, the `/login` endpoint is no longer available for application services
|
||||
to use on servers that have switched to OAuth2 ([MSC3861]).
|
||||
|
||||
This MSC proposes a dedicated API endpoint for application services to create
|
||||
and delete devices for users, addressing the existing gap to enable encrypted
|
||||
application services without `/login`.
|
||||
|
||||
## Proposal
|
||||
|
||||
This MSC proposes to extend existing endpoints to allow application services to
|
||||
create and delete devices for their users without relying on the `/login` and
|
||||
`/logout` mechanisms.
|
||||
|
||||
As all changes here only apply to application services, guest access is not
|
||||
relevant.
|
||||
|
||||
### [**`PUT /_matrix/client/v3/devices/{deviceId}`**](https://spec.matrix.org/v1.16/client-server-api/#put_matrixclientv3devicesdeviceid)
|
||||
|
||||
This endpoint is updated to allow the creation of a new device for a user, if
|
||||
the device ID does not exist. This behavior is only available to application
|
||||
services.
|
||||
|
||||
This endpoint will use the 201 status code to indicate that a new device was
|
||||
created, in addition to the existing 200 status code for existing devices.
|
||||
|
||||
The endpoint is rate limited. Servers may want to use login rate limits for
|
||||
device creation, although in most cases application services will disable all
|
||||
rate limits anyway.
|
||||
|
||||
### [**`DELETE /_matrix/client/v3/devices/{deviceId}`**](https://spec.matrix.org/v1.16/client-server-api/#delete_matrixclientv3devicesdeviceid)
|
||||
|
||||
This endpoint no longer requires User-Interactive Authentication for application services.
|
||||
|
||||
### [**`POST /_matrix/client/v3/delete_devices`**](https://spec.matrix.org/v1.16/client-server-api/#post_matrixclientv3delete_devices)
|
||||
|
||||
This endpoint no longer requires User-Interactive Authentication for application services.
|
||||
|
||||
### [**`POST /_matrix/client/v3/keys/device_signing/upload`**](https://spec.matrix.org/v1.16/client-server-api/#post_matrixclientv3keysdevice_signingupload)
|
||||
|
||||
This endpoint no longer requires User-Interactive Authentication for application services,
|
||||
even if cross-signing keys already exist.
|
||||
|
||||
This is not technically a part of device management, but appservices will need
|
||||
to be able to verify themselves including generating cross-signing keys for
|
||||
[MSC4153] and replacing cross-signing keys is necessary in some cases (e.g. if
|
||||
the appservice recovery key is misplaced).
|
||||
|
||||
[MSC4153]: https://github.com/matrix-org/matrix-spec-proposals/pull/4153
|
||||
|
||||
### [**`POST /_matrix/client/v3/login`**](https://spec.matrix.org/v1.16/client-server-api/#post_matrixclientv3login)
|
||||
|
||||
Logins with the [`m.login.application_service` type] will return HTTP 400 with a
|
||||
new `M_APPSERVICE_LOGIN_UNSUPPORTED` error code if the homeserver has switched
|
||||
to OAuth2.
|
||||
|
||||
[`m.login.application_service` type]: https://spec.matrix.org/v1.16/client-server-api/#appservice-login
|
||||
|
||||
### [**`POST /_matrix/client/v3/register`**](https://spec.matrix.org/v1.16/client-server-api/#post_matrixclientv3register)
|
||||
|
||||
Currently, the default behavior for `/register` is to create a new device and
|
||||
access token (i.e. login) in addition to creating the user. Similar to `/login`,
|
||||
creating an access token is no longer possible on servers that have switched to
|
||||
OAuth2. However, creating users via the endpoint is still required, so unlike
|
||||
`/login`, `/register` will not be removed entirely.
|
||||
|
||||
Therefore, application services on homeservers that have switched to OAuth2
|
||||
MUST call the endpoint with `"inhibit_login": true`. Calls without the parameter,
|
||||
or with a different value than `true`, will return HTTP 400 with the
|
||||
`M_APPSERVICE_LOGIN_UNSUPPORTED` error code.
|
||||
|
||||
## Potential issues
|
||||
|
||||
The change to `/v3/register` is technically backwards-incompatible, but it will
|
||||
break when switching to next-gen auth in any case, so a new endpoint version
|
||||
would not be useful.
|
||||
|
||||
The endpoint could just stop returning access tokens to avoid breaking existing
|
||||
appservices that don't read that field, but an explicit error was chosen to
|
||||
avoid silent breakage of appservices that do depend on the field.
|
||||
|
||||
The breaking changes to `/login` and `/register` only apply to homeservers which
|
||||
have switched to OAuth2. Homeservers MAY have implementation-specific methods of
|
||||
opting into the breaking changes before switching to OAuth2 entirely to test
|
||||
compatibility.
|
||||
|
||||
## Security considerations
|
||||
|
||||
This MSC lets application services delete devices and replace cross-signing keys
|
||||
without the usual re-authentication requirement. It is considered an acceptable
|
||||
risk, as application services have to be registered by the server admin.
|
||||
|
||||
## Alternatives
|
||||
|
||||
A new set of endpoints dedicated to application services could be added to the
|
||||
specification, like `GET|PUT|DELETE /_matrix/client/v3/appservices/{appId}/devices/{deviceId}`.
|
||||
|
||||
This would have the advantage of not changing the behavior of existing endpoints.
|
||||
|
||||
## Dependencies
|
||||
|
||||
In order to use the devices created using this MSC, appservices need to be able
|
||||
to use device IDs as a part of identity assertion, as defined by [MSC4326].
|
||||
|
||||
## Unstable prefix
|
||||
|
||||
`IO.ELEMENT.MSC4190.M_APPSERVICE_LOGIN_UNSUPPORTED` should be used as the
|
||||
error code instead of `M_APPSERVICE_LOGIN_UNSUPPORTED`.
|
||||
|
||||
[MSC4326]: https://github.com/matrix-org/matrix-spec-proposals/pull/4326
|
||||
[MSC3861]: https://github.com/matrix-org/matrix-spec-proposals/pull/3861
|
||||
@ -0,0 +1,60 @@
|
||||
# MSC4210: Remove legacy mentions
|
||||
Matrix v1.7 introduced [intentional mentions], where events list users they
|
||||
mention explicitly, instead of the recipients inferring mentions from the raw
|
||||
message text. For backwards-compatibility reasons, messages without the new
|
||||
`m.mentions` field still use the old plaintext matching for mentions.
|
||||
|
||||
[intentional mentions]: https://spec.matrix.org/v1.15/client-server-api/#user-and-room-mentions
|
||||
|
||||
Plaintext matching means it's very difficult for automated tools to tell which
|
||||
users are mentioned in a message. This means that it's easy to spam mentions by
|
||||
simply not using intentional mentions.
|
||||
|
||||
If intentional mentions are mandatory, automated tools could easily ban users
|
||||
who send more than X mentions in a single message. There could even be a new
|
||||
push rule condition to allow checking the number of mentioned users and skip
|
||||
notifying entirely.
|
||||
|
||||
## Proposal
|
||||
Support for legacy mentions is dropped. Specifically, the following deprecated
|
||||
standard push rules are removed entirely:
|
||||
|
||||
* [`.m.rule.contains_display_name`](https://spec.matrix.org/v1.15/client-server-api/#_m_rule_contains_display_name)
|
||||
* [`.m.rule.contains_user_name`](https://spec.matrix.org/v1.15/client-server-api/#_m_rule_contains_user_name)
|
||||
* [`.m.rule.roomnotif`](https://spec.matrix.org/v1.15/client-server-api/#_m_rule_roomnotif)
|
||||
|
||||
Additionally, the `contains_display_name` [push rule condition] is deprecated.
|
||||
|
||||
[push rule condition]: https://spec.matrix.org/v1.15/client-server-api/#conditions-1
|
||||
|
||||
Including an empty `m.mentions` key is still required for clients that are
|
||||
aware of intentional mentions, as omitting it would cause current clients to
|
||||
assume messages are not using intentional mentions.
|
||||
|
||||
## Potential issues
|
||||
Users using old clients (which don't send intentional mentions) will no longer
|
||||
be able to mention users on up-to-date clients/servers.
|
||||
|
||||
Users using old clients (which don't support the new push rule conditions) will
|
||||
also no longer be notified for mentions in case the client depends on the push
|
||||
rules served by the server.
|
||||
|
||||
## Alternatives
|
||||
The removal could be done in a new room version, such as when switching to
|
||||
extensible events, as suggested by [MSC3952]. However, such a migration will
|
||||
likely take much longer than clients implementing intentional mentions.
|
||||
Additionally, the room upgrade UX is still an open issue, which means many
|
||||
rooms simply don't upgrade. Therefore, making a slightly breaking change to
|
||||
existing room versions seems like the better option.
|
||||
|
||||
[MSC3952]: https://github.com/matrix-org/matrix-spec-proposals/pull/3952
|
||||
|
||||
## Security considerations
|
||||
This proposal doesn't add any features, so there are no new security
|
||||
considerations.
|
||||
|
||||
## Unstable prefix
|
||||
Not applicable, this proposal only removes features.
|
||||
|
||||
## Dependencies
|
||||
None.
|
||||
@ -0,0 +1,54 @@
|
||||
# MSC4213: Remove `server_name` parameter
|
||||
|
||||
[MSC4156] deprecated the `server_name` parameter on [`/_matrix/client/v3/join/{roomIdOrAlias}`]
|
||||
and [`/_matrix/client/v3/knock/{roomIdOrAlias}`] in favor of a new parameter `via`. This change
|
||||
shipped in [Matrix v1.12]. In line with the [deprecation policy], the `server_name` parameter
|
||||
is now eligible for removal from the spec.
|
||||
|
||||
|
||||
## Proposal
|
||||
|
||||
The deprecated `server_name` parameter is removed from [`/_matrix/client/v3/join/{roomIdOrAlias}`]
|
||||
and [`/_matrix/client/v3/knock/{roomIdOrAlias}`].
|
||||
|
||||
|
||||
## Potential issues
|
||||
|
||||
None. Servers can continue advertising support for earlier versions of the spec that included
|
||||
`server_name` via [`/_matrix/client/versions`].
|
||||
|
||||
As of writing, the following stable implementations of [MSC4156] are known to the author:
|
||||
|
||||
- synapse: https://github.com/element-hq/synapse/pull/17650
|
||||
- dendrite: https://github.com/matrix-org/dendrite/pull/3438
|
||||
- matrix-js-sdk: https://github.com/matrix-org/matrix-js-sdk/pull/4381
|
||||
- ruma: https://github.com/ruma/ruma/pull/1891
|
||||
- trixnity: https://gitlab.com/trixnity/trixnity/-/merge_requests/478
|
||||
|
||||
|
||||
## Alternatives
|
||||
|
||||
None.
|
||||
|
||||
|
||||
## Security considerations
|
||||
|
||||
None.
|
||||
|
||||
|
||||
## Unstable prefix
|
||||
|
||||
None.
|
||||
|
||||
|
||||
## Dependencies
|
||||
|
||||
None.
|
||||
|
||||
|
||||
[`/_matrix/client/v3/join/{roomIdOrAlias}`]: https://spec.matrix.org/v1.12/client-server-api/#post_matrixclientv3joinroomidoralias
|
||||
[`/_matrix/client/v3/knock/{roomIdOrAlias}`]: https://spec.matrix.org/v1.12/client-server-api/#post_matrixclientv3knockroomidoralias
|
||||
[`/_matrix/client/versions`]: https://spec.matrix.org/v1.10/client-server-api/#get_matrixclientversions
|
||||
[Matrix v1.12]: https://spec.matrix.org/v1.12/changelog/v1.12/
|
||||
[MSC4156]: https://github.com/matrix-org/matrix-spec-proposals/pull/4156
|
||||
[deprecation policy]: https://spec.matrix.org/v1.12/#deprecation-policy
|
||||
@ -0,0 +1,155 @@
|
||||
# MSC4225: Specification of an order in which one-time-keys should be issued
|
||||
|
||||
The specification for the
|
||||
[`/keys/claim`](https://spec.matrix.org/v1.12/client-server-api/#post_matrixclientv3keysclaim)
|
||||
endpoint does not specify any particular order in which one-time keys (OTKs)
|
||||
should be returned, leading to the possibility that old keys can remain on the
|
||||
server a long time. Clients may discard the private parts of such old keys,
|
||||
leading to [unable-to-decrypt
|
||||
errors](https://github.com/element-hq/element-meta/issues/2356).
|
||||
|
||||
See the Appendix below for a more detailed discussion of the problem.
|
||||
|
||||
## Proposal
|
||||
|
||||
[`/_matrix/client/v3/keys/claim`](https://spec.matrix.org/v1.12/client-server-api/#post_matrixclientv3keysclaim)
|
||||
and [`/_matrix/federation/v1/user/keys/claim`](https://spec.matrix.org/v1.12/server-server-api/#post_matrixfederationv1userkeysclaim)
|
||||
should return one-time keys in the order that they were uploaded via
|
||||
[`/keys/upload`](https://spec.matrix.org/v1.12/client-server-api/#post_matrixclientv3keysupload). All
|
||||
keys uploaded in a given call to `/keys/upload` are considered equivalent in
|
||||
this regard; no ordering is specified within them.
|
||||
|
||||
This means that the server will retain only the most recently-uploaded one-time
|
||||
keys, therefore significantly reducing the chance that clients will discard
|
||||
private one-time keys that are later used.
|
||||
|
||||
### Implementation note
|
||||
|
||||
When servers first implement this proposal, they may still have old one-time
|
||||
keys in their datastore, and this may take many years to resolve.
|
||||
|
||||
It is suggested that one solution to this is, as a one-time job, to drop all
|
||||
one-time keys older than, say, a week, from the database. Having done so,
|
||||
clients will upload new one-time keys as soon as they come online; in the
|
||||
meantime, fallback keys are available to allow conversation to continue.
|
||||
|
||||
Servers might consider applying further heuristics: for example, keys produced
|
||||
by libolm are far more likely to have been dropped by the client than those
|
||||
produced by Vodozemac, because libolm only retained 100 keys, whereas Vodozemac
|
||||
retains 5000. The two can be identified by the different lengths of key ID they
|
||||
produce (6 characters vs 11 characters).
|
||||
|
||||
## Potential issues
|
||||
|
||||
This proposal is not a complete solution to the problem of premature discarding
|
||||
of one-time keys: even if the server issues a recent one-time key, it is still
|
||||
possible for a to-device message to be delayed so long that the recipient has
|
||||
discarded the private part of the one-time key. It is, however, a significant
|
||||
improvement. A possible future solution is for clients that expect to be used
|
||||
in conditions of poor connectivity to keep old OTKs for longer.
|
||||
|
||||
There are other ways in which the server and client can get out of sync with
|
||||
respect to one-time keys, including by a [database
|
||||
rollback](https://github.com/element-hq/element-meta/issues/2155), or
|
||||
implementation defects. It is anticipated that other solutions will be found
|
||||
for those situations.
|
||||
|
||||
## Alternatives
|
||||
|
||||
1. Mandate that clients keep the private parts of all uploaded but unused OTKs
|
||||
indefinitely.
|
||||
|
||||
Given that each one-time key is only 32 bytes (plus the ID, say 8 bytes), it
|
||||
would certainly be possible for a client implementation to hold a very large
|
||||
number of private OTKs without significant concerns about resource usage. In
|
||||
particular, a OTK is much smaller than a Megolm key, and there is no limit
|
||||
to the number of Megolm keys that a client has to retain.
|
||||
|
||||
In short though, this just seems inefficient, compared to specifying that
|
||||
OTKs should be issued in upload order.
|
||||
|
||||
2. [MSC4162](https://github.com/matrix-org/matrix-spec-proposals/pull/4162)
|
||||
proposes a mechanism by which a client can inform the server that it is
|
||||
discarding certain OTKs, so that the server can also remove the public
|
||||
keys. This seems a heavier-weight solution to the problem.
|
||||
|
||||
3. A more invasive alternative would be to design an encryption stack which
|
||||
does not rely on one-time keys. Setting aside whether the security
|
||||
properties of such a protocol would be sufficient, this is considered well
|
||||
out-of-scope for this proposal.
|
||||
|
||||
## Security considerations
|
||||
|
||||
Requiring keys to be allocated in upload order might leak information about the
|
||||
user's traffic level, since key IDs are typically allocated sequentially: if I
|
||||
issue two claims for Alice's OTKs a week apart, and I get sequential key IDs, I
|
||||
know that nobody else has opened a conversation with her in that time.
|
||||
|
||||
To mitigate this, we might consider having clients create key IDs
|
||||
non-sequentially (whilst remaining unique). This is considered out-of-scope for
|
||||
this MSC.
|
||||
|
||||
## Unstable prefix
|
||||
|
||||
None required.
|
||||
|
||||
## Dependencies
|
||||
|
||||
None.
|
||||
|
||||
## Appendix: detailed explanation of the failure mode
|
||||
|
||||
### Background
|
||||
|
||||
End-to-end encryption in Matrix relies on individual devices sharing
|
||||
[Megolm](https://gitlab.matrix.org/matrix-org/olm/blob/master/docs/megolm.md)
|
||||
message keys via [to-device
|
||||
messages](https://spec.matrix.org/v1.12/client-server-api/#send-to-device-messaging)
|
||||
which are themselves encrypted using the
|
||||
[Olm](https://gitlab.matrix.org/matrix-org/olm/blob/master/docs/olm.md)
|
||||
ratchet.
|
||||
|
||||
Suppose Alice wishes to send an Olm-encrypted message to Bob (with whom she
|
||||
has not previously established an Olm session). When Bob logged in, his device
|
||||
will have created a long-term identity key, as well as a number (typically 50)
|
||||
of one-time keys. Each of these keys has a private part, which Bob's device
|
||||
retains locally, and a public part, which Bob's device publishes to his
|
||||
homeserver via the
|
||||
[`/keys/upload`](https://spec.matrix.org/v1.12/client-server-api/#post_matrixclientv3keysupload) endpoint.
|
||||
|
||||
Now, to establish an Olm session, Alice needs to claim one of Bob's one-time
|
||||
keys. She does this by calling the
|
||||
[`/keys/claim`](https://spec.matrix.org/v1.12/client-server-api/#post_matrixclientv3keysclaim)
|
||||
endpoint. Together with Bob's identity key, this allows Alice to encrypt a
|
||||
message that only Bob will be able to decrypt.
|
||||
|
||||
Over time, Bob's supply of one-time keys will be depleted. The `/sync` endpoint
|
||||
informs clients how many one-time keys remain unclaimed on the server, so that
|
||||
it can generate new ones when required.
|
||||
|
||||
See [One-time and fallback
|
||||
keys](https://spec.matrix.org/v1.12/client-server-api/#one-time-and-fallback-keys)
|
||||
which specifies much of this behaviour.
|
||||
|
||||
### Problem
|
||||
|
||||
Clearly, a device must retain the private part of each one-time key until that
|
||||
key is used to establish an Olm session. However, for a number of reasons,
|
||||
ranging from network errors to malicious activity, it is possible for a claimed
|
||||
one-time key never to be used to establish an Olm session.
|
||||
|
||||
This presents a problem: there is a limit to the number of private one-time
|
||||
keys that a client can retain. Over time, as keys are repeatedly claimed,
|
||||
replaced with newly-generated keys, but not actually used, the client must
|
||||
start to discard older keys.
|
||||
|
||||
Unfortunately, the Matrix specification does not currently specify any order in
|
||||
which keys should be returned by `/keys/claim`. This means that homeservers can
|
||||
legitimately issue one-time keys effectively at random. Over time, then, it is
|
||||
easy to get into a situation where the server still holds some very old
|
||||
one-time keys, for which the client has discarded the private parts.
|
||||
|
||||
Suppose, when Alice claims one of Bob's one-time keys, she is issued one whose
|
||||
private part Bob has discarded. Then, Bob will be unable to decrypt the Olm
|
||||
message from Alice, and (assuming the Olm message contained Megolm keys), will
|
||||
be unable to decrypt any room messages that Alice sends.
|
||||
@ -0,0 +1,49 @@
|
||||
# MSC4239: Room version 11 as the default room version
|
||||
|
||||
[Room version 11](https://spec.matrix.org/v1.12/rooms/v11/) was introduced in Matrix 1.8 back in
|
||||
August 2023. The room version is a light cleanup from [room version 10](https://spec.matrix.org/v1.12/rooms/v10/),
|
||||
particularly around the redaction algorithm. There are no other major changes.
|
||||
|
||||
Over the last year since release, the expectation was that there might be a room version 12 in quick
|
||||
succession, however as is tradition for any expectation, things changed. This proposal bumps the
|
||||
[default suggested room version](https://spec.matrix.org/v1.12/rooms/#complete-list-of-room-versions)
|
||||
from version 10 to version 11, bringing the redaction algorithm cleanup to the wider ecosystem.
|
||||
|
||||
## Proposal
|
||||
|
||||
The specification adopts room version 11 as the suggested default room version. No stability status
|
||||
changes are made to any room version.
|
||||
|
||||
## Potential issues
|
||||
|
||||
Some servers may not have updated to support version 11 yet, though many servers support version 10.
|
||||
The delta between the versions is minimal.
|
||||
|
||||
## Alternatives
|
||||
|
||||
No relevant alternatives.
|
||||
|
||||
## Security considerations
|
||||
|
||||
No relevant security considerations (they would have been made in [MSC3820](https://github.com/matrix-org/matrix-spec-proposals/pull/3820)).
|
||||
|
||||
## Unstable prefix
|
||||
|
||||
No relevant prefix - servers can already choose a different default room version. This MSC formalizes
|
||||
the default.
|
||||
|
||||
## Dependencies
|
||||
|
||||
No outstanding blockers are listed.
|
||||
|
||||
## Prior art
|
||||
|
||||
* https://github.com/matrix-org/matrix-spec-proposals/pull/3904 - Room version 10 to default (released in Matrix 1.6, February 2023)
|
||||
* https://github.com/matrix-org/matrix-spec-proposals/pull/3589 - Room version 9 to default (released in Matrix 1.3, June 2022)
|
||||
* https://github.com/matrix-org/matrix-spec-proposals/pull/2788 - Room version 6 to default (released in Matrix 1.1(?), November 2021)
|
||||
* https://github.com/matrix-org/matrix-spec-proposals/pull/2334 - Room version 5 to default (released in r0.6.0, November 2019)
|
||||
* https://github.com/matrix-org/matrix-spec-proposals/pull/2002 - Room version 4 to default (released ~r0.5.0, "Matrix 1.0", June 2019)
|
||||
* https://github.com/matrix-org/matrix-spec-proposals/pull/1943 - Room version 3 to default (closed in favour of version 4)
|
||||
|
||||
Note: Room versions 2, 3, 7, and 8 were never adopted as the default room version. Version 1 was the original room version,
|
||||
released formally in https://github.com/matrix-org/matrix-doc/pull/1773 (~r0.5.0, "Matrix 1.0", June 2019).
|
||||
@ -0,0 +1,121 @@
|
||||
# MSC4254: Usage of [RFC7009] Token Revocation for Matrix client logout
|
||||
|
||||
This proposal is part of the broader [MSC3861: Next-generation auth for Matrix, based on OAuth 2.0/OIDC][MSC3861].
|
||||
|
||||
This MSC specifies how Matrix clients should use OAuth 2.0 Token Revocation as defined in [RFC7009] to implement client logout.
|
||||
|
||||
## Proposal
|
||||
|
||||
### Prerequisites
|
||||
|
||||
This proposal requires the client to know the following authorization server metadata about the homeserver:
|
||||
|
||||
- `revocation_endpoint`: the URL where the client is able to revoke tokens
|
||||
|
||||
The discovery of the above metadata is out of scope for this MSC, and is currently covered by [MSC2965].
|
||||
|
||||
### Token revocation
|
||||
|
||||
When a user wants to log out from a client, the client SHOULD revoke either its access token or refresh token by making a POST request to the revocation endpoint as described in [RFC7009].
|
||||
|
||||
The server MUST revoke both the access token and refresh token associated with the token provided in the request.
|
||||
|
||||
The request includes the following parameters, encoded as `application/x-www-form-urlencoded`:
|
||||
|
||||
- `token`: This parameter MUST contain either the access token or the refresh token to be revoked.
|
||||
- `token_type_hint`: This parameter is OPTIONAL, and if present, MUST have a value of either `access_token` or `refresh_token`. The server MAY use this value to optimize the token lookup process
|
||||
- `client_id`: The client identifier obtained during client registration. This parameter is OPTIONAL.
|
||||
|
||||
If the `client_id` is not provided, or does not match the client associated with the token, the server SHOULD still revoke the token.
|
||||
This behavior is meant to help good actors like secret scanning tools to proactively revoke leaked tokens.
|
||||
The server MAY also warn the user that one of their sessions may be compromised in this scenario.
|
||||
|
||||
#### Sample flow
|
||||
|
||||
Revoking using the access token:
|
||||
|
||||
```http
|
||||
POST /oauth2/revoke HTTP/1.1
|
||||
Host: auth.example.com
|
||||
Content-Type: application/x-www-form-urlencoded
|
||||
|
||||
token=mat_ooreiPhei2wequu9fohkai3AeBaec9oo&
|
||||
token_type_hint=access_token&
|
||||
client_id=s6BhdRkqt3
|
||||
```
|
||||
|
||||
```http
|
||||
HTTP/1.1 200 OK
|
||||
```
|
||||
|
||||
Or equivalently, using the refresh token:
|
||||
|
||||
```http
|
||||
POST /oauth2/revoke HTTP/1.1
|
||||
Host: auth.example.com
|
||||
Content-Type: application/x-www-form-urlencoded
|
||||
|
||||
token=mar_Pieyiev3aenahm4atah7aip3eiveizah&
|
||||
token_type_hint=refresh_token&
|
||||
client_id=s6BhdRkqt3
|
||||
```
|
||||
|
||||
```http
|
||||
HTTP/1.1 200 OK
|
||||
```
|
||||
|
||||
### Handling errors
|
||||
|
||||
The server may return an error response as defined in [RFC7009]. Note that RFC7009 mandates a [RFC6749 error response](https://datatracker.ietf.org/doc/html/rfc6749#section-5.2) rather than a Matrix standard error response.
|
||||
|
||||
The client should handle these errors appropriately:
|
||||
|
||||
- If the token is already revoked or invalid, the server returns a 200 OK response
|
||||
- If the client is not authorized to revoke the token, the server returns a 401 Unauthorized response
|
||||
- For other errors, the server returns a 400 Bad Request response with error details
|
||||
|
||||
### Replacement of existing APIs
|
||||
|
||||
This proposal replaces the existing [`/_matrix/client/v3/logout`] endpoint for [MSC3861]-compatible clients.
|
||||
Those clients MUST use this mechanism to logout, and clients using the [`/_matrix/client/v3/login`] endpoint to login MUST keep using the existing [`/_matrix/client/v3/logout`] endpoint.
|
||||
|
||||
Note that this proposal does not itself provide alternatives to endpoints like [`POST /_matrix/client/v3/logout/all`], [`DELETE /_matrix/client/v3/devices/{deviceId}`] or [`POST /_matrix/client/v3/delete_devices`].
|
||||
Under the [MSC3861] proposal, management of other devices is not the responsibility of the client, and should instead be provided in a separate user interface by the homeserver.
|
||||
|
||||
|
||||
## Potential issues
|
||||
|
||||
The main consideration around token revocation is ensuring proper cleanup of all related tokens and state. The server must:
|
||||
|
||||
1. Track the relationship between access tokens and refresh tokens
|
||||
2. Properly revoke both tokens when either one is provided
|
||||
3. Clean up any Matrix device associated with the session
|
||||
|
||||
## Alternatives
|
||||
|
||||
### OpenID Connect RP-Initiated Logout
|
||||
|
||||
OpenID Connect defines a [RP-Initiated Logout](https://openid.net/specs/openid-connect-rpinitiated-1_0.html) specification that allows clients to initiate a logout through a browser redirect. This would:
|
||||
|
||||
1. Allow the server to clear browser session state
|
||||
2. Support single logout across multiple clients
|
||||
3. Give visual feedback to the user about the logout process
|
||||
|
||||
However, this approach requires a browser redirect which may not be desirable for all clients, especially mobile platforms.
|
||||
|
||||
## Security considerations
|
||||
|
||||
Token revocation is a critical security feature that allows users to terminate access when needed. Some key security aspects:
|
||||
|
||||
- Servers must revoke both the access token and refresh token when either is revoked
|
||||
- The server should consider revoking other related sessions, like browser cookie sessions used during authentication
|
||||
- Revoking a token should be effective immediately, and not be usable for any further requests
|
||||
|
||||
[RFC7009]: https://tools.ietf.org/html/rfc7009
|
||||
[MSC2965]: https://github.com/matrix-org/matrix-spec-proposals/pull/2965
|
||||
[MSC3861]: https://github.com/matrix-org/matrix-spec-proposals/pull/3861
|
||||
[`/_matrix/client/v3/login`]: https://spec.matrix.org/v1.13/client-server-api/#login
|
||||
[`/_matrix/client/v3/logout`]: https://spec.matrix.org/v1.13/client-server-api/#post_matrixclientv3logout
|
||||
[`POST /_matrix/client/v3/logout/all`]: https://spec.matrix.org/v1.13/client-server-api/#post_matrixclientv3logoutall
|
||||
[`DELETE /_matrix/client/v3/devices/{deviceId}`]: https://spec.matrix.org/v1.13/client-server-api/#delete_matrixclientv3devicesdeviceid
|
||||
[`POST /_matrix/client/v3/delete_devices`]: https://spec.matrix.org/v1.13/client-server-api/#post_matrixclientv3delete_devices
|
||||
@ -0,0 +1,139 @@
|
||||
# MSC4260: Reporting users (Client-Server API)
|
||||
|
||||
[MSC4151 (merged)](https://github.com/matrix-org/matrix-spec-proposals/blob/main/proposals/4151-report-room.md)
|
||||
added an endpoint to report entire rooms to the server admin, expanding upon the existing report event
|
||||
API. To fully complement this set of APIs, this proposal introduces a Client-Server API endpoint to
|
||||
report entire users, independent of rooms.
|
||||
|
||||
Like MSC4151, the scope of this MSC is intentionally narrow to facilitate quick traversal through the
|
||||
MSC process. Other, future, MSCs may be required to build out even more APIs for reporting content.
|
||||
|
||||
Also like MSC4151, it is expected that a future series of MSCs will revamp reporting in Matrix.
|
||||
|
||||
## Proposal
|
||||
|
||||
Taking inspiration from [`POST /rooms/:roomId/report/:eventId`](https://spec.matrix.org/v1.10/client-server-api/#post_matrixclientv3roomsroomidreporteventid),
|
||||
a new endpoint is introduced:
|
||||
|
||||
```
|
||||
POST /_matrix/client/v3/users/:userId/report
|
||||
{
|
||||
"reason": "<user-supplied, may be empty>"
|
||||
}
|
||||
```
|
||||
|
||||
`reason` is a human-readable string describing the reason for the report. The string may be blank,
|
||||
but *must* be provided (to align with `/report/:eventId`).
|
||||
|
||||
**Note**: `score` is not carried over from `/report/:eventId` because it has not proven useful. A
|
||||
future MSC may introduce it. The same was done in MSC4151 for `/rooms/:roomId/report`.
|
||||
|
||||
There are no restictions on who can report a user: knowing the user ID is sufficient. This is to
|
||||
ensure that results from the user directory, invites, links, etc can all be reported. If the user
|
||||
does not exist on the server, the endpoint returns `404 M_NOT_FOUND`. Otherwise, `200` with `{}` as
|
||||
a response body. If a user doesn't exist and the server wishes to hide that detail, it MAY return a
|
||||
successful (`200`) response instead.
|
||||
|
||||
Like `/report/:eventId`, handling of the report is left as a deliberate implementation detail.
|
||||
|
||||
### Examples
|
||||
|
||||
**Note**: Some clients may need to `encodeURIComponent` (or similar) the user ID to use it in a path
|
||||
parameter.
|
||||
|
||||
```
|
||||
POST /_matrix/client/v3/users/@alice:example.org/report
|
||||
{"reason":"bad person"}
|
||||
|
||||
> 200 OK
|
||||
> {}
|
||||
```
|
||||
|
||||
```
|
||||
POST /_matrix/client/v3/users/@alice:example.org/report
|
||||
{"reason":""}
|
||||
|
||||
> 200 OK
|
||||
> {}
|
||||
```
|
||||
|
||||
```
|
||||
POST /_matrix/client/v3/users/@alice:example.org/report
|
||||
{"reason":""}
|
||||
|
||||
> 404 OK
|
||||
> {"errcode":"M_NOT_FOUND","error":"User does not exist"}
|
||||
```
|
||||
|
||||
## Safety considerations
|
||||
|
||||
* Server admins may be exposed to harmful content through `reason`. This is an existing issue with
|
||||
the reporting module, and difficult to fix. Applications which expose report reasons of any kind
|
||||
are encouraged to place disclosures in the user experience path. For example, a page explaining
|
||||
that the tool may contain harmful content before allowing the user temporary access, or the use of
|
||||
spoiler tags on report reasons/content.
|
||||
|
||||
* Clients MAY add reported users to the [ignore list](https://spec.matrix.org/v1.13/client-server-api/#ignoring-users)
|
||||
to both discourage duplicate reports and to remove the harmful content from the user's view, where
|
||||
possible. This may require filtering user directory responses and local timeline filtering.
|
||||
|
||||
* Users may report other users instead of events in any specific room, particularly during a harmful
|
||||
content spam wave. Administrators and safety teams should aim to clean up a user's events if they
|
||||
take action against the account, where appropriate.
|
||||
|
||||
* 'Report flooding' is more easily possible with this new endpoint, where many users report a user
|
||||
with the hope of getting them kicked off the server. Automated decision making is not recommended
|
||||
for this endpoint to prevent consequences like this from happening. Teams may wish to consider using
|
||||
reversible options like [suspension](https://spec.matrix.org/v1.13/client-server-api/#account-suspension)
|
||||
and [locking](https://spec.matrix.org/v1.13/client-server-api/#account-locking).
|
||||
|
||||
## Potential issues
|
||||
|
||||
* Within the Trust & Safety environment, it is well known that `reason` alone is insufficient for an
|
||||
informed report. Self-triage categories and mandatory `reason` for some of those categories help
|
||||
improve a safety team's ability to handle a report. These features are not included in this proposal
|
||||
as they require further thought and consideration - a future MSC may expand (or even deprecate) the
|
||||
report endpoints to support this added information.
|
||||
|
||||
* While reports against non-local users are permitted, this MSC does not introduce a way for those
|
||||
reports to transit federation to the target's server. This is considered an issue for another MSC,
|
||||
like [MSC3843](https://github.com/matrix-org/matrix-spec-proposals/pull/3843) or
|
||||
[MSC4202](https://github.com/matrix-org/matrix-spec-proposals/pull/4202).
|
||||
|
||||
* Whether a user exists on the server is revealed through the new endpoint. Servers have the option
|
||||
to mask this detail by ignoring the report.
|
||||
|
||||
## Alternatives
|
||||
|
||||
* If the client is aiming to report a user within a room, reporting the membership event within that
|
||||
room may be suitable. If the user is aiming to report a broad pattern of behaviour, or a profile
|
||||
concern spanning multiple rooms/communities, a more generic API is preferred. A dedicated API is
|
||||
also required when users are shown outside the context of a room, such as during invites (when event
|
||||
IDs may not be known) or when looking for users/friends to chat to.
|
||||
|
||||
* [MSC4202](https://github.com/matrix-org/matrix-spec-proposals/pull/4202) discusses the idea of
|
||||
reporting profiles generally, and aims to work within the context of a room. Introducing a new
|
||||
dedicated endpoint is compatible with MSC4202's objectives.
|
||||
|
||||
## Security considerations
|
||||
|
||||
* Rate limiting is strongly recommended for this new endpoint.
|
||||
|
||||
* Authentication is required for this new endpoint.
|
||||
|
||||
* Guest access is not permitted for this new endpoint to reduce spam. A future MSC may change this
|
||||
out of necessity. MSC4151 and the original report events API are likely similarly affected.
|
||||
|
||||
* Servers which opt to hide the existence of a user on the new endpoint should consider implementing
|
||||
a constant time function to avoid unintentionally disclosing that a user exists by processing the
|
||||
request slower.
|
||||
|
||||
## Unstable prefix
|
||||
|
||||
While this proposal is not considered stable, implementations should use `/_matrix/client/unstable/org.matrix.msc4260/users/:userId/report`
|
||||
instead. Clients should note the [`M_UNRECOGNIZED` behaviour](https://spec.matrix.org/v1.13/client-server-api/#common-error-codes)
|
||||
for servers which do not support the (un)stable endpoint.
|
||||
|
||||
## Dependencies
|
||||
|
||||
This MSC has no direct dependencies.
|
||||
@ -0,0 +1,60 @@
|
||||
# MSC4304: Room Version 12
|
||||
|
||||
A new room version, `12`, is proposed using [room version 11](https://spec.matrix.org/v1.15/rooms/v11/)
|
||||
as a base and incorporating the following MSCs:
|
||||
|
||||
* [MSC4289](https://github.com/matrix-org/matrix-spec-proposals/pull/4289) - Explicitly privilege room creators
|
||||
* [MSC4291](https://github.com/matrix-org/matrix-spec-proposals/pull/4291) - Room IDs as hashes of the create event
|
||||
* [MSC4297](https://github.com/matrix-org/matrix-spec-proposals/pull/4297) - State Resolution v2.1
|
||||
|
||||
Though not technically required, [MSC4307: Validate `auth_events` are in the correct room](https://github.com/matrix-org/matrix-spec-proposals/pull/4307)
|
||||
is explicitly included in this room version as well.
|
||||
|
||||
Other MSCs are capable of being included in this version, but they do not have sufficient implementation, acceptance,
|
||||
and/or testing to be considered stable enough for v12 rooms. A future room version may still include them. Most
|
||||
notable are:
|
||||
|
||||
* https://github.com/matrix-org/matrix-spec-proposals/pull/2870 - Lacking testing.
|
||||
* https://github.com/matrix-org/matrix-spec-proposals/pull/2244 - Lacking implementation.
|
||||
|
||||
Room version 12 upon being added to the specification shall be considered stable. No other room versions
|
||||
are affected by this MSC.
|
||||
|
||||
Typically, an MSC like this one which cuts a room version release would not be encouraged to make that same
|
||||
room version the default for new rooms. Given the security context around the above MSCs however, this MSC
|
||||
***does*** update the default room version to be v12 immediately. A wide variety of server implementations
|
||||
already exist at the time of publishing this MSC, and major clients have been tested for compatibility with
|
||||
the room version, though there are some noted incompatibilities expected.
|
||||
|
||||
As a result of those incompatibilities, servers are encouraged to exercise the "SHOULD" on the default room
|
||||
version applied by the spec and deviate in the early days/weeks of v12's rollout. Once their respective
|
||||
communities are better prepared, which may be a matter of days after publishing, servers SHOULD return back
|
||||
to the default in the spec.
|
||||
|
||||
## Unstable prefix
|
||||
|
||||
Implementations looking to test v12 before written into the specification should use `org.matrix.hydra.11`
|
||||
as the room version, treating it as unstable.
|
||||
|
||||
## Prior art
|
||||
|
||||
Room version MSCs are meant to be lightweight and fit a standard process. In backwards chronological
|
||||
order, they are:
|
||||
|
||||
* https://github.com/matrix-org/matrix-spec-proposals/pull/4239 - Room version 11 (made default)
|
||||
* https://github.com/matrix-org/matrix-spec-proposals/pull/3820 - Room version 11 (creation)
|
||||
* https://github.com/matrix-org/matrix-spec-proposals/pull/3904 - Room version 10 (made default)
|
||||
* https://github.com/matrix-org/matrix-spec-proposals/pull/3604 - Room version 10 (creation)
|
||||
* https://github.com/matrix-org/matrix-spec-proposals/pull/3589 - Room version 9 (made default)
|
||||
* https://github.com/matrix-org/matrix-spec-proposals/pull/3375 - Room version 9 (creation)
|
||||
* https://github.com/matrix-org/matrix-spec-proposals/pull/3289 - Room version 8 (creation)
|
||||
* https://github.com/matrix-org/matrix-spec-proposals/pull/2998 - Room version 7 (creation)
|
||||
* https://github.com/matrix-org/matrix-spec-proposals/pull/2788 - Room version 6 (made default)
|
||||
* https://github.com/matrix-org/matrix-spec-proposals/pull/2240 - Room version 6 (creation)
|
||||
* https://github.com/matrix-org/matrix-spec-proposals/pull/2077 - Room version 5 (creation)
|
||||
* https://github.com/matrix-org/matrix-spec-proposals/pull/2002 - Room version 4 (creation; made default [retroactively](https://github.com/matrix-org/matrix-doc/pull/2082))
|
||||
* https://github.com/matrix-org/matrix-spec-proposals/pull/1943 - Room version 3 (made default; closed)
|
||||
* https://github.com/matrix-org/matrix-spec-proposals/pull/1659 - Room version 3 (no-longer-standard inline creation)
|
||||
* https://github.com/matrix-org/matrix-spec-proposals/pull/1759 - Room version 2 (creation)
|
||||
|
||||
Room version 1 was the first room version, released formally in https://github.com/matrix-org/matrix-doc/pull/1773 (~r0.5.0, "Matrix 1.0", June 2019)
|
||||
@ -0,0 +1,48 @@
|
||||
# MSC4307: Validate that `auth_events` are in the correct room
|
||||
|
||||
Each event in Matrix specifies a list of [auth events](https://spec.matrix.org/v1.14/server-server-api/#auth-events-selection), which are used during [event authorisation](https://spec.matrix.org/v1.14/server-server-api/#checks-performed-on-receipt-of-a-pdu) to ensure that the event should be permitted.
|
||||
|
||||
Currently, the Matrix specification does not make explicit that these auth events must be in the same room as the event itself.
|
||||
|
||||
This was the cause of a security vulnerability in Synapse 1.7 and earlier.
|
||||
|
||||
## Proposal
|
||||
|
||||
Within the [auth rules](https://spec.matrix.org/v1.14/rooms/v11/#authorization-rules), for all room versions, add a new rule 2.5 reading:
|
||||
|
||||
> 2.5. If any `auth_event` has a `room_id` which does not match that of the event being authorised, reject.
|
||||
|
||||
In practice, Synapse already
|
||||
[implements](https://github.com/element-hq/synapse/blob/9d43bec/synapse/event_auth.py#L234)
|
||||
this check, and we would expect that any other server does likewise. It is also
|
||||
[enforced](https://github.com/matrix-org/sytest/blob/bb83c6f0cbec5f822dcaecd22533ac3e7ffde0ef/tests/50federation/31room-send.pl#L201)
|
||||
by the SyTest homeserver test suite. It seems a clear omission in the text of
|
||||
the auth rules.
|
||||
|
||||
## Potential issues
|
||||
|
||||
If there exist implementations which do not already enforce this rule, then
|
||||
introducing it retrospectively could lead to split-brain situations where
|
||||
different servers accept different events into the DAG. However:
|
||||
|
||||
1. Since Synapse already implements this rule, the possibility of a split-brain already exists.
|
||||
2. The security implications of *not* doing this check are prohibitive (ultimately, an attacker with the ability to send messages to a room can subvert the event auth system to take over the room).
|
||||
|
||||
## Alternatives
|
||||
|
||||
We could leave the auth rules for existing room versions unchanged (and make
|
||||
either this or some other change in a future room version). Again though, given
|
||||
we believe all current implementations must implement this rule in practice,
|
||||
this seems futile.
|
||||
|
||||
## Security considerations
|
||||
|
||||
Auth rules are a very delicate area of the Matrix spec. Homeserver maintainers should be particularly careful when implementing them.
|
||||
|
||||
## Unstable prefix
|
||||
|
||||
N/A
|
||||
|
||||
## Dependencies
|
||||
|
||||
None.
|
||||
@ -0,0 +1,108 @@
|
||||
# MSC4311: Ensuring the create event is available on invites
|
||||
|
||||
Historically, when processing an incoming invite or outgoing knock, safety tooling would parse the room ID despite
|
||||
[being opaque](https://spec.matrix.org/v1.15/appendices/#room-ids), to determine the server which
|
||||
originally created the room. If that server was considered abusive, the invite or
|
||||
knock may be rejected or blocked early by the tooling. Note that checking the domain of the
|
||||
sender of an invite is inadequate, because the sender may not be on the same server as the
|
||||
user who created the room.
|
||||
|
||||
With [MSC4291](https://github.com/matrix-org/matrix-spec-proposals/pull/4291), room IDs lose their
|
||||
domain component. This, combined with [Stripped State](https://spec.matrix.org/v1.15/client-server-api/#stripped-state)
|
||||
recommending rather than requiring the `m.room.create` event, makes the above check harder if not
|
||||
impossible when the create event is missing or incomplete, as the room ID cannot be confirmed in
|
||||
MSC4291+ room versions.
|
||||
|
||||
To mitigate the problem in the case of invites,
|
||||
this MSC shifts the `m.room.create` event to a *required* stripped state event, and imposes validation
|
||||
to ensure the event matches the room. To support the new validation, the `m.room.create` event must
|
||||
be formatted as a full PDU in the stripped state of [invites](https://spec.matrix.org/v1.15/server-server-api/#put_matrixfederationv1inviteroomideventid)
|
||||
over federation. Similar treatment is applied to other stripped state events for uniformity.
|
||||
|
||||
[Knocks](https://spec.matrix.org/v1.15/server-server-api/#put_matrixfederationv1send_knockroomideventid)
|
||||
additionally include the full PDU format, though only to ensure symmetry between the two instances of
|
||||
stripped state. It's not possible to prevent a knock based on stripped state because the server will
|
||||
have already sent the knock before stripped state is received.
|
||||
|
||||
|
||||
## Proposal
|
||||
|
||||
On the Client-Server API, `m.room.create` MUST be provided in [Stripped State](https://spec.matrix.org/v1.15/client-server-api/#stripped-state),
|
||||
where available. No other changes are proposed to the Client-Server API. For clarity, this means clients
|
||||
continue to receive events which only have `content`, `sender`, `state_key` (optional), and `type` in
|
||||
the `invite_room_state`, `knock_room_state`, and wherever else stripped state is used.
|
||||
|
||||
Over federation, servers MUST include the `m.room.create` event in the [`invite_room_state`](https://spec.matrix.org/v1.15/server-server-api/#put_matrixfederationv1inviteroomideventid)
|
||||
and [`knock_room_state`](https://spec.matrix.org/v1.15/server-server-api/#put_matrixfederationv1send_knockroomideventid).
|
||||
Servers MUST additionally format events in `invite_room_state` and `knock_room_state` as PDUs according
|
||||
to that room version's event format specification. Together, these changes allow servers to validate
|
||||
the room ID matches the invite (or knock, though it's already sent by the time validation would happen).
|
||||
|
||||
Specifically, including the `m.room.create` event as a full PDU allows servers to calculate the room
|
||||
ID by hashing the event in MSC4291+ room versions. For other room versions (1 through 11), the server
|
||||
can at most compare the `room_id` field of the create event with the invite/knock membership event.
|
||||
|
||||
If any of the events are not a PDU, not for the room ID specified, or fail [signature checks](https://spec.matrix.org/v1.15/server-server-api/#validating-hashes-and-signatures-on-received-events),
|
||||
or the `m.room.create` event is missing, the receiving server MAY respond to invites with a `400 M_MISSING_PARAM`
|
||||
standard Matrix error (new to the endpoint). For invites to room version 12+ rooms, servers SHOULD
|
||||
rather than MAY respond to such requests with `400 M_MISSING_PARAM`. For knocks, the server SHOULD remove any events from
|
||||
`knock_room_state` which fail the same validation check before passing the details along to clients.
|
||||
Ideally, the server would be able to prevent the knock from happening, though by the time the server
|
||||
can see the `knock_room_state`, the knock has already happened.
|
||||
|
||||
**Note**: Servers SHOULD consider their local ecosystems before imposing this validation completely,
|
||||
per the "Migration" section later in this document.
|
||||
|
||||
The `400 M_MISSING_PARAM` error SHOULD be translated to a 5xx error by the sending server over the
|
||||
Client-Server API. This is done because there's nothing the client can materially do differently to
|
||||
make the request succeed.
|
||||
|
||||
When comparing the room IDs, servers will need to calculate the room ID from the `m.room.create` event
|
||||
as described by MSC4291 (take the reference hash of the event for an event ID, swap the sigil).
|
||||
|
||||
|
||||
## Potential issues
|
||||
|
||||
* Some server implementations allow safety tooling and other applications to hook into them between
|
||||
the Federation API and Client-Server API. Such implementations are encouraged to make the create
|
||||
event reasonably available in its full form to those applications. Typically, this will be an internal
|
||||
representation of the event which still has the capability to serialize down to a PDU.
|
||||
|
||||
* Implementations should take care to not unintentionally trust the events contained in `invite_room_state`
|
||||
and `knock_room_state`, despite appearing as complete events. This is due to the lack of each event's
|
||||
auth chain being included, and reassurance that the events are the current events.
|
||||
|
||||
## Alternatives
|
||||
|
||||
This proposal fills a potential gap in information created by MSC4291, making the alternatives roughly
|
||||
equivalent to "don't do this". A possible alternative is in the shape of [MSC4329](https://github.com/matrix-org/matrix-spec-proposals/pull/4329)
|
||||
where the `/invite` endpoint changes, however the changes are roughly the same as this proposal's.
|
||||
|
||||
|
||||
## Security considerations
|
||||
|
||||
Security considerations are made throughout, especially around validating the events included.
|
||||
|
||||
|
||||
## Unstable prefix
|
||||
|
||||
This proposal does not require an unstable prefix as the behaviour can be accomplished without overly
|
||||
affecting client or server implementations.
|
||||
|
||||
|
||||
## Migration
|
||||
|
||||
Mentioned above, existing server implementations SHOULD warn rather than fail on invites which don't
|
||||
have complete PDUs inside `invite_room_state` until their local ecosystem adoption allows for the
|
||||
full set of validation to be applied. If PDUs are complete, but for a different room, the invite SHOULD
|
||||
still fail in v12 rooms per the validation above.
|
||||
|
||||
This proposal suggests that servers wait no longer than 3 months (or about 1 full spec release cycle)
|
||||
after this proposal is released to enforce the full validation, though servers may extend this as
|
||||
needed for their ecosystems to gain support.
|
||||
|
||||
|
||||
## Dependencies
|
||||
|
||||
This proposal requires [MSC4291](https://github.com/matrix-org/matrix-spec-proposals/pull/4291) in
|
||||
order to make any amount of sense.
|
||||
@ -0,0 +1,110 @@
|
||||
# MSC4312: Resetting cross-signing keys in the OAuth world
|
||||
|
||||
Matrix v1.15 added new [OAuth APIs] for authentication. As of writing, these APIs are not compatible
|
||||
with the existing [User-Interactive Authentication (UIA)] mechanism that is used on a number of
|
||||
endpoints. This is not problematic in most cases because these endpoints cover actions that can now
|
||||
be preformed in the authorization server's web UI. One notable exception, however, is
|
||||
[`/_matrix/client/v3/keys/device_signing/upload`] which clients use to publish their cross-signing
|
||||
keys. This endpoint requires UIA when previously uploaded keys are being replaced, for instance
|
||||
because the user lost their recovery key. OAuth knows nothing about cross-signing keys and,
|
||||
consequently, the spec labels this endpoint as unusable:
|
||||
|
||||
> **WARNING:** When this endpoint requires User-Interactive Authentication, it cannot be used when
|
||||
> the access token was obtained via the OAuth 2.0 API.
|
||||
|
||||
This is obviously not practical and unofficial workarounds have been invented to enable resetting
|
||||
one's cross-signing keys in the client / homeserver / authorization server triangle. This proposal
|
||||
documents these workarounds as a low-effort interim workaround until better solutions are available.
|
||||
|
||||
## Proposal
|
||||
|
||||
Clients that have authenticated via the new [OAuth APIs] continue to use
|
||||
[`/_matrix/client/v3/keys/device_signing/upload`] to replace cross-signing keys. Homeservers
|
||||
continue to enforce UIA on the endpoint with a flow containing a single stage `m.oauth`[^1] together
|
||||
with a URL that points to the authorization server's account management UI.
|
||||
|
||||
``` json5
|
||||
{
|
||||
"session": "$ARBITRARY",
|
||||
"flows": [{
|
||||
"stages": ["m.oauth"]
|
||||
}],
|
||||
"params": {
|
||||
"m.oauth": {
|
||||
"url": "$AUTHORIZATION_SERVER_ACCOUNT_MANAGEMENT_URL"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The client then instructs the user to approve the reset of their cross-signing keys using the
|
||||
provided URL. How exactly that approval is achieved is an implementation detail between the
|
||||
authorization server and the homeserver[^2]. The required end result is that after approving, the
|
||||
client can complete the stage without further parameters.
|
||||
|
||||
``` json5
|
||||
{
|
||||
"auth": {
|
||||
"session": "$FROM_ABOVE"
|
||||
},
|
||||
"master_key": ...
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
To facilitate the navigation, a new action `org.matrix.cross_signing_reset` is introduced and MAY be
|
||||
used in the `account_management_actions_supported` authorization server metadata field from
|
||||
[MSC4191]. Servers SHOULD use this action to deep link the user if the authorization server supports
|
||||
it.
|
||||
|
||||
## Potential issues
|
||||
|
||||
Semantically, resetting cross-signing keys doesn't fall into the authorization server's domain. The
|
||||
scheme outlined above increases coupling between the authorization server and the homeserver and
|
||||
makes it more difficult to use off-the-shelve OAuth authorization servers.
|
||||
|
||||
## Alternatives
|
||||
|
||||
Rather than approving cross-signing reset specifically, the authorization server could provide
|
||||
mechanisms for temporary scope elevation. An example of a potential mechanism that could help
|
||||
achieve this is the [RFC 9470 OAuth 2.0 Step Up Authentication Challenge Protocol]. Theoretically
|
||||
such a mechanism could act as full replacement for UIA in the CS API where protection is needed for
|
||||
sensitive actions. [MSC4363] attempts to adapt this protocol to Matrix. This MSC is, however,
|
||||
nascent and more complex. Therefore it is proposed to codify this present mechanism into the spec.
|
||||
|
||||
## Security considerations
|
||||
|
||||
Since the details of how approval is communicated between the authorization server and the
|
||||
homeserver are left unspecified, implementations could introduce security risks through their
|
||||
concrete choice of protocol. The temporary lifting of UIA that happens between
|
||||
[matrix-authentication-service] and Synapse, for instance, creates a time window in which an
|
||||
attacker with an access token could take over the account.
|
||||
|
||||
## Unstable prefix
|
||||
|
||||
While this MSC is not considered stable, `m.oauth` should be referred to as
|
||||
`org.matrix.cross_signing_reset`.
|
||||
|
||||
Since this proposal is already used in production, for instance, on matrix.org, some care is
|
||||
required by servers when migrating from the unstable to the stable identifier. To prevent breaking
|
||||
clients that have implemented the unstable identifier, servers SHOULD offer two flows (one with each
|
||||
of `m.oauth` and `org.matrix.cross_signing_reset`).
|
||||
|
||||
## Dependencies
|
||||
|
||||
This proposal doesn't strictly depend on but works better with [MSC4191].
|
||||
|
||||
[^1]: Previous versions of this proposal used `m.cross_signing_reset` for the stage name. This was
|
||||
generalised into `m.oauth` to enable future reuse of the mechanism for other endpoints.
|
||||
|
||||
[^2]: [matrix-authentication-service], for instance, uses a [Synapse admin API] to temporarily lift
|
||||
UIA on the endpoint.
|
||||
|
||||
[OAuth APIs]: https://spec.matrix.org/v1.15/client-server-api/#oauth-20-api
|
||||
[User-Interactive Authentication (UIA)]: https://spec.matrix.org/v1.15/client-server-api/#user-interactive-authentication-api
|
||||
[`/_matrix/client/v3/keys/device_signing/upload`]: https://spec.matrix.org/v1.15/client-server-api/#post_matrixclientv3keysdevice_signingupload
|
||||
[MSC4191]: https://github.com/matrix-org/matrix-spec-proposals/pull/4191
|
||||
[RFC 9470 OAuth 2.0 Step Up Authentication Challenge Protocol]: https://datatracker.ietf.org/doc/rfc9470/
|
||||
[MSC4363]: https://github.com/matrix-org/matrix-spec-proposals/pull/4363
|
||||
[matrix-authentication-service]: https://github.com/element-hq/matrix-authentication-service
|
||||
[Synapse admin API]: https://element-hq.github.io/synapse/latest/admin_api/user_admin_api.html#allow-replacing-master-cross-signing-key-without-user-interactive-auth
|
||||
@ -0,0 +1,147 @@
|
||||
# MSC4323: User suspension & locking endpoints
|
||||
|
||||
Currently the specification outlines error codes for suspended and locked users,
|
||||
even going as far as to suggest which endpoints can and cannot be executed by suspended users.
|
||||
However, it does not currently define an endpoint which server administrators can call to suspend
|
||||
and unsuspend users on their server.
|
||||
As a result, moderation tooling such as Draupnir and Meowlnir have to implement
|
||||
implementation-specific calls, which is not sustainable as more implementations other than Synapse
|
||||
integrate this feature.
|
||||
|
||||
This proposal will outline new endpoints that will allow server administrators to
|
||||
suspend, unsuspend, lock, and unlock given users.
|
||||
|
||||
## Proposal
|
||||
|
||||
> [!IMPORTANT]
|
||||
> What defines a "server administrator" is left up to the implementation itself as most already have
|
||||
> their own systems for defining administrators (e.g. Synapse has a database flag, Conduit has room
|
||||
> membership) which rarely has a reason to be exposed outside of their respective management
|
||||
> interfaces.
|
||||
|
||||
Complementing [section 10.22 (Server Administration)][p1] of the client-to-server specification,
|
||||
four new endpoints are introduced:
|
||||
|
||||
- `GET /_matrix/client/v1/admin/suspend/{userId}`
|
||||
- `PUT /_matrix/client/v1/admin/suspend/{userId}`
|
||||
- `GET /_matrix/client/v1/admin/lock/{userId}`
|
||||
- `PUT /_matrix/client/v1/admin/lock/{userId}`
|
||||
|
||||
These new endpoints are similar to [`GET /_matrix/client/v3/admin/whois/{userId}`][p2] in that they
|
||||
are clearly defined as administration endpoints, however are restricted to only permitting
|
||||
execution on local server users.
|
||||
|
||||
### New endpoint definitions
|
||||
|
||||
The response body of both the `GET` and `PUT` endpoints, as well as the request body of the
|
||||
`PUT` endpoints, are defined below. Custom properties may be used provided they utilise
|
||||
[proper namespacing][p3] in their fields.
|
||||
|
||||
**Suspend**:
|
||||
|
||||
A single key, `suspended`, with a boolean indicating if the target account is suspended:
|
||||
|
||||
```json
|
||||
{"suspended": true}
|
||||
```
|
||||
|
||||
**Lock**:
|
||||
|
||||
A single key, `locked`, with a boolean indicating if the target account is locked:
|
||||
|
||||
```json
|
||||
{"locked": false}
|
||||
```
|
||||
|
||||
### New capability definition
|
||||
|
||||
The server should advertise that these new endpoints are available for the authenticated user
|
||||
to use by including the following new capability:
|
||||
|
||||
```json5
|
||||
{
|
||||
"capabilities": {
|
||||
"m.account_moderation": {
|
||||
"suspend": true, // or false if unavailable/unimplemented
|
||||
"lock": true // or false if unavailable/unimplemented
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This allows clients to determine whether they are able to suspend/lock users on this homeserver,
|
||||
allowing them to do things like dynamically show or hide a "suspend user" button, etc.
|
||||
|
||||
The capability should not be advertised at all if both `suspend` and `lock` would be `false`.
|
||||
Omitting a key is equivalent to it being `false`.
|
||||
|
||||
### Errors and restrictions
|
||||
|
||||
Sending a request to the respective endpoints returns:
|
||||
|
||||
- `400 / M_INVALID_PARAM`: The user ID does not belong to the local server.
|
||||
- `403 / M_FORBIDDEN`: The requesting user is not a server administrator, is trying to suspend/lock
|
||||
their own account, or the target user is another administrator.
|
||||
- `404 / M_NOT_FOUND`: The user ID is not found, or is deactivated.
|
||||
|
||||
In order to prevent user enumeration, implementations have to ensure that authorization is checked
|
||||
prior to trying to do account lookups.
|
||||
As this endpoint requires authentication with an administrator account, guest access is not
|
||||
permitted. Additionally, no rate-limiting is imposed.
|
||||
|
||||
[p1]: https://spec.matrix.org/v1.15/client-server-api/#server-administration
|
||||
[p2]: https://spec.matrix.org/v1.15/client-server-api/#get_matrixclientv3adminwhoisuserid
|
||||
[p3]: https://spec.matrix.org/v1.15/appendices/#common-namespaced-identifier-grammar
|
||||
|
||||
## Potential issues
|
||||
|
||||
This proposal does not outline any metadata fields for management, such as action reasons,
|
||||
temporary actions, authors, etc, which implementation-specific methods may currently have.
|
||||
This is for the sake of brevity and simplicity, and may be expanded upon by a future proposal.
|
||||
|
||||
This proposal is also written under the assumption that all server administrators are equal, and
|
||||
cannot be suspended or locked. If a server permits such actions against a privileged user, without
|
||||
stripping their privileges, conflicting behaviours may be encountered.
|
||||
|
||||
## Alternatives
|
||||
|
||||
A full "user-info" endpoint has been suggested, which would include more information about a user's
|
||||
account that could interest server administrators. This proposal focuses solely on providing
|
||||
tooling with the capability to suspend and lock without needing to maintain several
|
||||
implementation-specific versions of their code, and adding a full-fleged user-info endpoint is
|
||||
almost entirely out of scope.
|
||||
|
||||
## Security considerations
|
||||
|
||||
Adding these new endpoints may provide a path to circumvent restrictions previously imposed on
|
||||
implementation-specific versions of the suspend and lock endpoints (such as them being blocked off
|
||||
at the reverse proxy) - server developers will likely want to ensure that their users are made
|
||||
appropriate aware of this (via release notes or some other similar high-visibility channel) so that
|
||||
they can apply those same restrictions to these new endpoints if necessary.
|
||||
|
||||
These endpoints also increase the compromise value of an administrator account, as an attacker who
|
||||
breaches one of these accounts will be able to suspend or lock other users on the server. While
|
||||
the attacker would not be able to lock out other administrators, a single-administrator homeserver
|
||||
may be vulnerable to a temporary takeover if the sole administrator account is breached and
|
||||
the deployment cannot be secured & have the change reverted quickly.
|
||||
It may possibly also allow an attacker to disable other room-level moderation tooling, such as
|
||||
moderation bots, assuming those tools are not also server administrators.
|
||||
|
||||
## Unstable prefix
|
||||
|
||||
| Stable | Unstable |
|
||||
| ------ | -------- |
|
||||
| `/_matrix/client/v1/admin/...` | `/_matrix/client/unstable/uk.timedout.msc4323/admin/...` |
|
||||
| `m.account_moderation` | `uk.timedout.msc4323` |
|
||||
|
||||
`locked` and `suspended` in the request/response bodies do not require an unstable prefix
|
||||
as the entire body is new.
|
||||
|
||||
Servers should advertise `"uk.timedout.msc4323":true` in their `/versions` response while this
|
||||
proposal is unstable in order to advertise support for this new feature.
|
||||
It is left as an implementation detail whether to require authentication to view this version flag
|
||||
or not, as the capabilities endpoint requires authentication regardless.
|
||||
|
||||
## Dependencies
|
||||
|
||||
None
|
||||
@ -0,0 +1,117 @@
|
||||
# MSC4326: Device masquerading for appservices
|
||||
|
||||
*History*: This proposal is split off from [MSC3202: Encrypted Appservices](https://github.com/matrix-org/matrix-spec-proposals/pull/3202).
|
||||
|
||||
Appservices today can make requests as any (local) user in their namespace through [identity assertion](https://spec.matrix.org/v1.15/application-service-api/#identity-assertion).
|
||||
To support end-to-end encryption and other similar device-centric functionality, appservices need to
|
||||
be able to also pick the device ID they are speaking as.
|
||||
|
||||
This proposal adds device ID to the identity assertion appservices can already perform, leaving other
|
||||
aspects of end-to-end encryption support to other MSCs like MSC3202 (mentioned above).
|
||||
|
||||
|
||||
## Proposal
|
||||
|
||||
To complement the (optional) `user_id` query string parameter during identity assertion, an also-optional
|
||||
`device_id` parameter is also supported. The new `device_id` parameter is only available when `user_id`
|
||||
is available to the caller - when authenticating using an `as_token`.
|
||||
|
||||
When both a `user_id` and `device_id` are provided, and both are known/registered, the server uses those
|
||||
details for the remainder of the request. For many endpoints this means updating the "last seen IP"
|
||||
and "last seen timestamp" for the device, though for some endpoints it may mean interacting with the
|
||||
device specifically (such as when uploading one-time keys).
|
||||
|
||||
If the `device_id` does not already exist on the `user_id`, the server returns a `400 M_UNKNOWN_DEVICE`
|
||||
standard error response.
|
||||
|
||||
If the `device_id` is present without a `user_id`, the `user_id` is assumed to be the appservice's
|
||||
default sender (the user implied by `sender_localpart` in its registration). This is the same behaviour
|
||||
as today when the appservice makes such requests.
|
||||
|
||||
If the `device_id` is present and the requester is not able to use identity assertion, the request
|
||||
continues as though the `device_id` parameter was never present. This copies the behaviour of `user_id`.
|
||||
|
||||
### Examples
|
||||
|
||||
*All examples assume the `user_id` is within the appservice's scope.*
|
||||
|
||||
User ID asserted, but not device ID:
|
||||
|
||||
```text
|
||||
GET /_matrix/client/v3/account/whoami?user_id=@alice:example.org
|
||||
Authorization: Bearer as_token_here
|
||||
|
||||
{
|
||||
"user_id": "@alice:example.org",
|
||||
"is_guest": false
|
||||
}
|
||||
```
|
||||
|
||||
User ID and device ID asserted:
|
||||
|
||||
```text
|
||||
GET /_matrix/client/v3/account/whoami?user_id=@alice:example.org&device_id=ABC123
|
||||
Authorization: Bearer as_token_here
|
||||
|
||||
{
|
||||
"user_id": "@alice:example.org",
|
||||
"is_guest": false,
|
||||
"device_id": "ABC123"
|
||||
}
|
||||
```
|
||||
|
||||
Just device ID asserted:
|
||||
|
||||
```text
|
||||
GET /_matrix/client/v3/account/whoami?device_id=ABC123
|
||||
Authorization: Bearer as_token_here
|
||||
|
||||
{
|
||||
"user_id": "@the_appservice_sender:example.org",
|
||||
"is_guest": false,
|
||||
"device_id": "ABC123"
|
||||
}
|
||||
```
|
||||
|
||||
Nothing asserted:
|
||||
|
||||
```text
|
||||
GET /_matrix/client/v3/account/whoami
|
||||
Authorization: Bearer as_token_here
|
||||
|
||||
{
|
||||
"user_id": "@the_appservice_sender:example.org",
|
||||
"is_guest": false
|
||||
}
|
||||
```
|
||||
|
||||
## Potential issues
|
||||
|
||||
Appservices will need to create and manage their users' devices using another proposal or system. An
|
||||
example is [MSC4190](https://github.com/matrix-org/matrix-spec-proposals/pull/4190).
|
||||
|
||||
|
||||
## Alternatives
|
||||
|
||||
None relevant.
|
||||
|
||||
|
||||
## Security considerations
|
||||
|
||||
The behaviour of `device_id` is largely copied from `user_id`, so should not increase or decrease an
|
||||
appservice's capabilities beyond what it could already do. This is especially true for appservices
|
||||
which cover "real" users in their namespaces: while they couldn't (and still can't) access data encrypted
|
||||
before using something like [MSC3202](https://github.com/matrix-org/matrix-spec-proposals/pull/3202),
|
||||
they could log out whatever devices they don't want and register new ones accordingly.
|
||||
|
||||
|
||||
## Unstable prefix
|
||||
|
||||
For historical reasons, unstable implementations of this proposal should use `org.matrix.msc3202.device_id`
|
||||
instead of `device_id`.
|
||||
|
||||
`ORG.MATRIX.MSC4326.M_UNKNOWN_DEVICE` is used as the error code instead of `M_UNKNOWN_DEVICE`.
|
||||
|
||||
## Dependencies
|
||||
|
||||
None relevant. Some MSCs depend on this MSC's functionality, however.
|
||||
|
After Width: | Height: | Size: 135 KiB |
|
After Width: | Height: | Size: 152 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 125 KiB |
|
After Width: | Height: | Size: 149 KiB |
|
After Width: | Height: | Size: 159 KiB |
|
After Width: | Height: | Size: 254 KiB |
|
After Width: | Height: | Size: 172 KiB |
|
After Width: | Height: | Size: 165 KiB |
|
After Width: | Height: | Size: 228 KiB |
|
After Width: | Height: | Size: 67 KiB |
|
After Width: | Height: | Size: 237 KiB |