Merge branch 'main' into travis/msc/media-integrity

travis/msc/media-integrity
Travis Ralston 2 weeks ago
commit 64ea899e59

@ -8,3 +8,4 @@ OTKs = "OTKs"
[default.extend-words] [default.extend-words]
OTK = "OTK" OTK = "OTK"
OTKs = "OTKs" OTKs = "OTKs"
Iy = "Iy"

@ -11,9 +11,9 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Check out repository - name: Check out repository
uses: actions/checkout@v2 uses: actions/checkout@v4
- name: Check spelling of proposals - name: Check spelling of proposals
uses: crate-ci/typos@9be36f97fdbe645ee9a12449fb13aca856c2516a uses: crate-ci/typos@f2c1f08a7b3c1b96050cb786baaa2a94797bdb7d # v1.20.10
with: with:
config: ${{github.workspace}}/.github/_typos.toml config: ${{github.workspace}}/.github/_typos.toml

@ -69,19 +69,8 @@ include the line in your commit or pull request comment:
Signed-off-by: Your Name <your@email.example.org> Signed-off-by: Your Name <your@email.example.org>
...using your real name; unfortunately pseudonyms and anonymous contributions Git allows you to add this signoff automatically when using the `-s`
can't be accepted. Git makes this trivial - just use the -s flag when you do flag to `git commit`, which uses the name and email set in your
``git commit``, having first set ``user.name`` and ``user.email`` git configs `user.name` and `user.email` git configs.
(which you should have done anyway :)
### Private sign off
If you would like to provide your legal name privately to the Matrix.org
Foundation (instead of in a public commit or comment), you can do so by emailing
your legal name and a link to the pull request to dco@matrix.org. It helps to
include "sign off" or similar in the subject line. You will then be instructed
further.
Once private sign off is complete, doing so for future contributions will not be required.
[1]: https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request [1]: https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request

@ -11,11 +11,9 @@ MSC authors, feel free to ask in a thread on your PR or in the
[#matrix-spec:matrix.org](https://matrix.to/#/#matrix-spec:matrix.org) room for [#matrix-spec:matrix.org](https://matrix.to/#/#matrix-spec:matrix.org) room for
clarification of any of these points. clarification of any of these points.
- [ ] Are [appropriate - [ ] Are [appropriate implementation(s)](https://spec.matrix.org/proposals/#implementing-a-proposal) specified in the MSCs PR description?
implementation(s)](https://spec.matrix.org/proposals/#implementing-a-proposal)
specified in the MSCs PR description?
- [ ] Are all MSCs that this MSC depends on already accepted? - [ ] Are all MSCs that this MSC depends on already accepted?
- [ ] For each new endpoint that is introduced: - [ ] For each endpoint that is introduced or modified:
- [ ] Have authentication requirements been specified? - [ ] Have authentication requirements been specified?
- [ ] Have rate-limiting requirements been specified? - [ ] Have rate-limiting requirements been specified?
- [ ] Have guest access requirements been specified? - [ ] Have guest access requirements been specified?
@ -23,18 +21,13 @@ clarification of any of these points.
- [ ] Does each error case have a specified `errcode` (e.g. `M_FORBIDDEN`) and HTTP status code? - [ ] Does each error case have a specified `errcode` (e.g. `M_FORBIDDEN`) and HTTP status code?
- [ ] If a new `errcode` is introduced, is it clear that it is new? - [ ] If a new `errcode` is introduced, is it clear that it is new?
- [ ] Will the MSC require a new room version, and if so, has that been made clear? - [ ] Will the MSC require a new room version, and if so, has that been made clear?
- [ ] Is the reason for a new room version clearly stated? For example, - [ ] Is the reason for a new room version clearly stated? For example, modifying the set of redacted fields changes how event IDs are calculated, thus requiring a new room version.
modifying the set of redacted fields changes how event IDs are calculated,
thus requiring a new room version.
- [ ] Are backwards-compatibility concerns appropriately addressed? - [ ] Are backwards-compatibility concerns appropriately addressed?
- [ ] Are the [endpoint conventions](https://spec.matrix.org/latest/appendices/#conventions-for-matrix-apis) honoured? - [ ] Are the [endpoint conventions](https://spec.matrix.org/latest/appendices/#conventions-for-matrix-apis) honoured?
- [ ] Do HTTP endpoints `use_underscores_like_this`? - [ ] Do HTTP endpoints `use_underscores_like_this`?
- [ ] Will the endpoint return unbounded data? If so, has pagination been considered? - [ ] Will the endpoint return unbounded data? If so, has pagination been considered?
- [ ] If the endpoint utilises pagination, is it consistent with [the - [ ] If the endpoint utilises pagination, is it consistent with [the appendices](https://spec.matrix.org/latest/appendices/#pagination)?
appendices](https://spec.matrix.org/v1.8/appendices/#pagination)? - [ ] An introduction exists and clearly outlines the problem being solved. Ideally, the first paragraph should be understandable by a non-technical audience.
- [ ] An introduction exists and clearly outlines the problem being solved.
Ideally, the first paragraph should be understandable by a non-technical
audience
- [ ] All outstanding threads are resolved - [ ] All outstanding threads are resolved
- [ ] All feedback is incorporated into the proposal text itself, either as a fix or noted as an alternative - [ ] All feedback is incorporated into the proposal text itself, either as a fix or noted as an alternative
- [ ] While the exact sections do not need to be present, the details implied by the proposal template are covered. Namely: - [ ] While the exact sections do not need to be present, the details implied by the proposal template are covered. Namely:
@ -42,9 +35,9 @@ clarification of any of these points.
- [ ] Proposal text - [ ] Proposal text
- [ ] Potential issues - [ ] Potential issues
- [ ] Alternatives - [ ] Alternatives
- [ ] Security considerations
- [ ] Dependencies - [ ] Dependencies
- [ ] Stable identifiers are used throughout the proposal, except for the unstable prefix section - [ ] Stable identifiers are used throughout the proposal, except for the unstable prefix section
- [ ] Unstable prefixes [consider](README.md#unstable-prefixes) the awkward accepted-but-not-merged state - [ ] Unstable prefixes [consider](https://github.com/matrix-org/matrix-spec-proposals/blob/main/README.md#unstable-prefixes) the awkward accepted-but-not-merged state
- [ ] Chosen unstable prefixes do not pollute any global namespace (use “org.matrix.mscXXXX”, not “org.matrix”). - [ ] Chosen unstable prefixes do not pollute any global namespace (use “org.matrix.mscXXXX”, not “org.matrix”).
- [ ] Changes have applicable [Sign Off](CONTRIBUTING.md#sign-off) from all authors/editors/contributors - [ ] Changes have applicable [Sign Off](https://github.com/matrix-org/matrix-spec-proposals/blob/main/CONTRIBUTING.md#sign-off) from all authors/editors/contributors
- [ ] There is a dedicated "Security Considerations" section which detail any possible attacks/vulnerabilities this proposal may introduce, even if this is "None.". See [RFC3552](https://datatracker.ietf.org/doc/html/rfc3552) for things to think about, but in particular pay attention to the [OWASP Top Ten](https://owasp.org/www-project-top-ten/).

@ -85,14 +85,22 @@ idea.
## Security considerations ## Security considerations
**All proposals must now have this section, even if it is to say there are no security issues.**
*Think about how to attack your proposal. See [RFC 3552](https://datatracker.ietf.org/doc/html/rfc3552)
for things to think about, but in particular pay attention to lists from sources like
[OWASP Top Ten](https://owasp.org/www-project-top-ten/) for inspiration.*
*Some proposals may have some security aspect to them that was addressed in the proposed solution. This *Some proposals may have some security aspect to them that was addressed in the proposed solution. This
section is a great place to outline some of the security-sensitive components of your proposal, such as section is a great place to outline some of the security-sensitive components of your proposal, such as
why a particular approach was (or wasn't) taken. The example here is a bit of a stretch and unlikely to why a particular approach was (or wasn't) taken. The example here is a bit of a stretch and unlikely to
actually be worthwhile of including in a proposal, but it is generally a good idea to list these kinds actually be worthwhile of including in a proposal, but it is generally a good idea to list these kinds
of concerns where possible.* of concerns where possible.*
By having a template available, people would know what the desired detail for a proposal is. This is not MSCs can drastically affect the protocol. The authors of MSCs may not have a security background. If they
considered a risk because it is important that people understand the proposal process from start to end. do not consider vulnerabilities with their design, we rely on reviewers to consider vulnerabilities. This
is easy to forget, so having a mandatory 'Security Considerations' section serves to nudge reviewers
into thinking like an attacker.
## Unstable prefix ## Unstable prefix

@ -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.

@ -174,7 +174,7 @@ certificates comes with a number of downsides.
Configuring a working, federating homeserver is a process fraught with Configuring a working, federating homeserver is a process fraught with
pitfalls. This proposal adds the requirement to obtain a signed certificate to pitfalls. This proposal adds the requirement to obtain a signed certificate to
that process. Even with modern intiatives such as Let's Encrypt, this is that process. Even with modern initiatives such as Let's Encrypt, this is
another procedure requiring manual intervention across several moving parts. another procedure requiring manual intervention across several moving parts.
On the other hand: obtaining an SSL certificate should be a familiar process to On the other hand: obtaining an SSL certificate should be a familiar process to

@ -88,7 +88,7 @@ right encoding.
A potential extension would be to change *all* Base64 encodings to be A potential extension would be to change *all* Base64 encodings to be
URL-safe. This would address the inconsistency. However, it feels like a URL-safe. This would address the inconsistency. However, it feels like a
large job which would span the entire matrix ecosystem (far larger than large job which would span the entire matrix ecosystem (far larger than
updating clients to URL-encode their URL prarameters), and again the updating clients to URL-encode their URL parameters), and again the
situation would be confusing while the transition was in progress. situation would be confusing while the transition was in progress.
2. Incompleteness. Event IDs are certainly not the only identifier which can 2. Incompleteness. Event IDs are certainly not the only identifier which can

@ -44,10 +44,10 @@ proposal are `m.role.admin` and `m.role.security`.
- `m.role.admin` is a catch-all user for any queries. - `m.role.admin` is a catch-all user for any queries.
- `m.role.security` is intended for sensitive requests - `m.role.security` is intended for sensitive requests
Implementors may use custom values for role for other purposes, but it's suggested A value for `role` MUST be specified. Custom values are permitted using the
that the value be namespaced to prevent collisions. A value for `role` MUST be specified. [common namespaced identifier format](https://spec.matrix.org/v1.8/appendices/#common-namespaced-identifier-grammar).
`support_page` is an optional property to specify a affiliated page of the homserver to give users help `support_page` is an optional property to specify an affiliated page of the homeserver to give users help
specific to the homeserver, like extra login/registration steps. specific to the homeserver, like extra login/registration steps.
At least one valid key should be provided. This means `contacts` should have at least one entry, or the `support_page` should be defined. An empty object is not considered valid, however both `contacts `and `support_page` may be specified together. At least one valid key should be provided. This means `contacts` should have at least one entry, or the `support_page` should be defined. An empty object is not considered valid, however both `contacts `and `support_page` may be specified together.

@ -34,7 +34,7 @@ way that Homeservers do.
## Proposal ## Proposal
Throuhgout this proposal, $prefix will be used to refer to the prefix of the Throughout this proposal, $prefix will be used to refer to the prefix of the
API in question, ie. `/_matrix/identity/v2` for the IS API and API in question, ie. `/_matrix/identity/v2` for the IS API and
`/_matrix/integrations/v1` for the IM API. `/_matrix/integrations/v1` for the IM API.

@ -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.

@ -438,8 +438,8 @@ first we summarise the semantics of the proposed changes.
### Current membership ### Current membership
Only users without a current membership or with their current membership Only users without a current membership or with their current membership
set to "knock", "leave", or "invite" can knock on a room. This means that a user that set to "knock" or "leave" can knock on a room. This means that a user that
is banned or is currently in the room cannot knock on it. is banned, is invited or is currently in the room cannot knock on it.
### Join Rules ### Join Rules
This proposal makes use of the existing "knock" join rule. The value of This proposal makes use of the existing "knock" join rule. The value of

@ -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,144 @@
# Body field as media caption
When sending images or other attachments, users often want to include text to
convey additional information. Most chat platforms offer media captions as a
first-class feature, allowing users to choose the attachment and write text,
then send both together in one message.
Matrix currently does not enable this on the protocol level: at best, clients
can emulate the behavior by sending two messages quickly; at worst, the user
has to do that manually. Sending separate messages means it's possible for
the second message to be delayed or lost if something goes wrong.
## Proposal
This proposal allows the `filename` field from [`m.file`], and the `format` and
`formatted_body` fields from [`m.text`] for all media msgtypes (`m.image`,
`m.audio`, `m.video`, `m.file`). This proposal does not affect the `m.location`
msgtype, nor the separate `m.sticker` event type: stickers already use `body`
as a description, and locations don't have file names.
If the `filename` field is present in a media message, clients should treat
`body` as a caption instead of a file name. If the `format`/`formatted_body`
fields are present in addition to `filename` and `body`, then they should take
priority as the caption text. Formatted text in media captions is rendered the
same way as formatted text in `m.text` messages.
The current spec is somewhat ambiguous as to how `body` should be handled and
the definition varies across different message types. The current spec for
[`m.image`] describes `body` as
> A textual representation of the image. This could be the alt text of the
> image, the filename of the image, or some kind of content description for
> accessibility e.g. image attachment.
while [`m.audio`] describes it as
> A description of the audio e.g. Bee Gees - Stayin Alive, or some kind of
> content description for accessibility e.g. audio attachment.
In practice, clients (or at least Element) use it as the file name. As a part
of adding captions, the `body` field for all media message types is explicitly
defined to be used as the file name when the `filename` field is not present.
For `m.file` messages, the [current (v1.9) spec][`m.file`] confusingly defines
`filename` as "The original filename of the uploaded file" and simultaneously
recommends that `body` is "the filename of the original upload", effectively
saying both fields should have the file name. In order to avoid (old) messages
with both fields being misinterpreted as having captions, the `body` field
should not be used as a caption when it's equal to `filename`.
[`m.file`]: https://spec.matrix.org/v1.9/client-server-api/#mfile
[`m.text`]: https://spec.matrix.org/v1.9/client-server-api/#mtext
[`m.image`]: https://spec.matrix.org/v1.9/client-server-api/#mimage
[`m.audio`]: https://spec.matrix.org/v1.9/client-server-api/#maudio
### Examples
<details>
<summary>Image with caption</summary>
```json
{
"msgtype": "m.image",
"url": "mxc://maunium.net/HaIrXlnKfEEHvMNKzuExiYlv",
"filename": "cat.jpeg",
"body": "this is a cat picture :3",
"info": {
"w": 479,
"h": 640,
"mimetype": "image/jpeg",
"size": 27253
},
"m.mentions": {}
}
```
</details>
<details>
<summary>File with formatted caption</summary>
```json
{
"msgtype": "m.file",
"url": "mxc://maunium.net/TizWsLhHfDCETKRXdDwHoAGn",
"filename": "hello.txt",
"body": "this caption is longer than the file itself 🤔",
"format": "org.matrix.custom.html",
"formatted_body": "this <strong>caption</strong> is longer than the file itself 🤔",
"info": {
"mimetype": "text/plain",
"size": 14
},
"m.mentions": {}
}
```
</details>
### Summary
* `filename` is defined for all media msgtypes.
* `body` is defined to be a caption when `filename` is present and not equal to `body`.
* `format` and `formatted_body` are allowed as well for formatted captions.
* `body` is defined to be the file name when `filename` is not present.
## Potential issues
In clients that don't show the file name anywhere, the caption would not be
visible at all. However, extensible events would run into the same issue.
Clients having captions implemented beforehand may even help eventually
implementing extensible events.
Old clients may default to using the caption as the file name when the user
wants to download a file, which will be somewhat weird UX.
## Alternatives
### [MSC2529](https://github.com/matrix-org/matrix-spec-proposals/pull/2529)
MSC2529 would allow existing clients to render captions without any changes,
but the use of relations makes implementation more difficult, especially for
bridges. It would require either waiting a predefined amount of time for the
caption to come through, or editing the message on the target platform (if
edits are supported).
The format proposed by MSC2529 would also make it technically possible to use
other message types as captions without changing the format of the events,
which is not possible with this proposal.
### Extensible events
Like MSC2529, this would be obsoleted by [extensible events](https://github.com/matrix-org/matrix-spec-proposals/pull/3552).
However, fully switching to extensible events requires significantly more
implementation work, and it may take years for the necessary time to be
allocated for that.
## Security considerations
This proposal doesn't involve any security-sensitive components.
## Unstable prefix
The fields being added already exist in other msgtypes, so unstable prefixes
don't seem necessary. Additionally, using `body` as a caption could already be
considered spec-compliant due to the ambiguous definition of the field, and
only adding unstable prefixes for the other fields would be silly.

@ -51,7 +51,7 @@ property should contains a `key` that indicates the annotation being
applied. For example, when reacting with emojis, the `key` contains the emoji applied. For example, when reacting with emojis, the `key` contains the emoji
being used. being used.
An event annotating another with the thumbs-up emoji would therefore have the following `m.relates_to` propperty: An event annotating another with the thumbs-up emoji would therefore have the following `m.relates_to` property:
```json ```json
"m.relates_to": { "m.relates_to": {

@ -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&param2=value2`
- if set to `query`, the parameters will be in placed the query string, like `com.example.app:/callback?param1=value1&param2=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

@ -152,7 +152,7 @@ the room was created.
## Alternatives ## Alternatives
We chose the current `/timestamp_to_event` route because it sounded like the We chose the current `/timestamp_to_event` route because it sounded like the
easist path forward to bring it to fruition and get some real-world experience. easiest path forward to bring it to fruition and get some real-world experience.
And was on our mind during the [initial discussion](https://docs.google.com/document/d/1KCEmpnGr4J-I8EeaVQ8QJZKBDu53ViI7V62y5BzfXr0/edit#bookmark=id.qu9k9wje9pxm) because there was some prior art with a [WIP And was on our mind during the [initial discussion](https://docs.google.com/document/d/1KCEmpnGr4J-I8EeaVQ8QJZKBDu53ViI7V62y5BzfXr0/edit#bookmark=id.qu9k9wje9pxm) because there was some prior art with a [WIP
implementation](https://github.com/matrix-org/synapse/pull/9445/commits/91b1b3606c9fb9eede0a6963bc42dfb70635449f) implementation](https://github.com/matrix-org/synapse/pull/9445/commits/91b1b3606c9fb9eede0a6963bc42dfb70635449f)
from @erikjohnston. The alternatives haven't been thrown out for a particular from @erikjohnston. The alternatives haven't been thrown out for a particular

@ -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,132 @@
# MSC3765: Rich text in room topics
## Problem
Topics are a central piece of room meta data and usually made easily
accessible to room members in clients. As a result, room administrators
often extend the use of topics to collect helpful peripheral information
that is related to the rooms purpose. Most commonly these are links to
external resources. At the moment, topics are limited to [plain text]
which, depending on the number and length of URLs and other content,
easily gets inconvenient to consume and calls for richer text formatting
options.
## Proposal
Drawing from extensible events as described in [MSC1767], a new content
block `m.topic` is defined, which wraps an `m.text` content block that
allows representing the room topic in different mime types. In current
room versions, this content block is added to the content of [`m.room.topic`]
events as shown below[^1].
```json5
{
"type": "m.room.topic",
"state_key": "",
"content": {
"m.topic": {
"m.text": [ {
"mimetype": "text/html",
"body": "All about <b>pizza</b> | <a href=\"https://recipes.pizza.net\">Recipes</a>"
}, {
"body": "All about **pizza** | [Recipes](https://recipes.pizza.net)"
}]
},
"topic": "All about **pizza** | [Recipes](https://recipes.pizza.net)"
},
...
}
```
In line with [MSC1767], clients should render the first mime type in the
array that they understand. Further details of how `m.text` works may
be found in [MSC1767] and are not repeated here.
The wrapping `m.topic` content block is similar to `m.caption` for file
uploads as defined in [MSC3551]. It avoids clients accidentally rendering
the topic as a room message. ([MSC1767] specifies that unknown events with
an `m.text` content block should be rendered as a regular room message, and
while [MSC1767] had explicitly excluded state events from being treated as
extensible, this is being changed with [MSC4252].) The extra content block, therefore, allows putting
a fallback representation that is actually designated for the timeline
into a separate `content['m.text']` field. In addition, the `m.topic` content
block also serves as a good place for additional fields to be added by
other MSCs in the future.
It is recommended that clients always include a plain text variant within `m.text` when
sending `m.room.topic` events. This prevents bad UX in situations where a plain
text topic is sufficient such as the public rooms directory.
Additionally, clients should duplicate the plain text topic into the existing
`topic` field for backwards compatibility with clients that don't support
`m.topic` yet. This also helps prevent inconsistencies since such clients
are likely to delete the `m.topic` content block when updating `m.room.topic`
themselves.
In order to prevent formatting abuse in room topics, clients are
encouraged to limit the length of topics during both entry and display,
for instance, by capping the number of displayed lines. Additionally,
clients should ignore things like headings and enumerations (or format them
as regular text). A future MSC may introduce a mechanism to capture extended
multiline details that are not suitable for room topics in a separate field
or event type.
On the server side, any logic that currently operates on the `topic` field is
updated to use the `m.topic` content block instead:
- In [`/_matrix/client/v3/createRoom`], the `topic` parameter should cause `m.room.topic`
to be written with a `text/plain` mimetype in `m.topic`. If at the same time an
`m.room.topic` event is supplied in `initial_state`, it is overwritten entirely.
A future MSC may generalize the `topic` parameter to allow specifying other mime
types without `initial_state`.
- In [`GET /_matrix/client/v3/publicRooms`], [`GET /_matrix/federation/v1/publicRooms`]
and their `POST` siblings, the `topic` response field should be read from the
`text/plain` mimetype of `m.topic` if it exists or omitted otherwise.
A plain text topic is sufficient here because this data is commonly
only displayed to users that are *not* a member of the room yet. These
users don't commonly have the same need for rich room topics as users
who already reside in the room. A future MSC may update these endpoints
to support rich text topics.
- The same logic is applied to [`/_matrix/client/v1/rooms/{roomId}/hierarchy`]
and [`/_matrix/federation/v1/hierarchy/{roomId}`].
- In [server side search], the `room_events` category is expanded to search
over the `m.text` content block of `m.room.topic` events.
## Potential issues
None.
## Alternatives
The combination of `format` and `formatted_body` currently utilised to
enable HTML in `m.room.message` events could be generalised to
`m.room.topic` events. However, this would only allow for a single
format in addition to plain text and is a weaker form of reuse than
described in the introductory section of [MSC1767].
## Security considerations
Allowing HTML in room topics is subject to the same security
considerations that apply to HTML in room messages. In particular,
topics are already included in the content that clients should [sanitise]
for unsafe HTML.
## Unstable prefix
While this MSC is not considered stable, `m.topic` should be referred to
as `org.matrix.msc3765.topic`.
[^1]: A future MSC may discuss how to adopt the `m.topic` content block in
new room versions which support extensible events.
[plain text]: https://spec.matrix.org/v1.12/client-server-api/#mroomtopic
[MSC1767]: https://github.com/matrix-org/matrix-spec-proposals/pull/1767
[MSC4252]: https://github.com/matrix-org/matrix-spec-proposals/pull/4252
[sanitise]: https://spec.matrix.org/v1.12/client-server-api/#security-considerations
[server side search]: https://spec.matrix.org/v1.12/client-server-api/#server-side-search
[`m.room.topic`]: https://spec.matrix.org/v1.12/client-server-api/#mroomtopic
[`/_matrix/client/v1/rooms/{roomId}/hierarchy`]: https://spec.matrix.org/v1.12/client-server-api/#get_matrixclientv1roomsroomidhierarchy
[`/_matrix/client/v3/createRoom`]: https://spec.matrix.org/v1.12/client-server-api/#post_matrixclientv3createroom
[`/_matrix/federation/v1/hierarchy/{roomId}`]: https://spec.matrix.org/v1.12/server-server-api/#get_matrixfederationv1hierarchyroomid
[`GET /_matrix/client/v3/publicRooms`]: https://spec.matrix.org/v1.12/client-server-api/#get_matrixclientv3publicrooms
[`GET /_matrix/federation/v1/publicRooms`]: https://spec.matrix.org/v1.12/server-server-api/#get_matrixfederationv1publicrooms

@ -1,4 +1,4 @@
# MSC3604: Room Version 11 # MSC3820: Room Version 11
A new room version, `11`, is proposed using [room version 10](https://spec.matrix.org/v1.7/rooms/v10/) as a base A new room version, `11`, is proposed using [room version 10](https://spec.matrix.org/v1.7/rooms/v10/) as a base
and incorporating the following MSCs: and incorporating the following MSCs:

@ -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,272 @@
# MSC4153: Exclude non-cross-signed devices
End-to-end encryption was [first introduced to Matrix in
2016](https://matrix.org/blog/2016/11/21/matrix-s-olm-end-to-end-encryption-security-assessment-released-and-implemented-cross-platform-on-riot-at-last/). Over
the years, more encryption-related features have been added, such as key
verification, cross-signing, key backup, and secure storage/sharing.
The current spec allows clients freedom to choose what features to implement.
And while clients should be able to make decisions based on their threat model,
there are behaviours that the spec can recommend that will improve the user
experience and security of encrypted conversations.
In general, this MSC proposes to standardize on using cross-signing as a basis
for trusting devices. While a user may be unable to verify every other user
that they communicate with, or may be unaware of the need to verify other
users, cross-signing gives some measure of protection and so should be used
where possible. One of the goals of this MSC is to reduce the number of
warnings that users will encounter by taking advantage of cross-signing.
## Proposal
Note: The changes below only apply to clients that support
[encryption](https://spec.matrix.org/v1.15/client-server-api/#end-to-end-encryption).
### Users SHOULD have cross-signing keys
Clients SHOULD create new [cross-signing
keys](https://spec.matrix.org/v1.15/client-server-api/#cross-signing) for users
who do not yet have cross-signing keys.
Since [replacing a cross-signing
key](https://spec.matrix.org/v1.15/client-server-api/#post_matrixclientv3keysdevice_signingupload)
requires User-Interactive Authentication, this will prevent clients from
conflicting if they try to create cross-signing keys at the same time.
### Users SHOULD have Secret Storage
The [spec](https://spec.matrix.org/v1.15/client-server-api/#storage) currently
does not give recommendations for what information is stored in Secret Storage,
or even whether Secret Storage is available to users. Secret Storage allows
users to keep secrets on the server so that they are accessible when the user
logs in to a new device. This is necessary to retrieve secrets when the user
does not have an existing device that can then share the secrets with the new
device. Therefore users SHOULD have Secret storage set up to avoid needing to
reset their cryptographic identity in this case.
The users Secret Storage SHOULD contain the users cross-signing secret keys
and the key backup decryption key (if the user is using key backup). This
ensures that users use cross-signing and key backup on new devices.
The user's Secret Storage SHOULD have a default key (a key referred to by
`m.secret_storage.default_key`) that encrypts the private cross-signing keys and
key backup key (if available).
### Verifying individual devices of other users is deprecated
When one user verifies a different user, the verification SHOULD verify the
users cross-signing keys. Any flow between different users that does not
verify the users' cross-signing keys (it verifies only the device keys) is
deprecated. Verifying a users own device keys is still supported.
Specifically, for the currently specced verification methods:
- In Step 15 of (SAS
verification)[https://spec.matrix.org/v1.15/client-server-api/#short-authentication-string-sas-verification],
the master cross-signing key SHOULD be included when two different users are
verifying it other.
- [QR code
verification](https://spec.matrix.org/v1.15/client-server-api/#qr-codes)
already satisfies this requirement.
### Devices SHOULD be cross-signed
Clients SHOULD encourage users to cross-sign their devices. This includes both
when logging in a new device, and for existing devices. Clients may even go so
far as to require cross-signing of devices by preventing the user from using
the client until the device is cross-signed. If the user cannot cross-sign
their device (for example, if they have forgotten their Secret Storage key),
the client can allow users to reset their Secret Storage, cross-signing, and
key backup.
### Clients SHOULD flag when cross-signing keys change
If Alices cross-signing keys change, Alices own devices MUST alert her to
this fact, and prompt her to re-cross-sign those devices. If Bob is in an
encrypted room with Alice, Bobs devices SHOULD inform him of Alices key
change and SHOULD prevent him from sending an encrypted message to Alice
without acknowledging the change.
Bobs clients may behave differently depending on whether Bob had previously
verified Alice or not. For example, if Bob had previously verified Alice, and
Alices keys change, Bobs client may require Bob to re-verify, or may display
a more aggressive warning.
Note that this MSC does not propose a mechanism for remembering previous
cross-signing keys between devices. In other words if Alice changes her
cross-signing keys and then Bob logs in a new device, Bobs new device will not
know that Alices cross-signing keys had changed, even if Bob has other devices
that were previously logged in. This may result in Bob never seeing a warning
about Alice's identity change, for example if Bob logs out of his last device,
then Alice changes her cross-signing keys, and then Bob logs into a new device.
In addition, this MSC does not propose a mechanism for synchronising between
devices information regarding what warnings the user has seen or acknowledged.
That is, if Alice changes her cross-signing keys and Bob has multiple devices
logged in, then Bob will see a warning on all his devices, and will have to
dismiss the warning on all of his devices.
A mechanism for synchronising information between devices could be proposed by
another MSC.
### Encrypted to-device messages SHOULD NOT be sent to non-cross-signed devices
Since non-cross-signed devices dont provide any assurance that the device
belongs to the user, and server admins can trivially create new devices for
users, clients SHOULD NOT send encrypted to-device messages, such as room keys or
secrets (via Secret Sharing), to non-cross-signed devices by default. When
sending room keys, clients can use a [`m.room_key.withheld`
message](https://spec.matrix.org/v1.15/client-server-api/#reporting-that-decryption-keys-are-withheld)
with a code of `m.unverified` to indicate to the non-cross-signed device why it
is not receiving the room key.
An allowed exception to this rule is that clients may provide users the ability
to encrypt to specific non-cross-signed devices for development or testing
purposes.
A future MSC may specify exceptions to this rule. For example, if a future MSC
defines a device verification method that uses encrypted to-device messages,
such messages would need to be sent to a user's own non-cross-signed devices, so
that the user can verify their device to cross-sign it.
### Encrypted messages from non-cross-signed devices SHOULD be ignored
Similarly, clients have no assurance that encrypted messages sent from
non-cross-signed devices were sent by the user, rather than an
impersonator. Therefore messages sent from non-cross-signed devices cannot be
trusted and SHOULD NOT be displayed to the user.
Again, an allowed exception to this is that clients may allow the user to
override this behaviour for specific devices for development or testing
purposes.
### Non-cryptographic devices SHOULD NOT impact E2EE behaviour
For the sake of clarity: non-cryptographic devices (devices which do not have
device identity keys uploaded to the homeserver) should not have any impact on
a client's E2EE behaviour. For all intents and purposes, non-cryptographic
devices are a completely separate concept and do not exist from the perspective
of the cryptography layer since they do not have identity keys, so it is
impossible to send them decryption keys.
In particular, Matrix clients MUST NOT consider non-cryptographic devices to be
equivalent to non-cross-signed cryptographic devices for purposes of enforcing
E2EE policy. For example, clients SHOULD NOT warn nor refuse to send messages
due to the presence of non-cryptographic devices.
The intent of this is to smoothly support and minimise interference from
applications which choose to set up E2EE only on demand (e.g.
[WorkAdventure](https://workadventu.re/article-en/managing-e2e-encryption-with-matrix-in-a-simple-way/)).
Such clients should initially create a non-cryptographic device until they are
ready to set up E2EE. Only when they are ready will they create the device
identity keys for the device and upload them to the homeserver, converting the
device into a cryptographic device and making it subject to the rules given in
this MSC.
### Clients MAY make provisions for encrypted bridges
Some bridges are structured in a way such that only one user controlled by the
bridge (often called the bridge bot) participates in encryption, and encrypted
messages from other bridge users are encrypted by the bridge bot. Thus
encrypted messages sent by one user could be encrypted by a Megolm session sent
by a different user. Clients MAY accept such messages, provided the session
creator's device is cross-signed. However, the client MUST annotate the message with
a warning, unless the client has a way to check that the bridge bot is permitted
to encrypt messages on behalf of the user.
[MSC4350](https://github.com/matrix-org/matrix-spec-proposals/pull/4350)
presents a way for bridge users to indicate that the bridge bot is allowed to
perform encryption on their behalf.
## Potential Issues
### Client support
If a user has devices that are not cross-signed, they will not be able to
communicate with other users whose clients implement this proposal completely,
due to the "Encrypted to-device messages MUST NOT be sent to non-cross-signed
devices" and "Encrypted messages from non-cross-signed devices SHOULD be
ignored" sections. Thus we encourage clients to implement cross-signing as soon
as possible, and to encourage users to cross-sign their devices, and clients
should delay the implementation of those two sections (or make it optional)
until most clients have implemented cross-signing.
The following clients support cross-signing:
- Cinny
- Element (all platforms), and derivatives such as Schildi Chat
- Fractal
- gomuks
- NeoChat
- Nheko
- pantalaimon
- Tammy
- Trixnity Messenger
The following encryption-capable clients do not support cross-signing:
- kazv
- Quaternion (versions prior to 0.98)
### Bots and application services
This is a special case to the issue above, but seems to be a large enough class
that it deserves its own mention: support for cross-signing in bots and
application services may be less common than in interactive clients. When a
client fully implements this proposal, users will be unable to interact with
bots and application services in encrypted rooms if they do not support
cross-signing.
Some possible solutions for bots are:
- if a bot is the only device logged into a given account, the bot can create its
own cross-signing keys and cross-sign its device.
- the bot administrator can provide the Secret Storage key to the bot so that
the bot can fetch its self-signing private key and cross-sign its device.
- the bot can log its device keys so that the administrator can cross-sign it
from a different device by manually comparing the device keys. Note that many
clients do not have the ability to verify by comparing device keys.
The following bots support cross-signing:
- [meowlnir](https://github.com/maunium/meowlnir)
- [Arnie](https://gitlab.com/andybalaam/arnie)
- [maubot](https://github.com/maubot/maubot)
The following bot SDKs support, or plan to support, cross-signing such that any
bots written using them will support cross-signing:
- [mautrix-go](https://github.com/mautrix/go) (planned support for Application Services)
## Alternatives
We could do nothing and leave things as they are, but the rules given in this
MSC provide improved security.
## Security considerations
Warning the user about cross-signing key changes can be circumvented by a
malicious server if it sends forged cross-signing keys the first time the user
sees them. Therefore users should still verify other users when security is
important.
## Unstable prefix
No new names are introduced, so no unstable prefix is needed.
## Dependencies
Though not strictly dependencies, other MSCs improve the behaviour of this MSC:
- [Authenticated backups
(MSC4048)](https://github.com/matrix-org/matrix-spec-proposals/pull/4048)
will improve the user experience by ensuring that trust information is
preserved when loading room keys from backup. We may also need to add
information to the backup about the cross-signing status of the device,
but this can be addressed in a future MSC.
- [Including device keys with Olm-encrypted events
(MSC4147)](https://github.com/matrix-org/matrix-spec-proposals/pull/4147)
allows recipients to check the cross-signing status of devices that have been
deleted.
- [Permitting encryption impersonation for appservices
(MSC4350)](https://github.com/matrix-org/matrix-spec-proposals/pull/4350)
allows a user to assert that a bridge is allowed to encrypt for them.

@ -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,253 @@
# MSC4222: Adding `state_after` to `/sync`
The current [`/sync`](https://spec.matrix.org/v1.14/client-server-api/#get_matrixclientv3sync) API does not
differentiate between state events in the timeline and updates to state, and so can cause the client's view
of the current state of the room to diverge from the actual state of the room as seen by the server.
The fundamental issue is that clients need to know the current authoritative room state, but the current model
lacks an explicit representation of that. Clients derive state by assuming a linear application of events, for
example:
```
state_before + timeline => state_after
```
However, room state evolves as a DAG (Directed Acyclic Graph), not a linear chain. A simple example illustrates:
```diagram
A
|
B
/ \
C D
```
Each of A, B, C, and D are non-conflicting state events.
- State after C = `{A, B, C}`
- State after D = `{A, B, D}`
- Current state = `{A, B, C, D}`
In this case, both C and D are concurrent, so the correct current state includes both. Clients that try to reconstruct
state from a timeline such as `[A, B, C, D]` or `[A, B, D, C]` might trivially compute a union — and for non-conflicting
cases, this works.
However, once conflicting state enters, resolution is needed. Consider this more complex example:
```diagram
A
|
B
/ \
C C' <-- C' wins via state resolution
\ / \
D E
```
Here, C and C' are conflicting state events — for example, both might define a different `m.room.topic`. Let's say C' wins
according to the server's state resolution rules. Then D and E are independent non-conflicting additions.
- State after C = `{A, B, C}`
- State after D = `{A, B, C'}`
- State after E = `{A, B, C', E}`
- Current state = `{A, B, C', D, E}`
Now suppose the client first receives timeline events `[A, B, C', E]`. The state it constructs is:
```
{A, B, C', E} ← Correct so far
```
Then it receives a subsequent sync with timeline `[C, D]`, and the state block includes only `{B}`. Under the current
`/sync` behavior:
- The timeline includes state event C, which incorrectly replaces C'.
- The client ends up with `{A, B, C, D, E}`, which is **invalid** — it prefers the wrong version of C.
This happens because the client re-applies C from the timeline, unaware that C' had already been resolved and accepted
earlier. There's no way for the client to know that C' is supposed to win, based solely on the timeline.
In [MSC4186 - Simplified Sliding Sync](https://github.com/matrix-org/matrix-spec-proposals/pull/4186) this problem is
solved by the equivalent `required_state` section including all state changes between the previous sync and the end of
the current sync, and clients do not update their view of state based on entries in the timeline.
## Proposal
This change is gated behind the client adding a `?use_state_after=true` (the unstable name is
`org.matrix.msc4222.use_state_after`) query param.
When enabled, the Homeserver will **omit** the `state` section in the room response sections. This is replaced by
`state_after` (the unstable field name is `org.matrix.msc4222.state_after`), which will include all state changes between the
previous sync and the *end* of the timeline section of the current sync. This is in contrast to the old `state` section
that only included state changes between the previous sync and the *start* of the timeline section. Note that this does
mean that a new state event will (likely) appear in both the timeline and state sections of the response.
This is basically the same as how state is returned in [MSC4186 - Simplified Sliding
Sync](https://github.com/matrix-org/matrix-spec-proposals/pull/4186).
Clients **MUST** only update their local state using `state_after` and **NOT** consider the events that appear in the timeline section of `/sync`.
Clients can tell if the server supports this change by whether it returns a `state` or `state_after` section in the
response. Servers that support this change **MUST** return the `state_after` property, even if empty.
### Examples
#### Example 1 \- Common case
Lets take a look at the common case of a state event getting sent down an incremental sync, which is non-gappy.
<table>
<tr><th>Previously</th><th>Proposed</th></tr>
<tr>
<td>
```json
{
"timeline": {
"events": [ {
"type": "org.matrix.example",
"state_key": ""
} ],
"limited": false,
},
"state": {
"events": []
}
}
```
</td>
<td>
```json
{
"timeline": {
"events": [ {
"type": "org.matrix.example",
"state_key": ""
} ],
"limited": false,
},
"state_after": {
"events": [ {
"type": "org.matrix.example",
"state_key": ""
} ]
}
}
```
</td>
</tr>
</table>
Since the current state of the room will include the new state event, it's included in the `state_after` section.
> [!NOTE]
> In the proposed API the state event comes down both in the timeline section *and* the state section.
#### Example 2 - Receiving “outdated” state
Next, lets look at what would happen if we receive a state event that does not take effect, i.e. that shouldnt cause the client to update its state.
<table>
<tr><th>Previously</th><th>Proposed</th></tr>
<tr>
<td>
```json
{
"timeline": {
"events": [ {
"type": "org.matrix.example",
"state_key": ""
} ],
"limited": false,
},
"state": {
"events": []
}
}
```
</td>
<td>
```json
{
"timeline": {
"events": [ {
"type": "org.matrix.example",
"state_key": ""
} ],
"limited": false,
},
"state_after": {
"events": []
}
}
```
</td>
</tr>
</table>
Since the current state of the room does not include the new state event, it's excluded from the `state_after` section.
> [!IMPORTANT]
> Even though both responses look very similar, the client **MUST NOT** update its state with the event from the timeline section when using `state_after`.
## Potential issues
With the proposed API the common case for receiving a state update will cause the event to come down in both the
`timeline` and `state_after` sections, potentially increasing bandwidth usage. However, it is common for the HTTP responses to
be compressed, heavily reducing the impact of having duplicated data.
Both before and after this proposal, clients are not able to calculate reliably exactly when in the
timeline the state changed (e.g. to figure out which message should show a user's previous/updated
display name - note that some clients e.g. Element have moved away from this UX). This is because
the accurate picture of the current state at an event is calculated by the server based on the room
DAG, including the state resolution process, and not based on a linear list of state updates.
This proposal ensures that the client has a more accurate view of the room state *after the sync has
finished*, but it does not provide any more information about the *history of state* as it relates
to events in the timeline. Clients attempting to build a best-effort view of this history by walking
the timeline may still do so, with the same caveats as before about correctness, but they should be
sure to make their view of the final state consistent with the changes provided in `state_after`.
The format of returned state in `state_after` in this proposal is a list of events. This
does not allow the server to indicate if an entry has been removed from the state. As with
[MSC4186 - Simplified Sliding Sync](https://github.com/matrix-org/matrix-spec-proposals/pull/4186),
this limitation is acknowledged but not addressed here. This is not a new issue and is left for
resolution in a future MSC.
## Alternatives
There are a number of options for encoding the same information in different ways, for example the response could
include both the `state` and a `state_delta` section, where `state_delta` would be any changes that needed to be applied
to the client calculated state to correct it. However, since
[MSC4186](https://github.com/matrix-org/matrix-spec-proposals/pull/4186) is likely to replace the current `/sync` API, we may as
well use the same mechanism. This also has the benefit of showing that the proposed API shape can be successfully
implemented by clients, as the MSC is implemented and in use by clients.
Another option would be for server implementations to try and fudge the state and timeline responses to ensure that
clients came to the correct view of state. For example, if the server detects that a sync response will cause the client
to come to an incorrect view of state it could either a) "fixup" the state in the `state` section of the *next* sync
response, or b) remove or add old state events to the timeline section. While both these approaches are viable, they're
both suboptimal to just telling the client the correct information in the first place. Since clients will need to be
updated to handle the new behavior for future sync APIs anyway, there is little benefit from not updating clients now.
We could also do nothing, and instead wait for [MSC4186](https://github.com/matrix-org/matrix-spec-proposals/pull/4186)
(or equivalent) to land and for clients to update to it.
## Security considerations
There are no security concerns with this proposal, as it simply encodes the same information sent to clients in a
different way
## Unstable prefix
| Name | Stable prefix | Unstable prefix |
| - | - | - |
| Query param | `use_state_after` | `org.matrix.msc4222.use_state_after` |
| Room response field | `state_after` | `org.matrix.msc4222.state_after` |
## Dependencies
None

@ -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,254 @@
## MSC4289: Explicitly privilege room creators
**NOTE**: This MSC was part of the security update to Matrix announced at https://matrix.org/blog/2025/07/security-predisclosure/.
This MSC was updated on August 14th, 2025 to include previously-embargoed details.
### Problem
Matrix has a longstanding problem that creators can lose control of rooms, either by promoting other
admins who they can then no longer demote or by demoting themselves (https://github.com/matrix-org/matrix-spec/issues/165).
Despite warnings from clients about these limitations, it is still surprising to users.
This MSC gives the room creator(s) an ability to demote those admins (or promote themselves).
Additionally, despite the nominal power level rules, in practice under circumstances the room creator's
server could craft a power level event that predates the promotion in order to roll it back (or indeed
roll back other power level changes). This behaviour is not exposed in the Client-Server API or power
level rules however, and so is somewhat unexpected behaviour.
* This behaviour happens because Matrix currently does not enforce finality on a room's DAG: any server
can retrospectively send events referencing older parts of the DAG. This provides full resilience
to arbitrary network partitions across the network as well as within a given server cluster, but
also means that a user can try to contradict themselves retrospectively to roll back their actions.
* As a result, in practice the room creator *does* have implicit administrative control over the rooms
they create, which is desirable in terms of solving the first problem above. However, the Client-Server
API (and UI) does not correctly reflect this.
* This MSC embraces the room creator's privilege in practice and formalizes their power level to be
infinitely high, always.
### Proposal
In short:
- Formally define the room creator as the user who sent the `m.room.create` event for a given room.
By definition, this is immutable per room.
- Update auth rules so that the room creator and `additional_creators` (see below) are always
considered to have infinite power level.
This means when sorting this user by PL, they always sort last ascending and first descending. Users
with [MAX_INT](https://spec.matrix.org/v1.14/appendices/#canonical-json) power level are still less than creators.
- Clients may guide creators who try to demote themselves to get someone else to upgrade the room instead.
- Clients no longer need to warn creators that if they promote someone to admin they wont be able to undo it. They
may need to highlight that any additional creators cannot be removed.
- Given the changes to auth rules need to be executed consistently across all servers, this requires a new room version.
It is important to note that this does NOT centralise the room on the creators server. The room
remains fully functional if the creators server is unreachable, as nothing in the protocol requires
communicating exclusively with the creators server. Indeed, the room remains fully functional in
the face of arbitrary network partitions. Conversation history is still replicated equally over all
participating servers, and the access control hierarchy can be shared equally across multiple servers,
and is enforced independently by all participating servers. However, access control, by definition,
specifies how some users are privileged over other users in a given context - and in such a hierarchy,
some entity always ends up on top.
This fixes [Should room creators always be able to give themselves power?](https://github.com/matrix-org/matrix-spec/issues/165)
once and for all (previous attempts being [MSC3915](https://github.com/matrix-org/matrix-spec-proposals/pull/3915)
“owner power level” and [MSC3510](https://github.com/matrix-org/matrix-spec-proposals/pull/3510) “let the same PL kick/ban/deop each other”).
>[!NOTE]
> Clients which show a user's power level SHOULD indicate creatorship in a similar way to help
> manage expectations on access control to users (i.e. to remind users who created the room, and so
> who can override access controls).
#### Create event changes
To support fully multilateral decentralisation, the create event `content` MAY include a new field `additional_creators`
which is a list of user IDs. All the user IDs specified have the same permissions as the original creator.
The [auth rules](https://spec.matrix.org/v1.14/rooms/v11/#authorization-rules) are updated to include additional validation on the create event:
> - If type is m.room.create:
> * 3: [...]
> * 4: ~~Otherwise, allow.~~
> * 4: **NEW: If the `additional_creators` field is present and is not an array of strings where each string
> passes the same [user ID validation](https://spec.matrix.org/v1.14/appendices/#user-identifiers) that
> is applied to the `sender`, reject.**
> * 5: Otherwise, allow.
User IDs in `additional_creators` are NOT bound to the creator server: any valid user ID may be provided.
Earlier versions of this proposal explicitly stated that `additional_creators` must be a [valid user ID](https://spec.matrix.org/v1.14/appendices/#user-identifiers)
but due to ambiguity between allowed/historical/invalid user IDs that exist on the public network, this proposal
merely states that the same validation applied on the `sender` key should be applied on the `additional_creators` field.
If this proposal is too strict, it would prevent historical user IDs from joining rooms with this MSC.
The intention of this wording is to allow the validation to be changed as and when the validation of the `sender` key changes.
See [MSC2828](https://github.com/matrix-org/matrix-spec-proposals/pull/2828) and [this clarification](https://github.com/matrix-org/matrix-spec/pull/1506)
for more information.
This new field is especially useful when creating DMs, as both parties retain equal control of the room.
#### `/createRoom` changes
In order to ensure Direct Message rooms have both the creator and recipient as joint creators,
[`/createRoom`](https://spec.matrix.org/v1.15/client-server-api/#post_matrixclientv3createroom)
requests with BOTH `preset: trusted_private_chat` and users in the `invite` field have additional meaning
server-side. The server SHOULD copy any users in the `invite` field into the `creation_content.additional_creators` field
in the **request body** and de-duplicate them. The net result is that the union of `invite` and `creation_content.additional_creators`
in the request body form the `additional_creators` in the `m.room.create` event.
#### Power levels event changes
This change affects the `m.room.power_levels` event which will no longer have the creator user ID with
`100` by default. Instead, the `users` map will be empty, and clients/servers must infer that the creator
has infinite power level based on the `m.room.create` event's `sender` (and `content.additional_creators` if present).
The auth rules for `m.room.power_levels` events are adjusted to say:
> 9. If type is `m.room.power_levels`:
> - 1). If any of the properties `users_default`, `events_default`, `state_default`, `ban`, `redact`, `kick`, or `invite` in content are present and not an integer, reject.
> - 2). If either of the properties `events` or `notifications` in `content` are present and not an object with values that are integers, reject.
> - 3). If the `users` property in `content` is not an object with keys that are valid user IDs with values that are integers, reject.
> - 4). **NEW: If the `users` property in `content` contains the `sender` of the `m.room.create` event or any of the user IDs in the create event's `additional_creators` array within `content`, reject.**
> - 5). ...rest of rules...
This ensures that there can be no confusion among clients or servers if the creator were to have a PL entry
in the `users` map.
>[!NOTE]
> We could add a compatibility shim which would inject the creators into the PL event for clients.
> Naively, this would set the creators to be `max(users)+1`. This naive solution is wrong though, as
> some PL events may have "the level required to send event X" to be higher than any other user, so the shim
> would also need to be `max(PL_to_send_anything)+1` in addition to `max(users)+1`.
>
> However, this would introduce new problems for client implementations:
> * This shim would break any client which asserts [MAX_INT](https://spec.matrix.org/v1.14/appendices/#canonical-json)
> in power levels, as the creator PL would have to be 1 greater than the actual max a real user could have.
> * Creators would appear to break PL transition rules, as they would be seen to give themselves more power
> (e.g if the max PL of non-creators was 100, then they increased a non-creator to 150, the same event would also
> transition all creators to PL151). This would also be confusing to render, as there would appear to be
> two changes (creator->PL151 and target user->PL150), when it practice only one change was made.
> * This logic makes it harder to transition to pure P2P systems in the future, where
> [clients sign federation events](https://github.com/matrix-org/matrix-spec-proposals/pull/4080), as clients
> would have to assert that the PL transitions are valid before committing a signature to authorise it.
> * The lack of any new role descriptor (e.g "Creator") means in practice major clients would simply list
> the creators as "Admin" (any PL>=100). This could cause confusion among users if a creator were to
> demote an admin, as this should not be possible.
This change does not add significantly more complexity to the calculation of PLs for users
in a room because both clients and servers have always needed BOTH the `m.room.power_levels` and `m.room.create`
events in order to display PLs correctly (as in previous room versions the absence of a PL event means the creator
has PL100). For this reason and the ones listed above, no compatibility shim is proposed with this proposal.
#### Tombstone changes
The _initial power levels event in the room_ MUST have the level required to send `m.room.tombstone` events
be higher than the level required to send state events. This is to ensure only creators are able to upgrade
the room _by default_, but allowing them to transfer ownership by increasing the PL of any user to PL150 (for example)
to allow them to send the tombstone event. Note: this may still be overridden by `power_level_content_override`.
The rationale for this is as follows: Matrix does not allow users with the same PL to demote each other.
Upgrading a room breaks this because the non-creator doing the upgrade will now gain unlimited PL, potentially
demoting the original creator ("potentially" because they could be set via `additional_creators` during the upgrade process).
As such, more protections need to be in place to guard against unauthorised privilege escalation by admins,
hence the introduced of a new PL150 tier for tombstoning the room. If we kept the ability to tombstone to be PL100,
then by default it would be impossible to allow someone to A) change the server ACLs, B) update history visibility,
without also C) giving them the ability to privilege escalate.
#### Room upgrades
A new `additional_creators` key is added to the [`/upgrade`](https://spec.matrix.org/v1.14/client-server-api/#post_matrixclientv3roomsroomidupgrade) endpoint. This has the same validation rules applied as the
`additional_creators` field in the `m.room.create` event, and serves as a way to transfer ownership of a room (remove a creator).
This key behaves in the same way as if it were specified in the `creation_content` in `/createRoom`:
the _entire set_ of additional creators are specified up-front. For example, consider the following scenario:
- Alice created a room and put Bob as an additional creator.
- Charlie has PL150 and wants to upgrade the room so Alice is no longer a creator. He wants to keep Bob as an additional creator.
- Charlie can `/upgrade` the room and specify Bob as an additional creator.
- The new room does not have Alice as a creator or additional creator.
This allows the creator status to move between users.
**Note** (added July 28, 2025 post-acceptance for clarity): If `additional_creators` is specified on
`/upgrade` but the new room version doesn't support `additional_creators`, the field is not used and
does nothing. For example, if a room was being upgraded to `11` with `additional_creators: [@alice:example.org]`,
the request would (probably) 200 OK but the new room's `m.room.create` event would *not* have an
`additional_creators` field. If the room was instead being upgraded to `12` (which contains this MSC),
then `additional_creators` would show up in the create event's `content`.
### Potential Issues
Any update to the set of creators in a room requires a room upgrade. This means room upgrades will occur
more often than today. Forming a complete timeline history across several rooms may make a number of things
harder for implementations. For instance, it increases the pressure to implement seamless merging of timelines
across a tombstone rather than the currently widespread "click to jump to the old room" UX.
Clients which don't already implement the [default power level for creators](https://spec.matrix.org/v1.15/client-server-api/#mroompower_levels)
may experience bugs where users who just created a room cannot (visually) change details of that room,
such as adding admins or setting the room's topic. A server-side backwards-compatibility shim to append
the room creators to the power levels event over the Client-Server API as `2**53-1` (JavaScript's `Number.MAX_SAFE_INTEGER`)
was considered, however with the expectation that most communities will upgrade their rooms when they're
ready rather than immediately upon availability of this MSC, clients in particular will have opportunity
to be updated accordingly.
Similarly, clients which attempt to set an explicit PL for the creator(s) will fail. A backwards-compatibility
shim was considered to ignore PLs set for creator(s) but rejected, on the basis of causing avoidable
confusion and technical debt, given clients are already making breaking changes for this room version.
### Alternatives
1. We could implement DAG finality, stopping servers forking the DAG at points known by all servers to
be in the past. However, there is an open question on how to handle faulty servers which break the
finality rule by referencing old events (e.g. after a database rollback) - and the current best
solution is to have an admin upgrade the room to solve the resulting splitbrain. Given this requires
(complicated and confusing) manual intervention, it feels that the simpler solution presented here
is preferable.
2. We could have implemented creator permissions as a high valued power level (as per MSC3915s “owner”
PL), but this does not actually provide more security. The reason why "Creators" aren't just a new
tier above "Admins" is because of two reasons:
1. The set of creators is immutable.
2. The creators are defined in the earliest event in the room.
These two properties ensure that it's not possible to backdate events and provides additional
security against self-demotions (creators cannot self-demote as the set of creators is immutable)
above and beyond alternatives such as adding a new PL150 tier above "Admins" PL100.
### Security Considerations
This MSC makes a distinction between creators and admins which did not formally exist before. If a room
is upgraded to this room version, the admin doing the upgrade will gain privileges they did not have
before. This allows admins to escalate their privileges to creator level. Early versions of this proposal
suggested that only the room creator would be able to upgrade to this new room version. However, many
existing rooms on the public federation have absent creators, making it impossible for those rooms to
upgrade to more secure room versions. As such, this proposal does not impose additional restrictions
on the upgrade process, and accepts the risk that admins may gain power over other admins if they were
first to upgrade the room.
Specifying `additional_creators` removes the ability to demote those additional creators, effectively
creating the same problem we have today where admins cannot be demoted. Care must be taken that clients
emphasise this to end-users that this cannot be changed.
In some cases, a room may outlast the creator's interest or participation in the room. Prior to this
happening it is considered best practice for at least one other user to be given enough power level
to send tombstone events (and therefore perform upgrades in the future), or to make use of
`additional_creators` per above. Communities may prefer to exclusively create rooms using a dedicated
account or give that account creator power via `additional_creators` too.
It is critical that all servers agree on the same create event and thus the creator(s) of the room in
order to apply auth checks correctly. Therefore, this MSC depends on [MSC4291: Room IDs as hashes of the create event](https://github.com/matrix-org/matrix-spec-proposals/pull/4291).
The room creator has always been able to leave an invite-only room and then rejoin it without an invite.
Clients may want to display left creators in a unique way such as keeping them in the membership list
but greying out their name, or displaying `(Creator: left)`.
### Credits
Thanks to Timo Kösters for initiating discussion around this MSC.
### Unstable prefix
During development this room version is referred to as `org.matrix.hydra.11` alongside MSC4291 and MSC4297.
### Dependencies
This MSC depends on ["MSC4291: Room IDs as hashes of the create event"](https://github.com/matrix-org/matrix-spec-proposals/pull/4291).

@ -0,0 +1,179 @@
## MSC4291: Room IDs as hashes of the create event
Currently rooms are identified by a room ID [made from a random string](https://spec.matrix.org/v1.14/appendices/#room-ids)
selected by the creating server, namespaced to the origin server. This allows a malicious server to
create a room whose ID collides with an existing ID, causing security issues if the rooms are confused
together. Furthermore, despite the specification stating that room IDs are opaque identifiers, both clients
and servers in the wild introspect the room ID for routing or moderation purposes. This is fundamentally
_unsafe_ as there are no guarantees the room ID is accurate without some verified events in the room.
By removing the domain from the room ID we ensure real world clients and servers cannot be manipulated
by an attacker who may claim domains they do not control.
This supplants [MSC4051](https://github.com/matrix-org/matrix-spec-proposals/pull/4051) with more information.
### Proposal
We redescribe the room ID to be the event ID of the room's `m.room.create`
event with the room ID sigil `!` instead of the event ID sigil `$`. For example, if a create event ID is
`$31hneApxJ_1o-63DmFrpeqnkFfWppnzWso1JvH3ogLM`, the room ID is
`!31hneApxJ_1o-63DmFrpeqnkFfWppnzWso1JvH3ogLM`.
*This effectively restricts the room ID grammar to be `!` + 43x unpadded urlsafe base64 characters.*
This binds a given room to a specific single `m.room.create` event, eliminating the risk of confusion.
This can be seen as an extension of [MSC1659](https://github.com/matrix-org/matrix-spec-proposals/blob/main/proposals/1659-event-id-as-hashes.md),
which replaced confusable `event_id`s with a hash of the event.
The `room_id` field is removed entirely from the `m.room.create` event, but is reintroduced on
non-federation APIs, exactly like how the `event_id` is missing over federation but reintroduced on the
other APIs. As the `room_id` is the create event ID, and all `auth_events` cite an `m.room.create`
event, the `auth_events` no longer specify the create event ID. This will slightly reduce
all event payload sizes.
The following changes on a new room version are made:
- Concerning the create event:
Step 1 of the [Checks performed on receipt of a PDU](https://spec.matrix.org/v1.14/server-server-api/#checks-performed-on-receipt-of-a-pdu)
is modified to remove the `room_id` as a universal example of:
> Is a valid event, otherwise it is dropped. For an event to be valid, it must ~~contain a room_id, and it must~~ comply with the event format of that room version.
- Concerning the [event format](https://spec.matrix.org/v1.14/rooms/v11/#event-format-1):
* The "Description" field for `auth_events` is adjusted to state:
> Required: Event IDs for the authorization events that would allow this event to be in the room.
>
> Must contain less than or equal to 10 events. Note that if the relevant auth event selection rules are used,
> this restriction should never be encountered.
> **NEW: MUST NOT contain the create event ID. This is already implied by the `room_id` field.**
* The "Description" field for `room_id` is adjusted to state:
> Required: Room identifier. Omitted on `m.room.create` events.
- Concerning [auth rules](https://spec.matrix.org/v1.14/rooms/v11/#authorization-rules):
* Change auth rule 1.2 (“If the domain of the `room_id` does not match the domain of the sender, reject.”)
to be (“If the create event has a `room_id`, reject”) given we no longer have a `room_id` on create events.
* Remove auth rule 2.4 (“If there is no `m.room.create` event among the entries, reject.”) given the create event is now implied by the `room_id`.
* Add auth rule 2.5: "If there are entries whose `room_id` does not match the `room_id` of the event itself, reject."
This overlaps with [MSC4307](https://github.com/matrix-org/matrix-spec-proposals/pull/4307).
* Add auth rule 2 (inserted before the current rule 2): "If the event's `room_id` is not an event ID
for an accepted (not rejected) `m.room.create` event, with the sigil `$` replaced with sigil `!`, reject."
This creates a chicken/egg problem when upgrading rooms because:
- The `m.room.tombstone` event needs a `content.replacement_room`.
- The `content.replacement_room` ID is now the create event of the new room.
- The create event of the new room needs the tombstone event ID in `content.predecessor.event_id`.
- While the spec [does not require](https://spec.matrix.org/v1.15/client-server-api/#server-behaviour-19)
the predecessor event to be the tombstone, there may be more than one "last event" if the DAG
has forward extremities. Prior to sending the tombstone event, servers could heal the DAG using
a dummy event, though this is far from elegant when the tombstone event performs this function.
- The `m.room.tombstone` event needs ...
<img width="793" alt="Creator chicken egg problem" src="images/4291-creator-chicken-egg.png" />
To break this cycle, this MSC deprecates the `content.predecessor.event_id` field from the `m.room.create` event. Clients
MUST NOT expect the field to be set, but SHOULD continue to use it if set. There appear to be no security
reasons why this field exists. This field is sometimes used in clients to jump back to the correct part in the old room's timeline when the tombstone
occurred, which can be relevant when there are lots of leave events after the tombstone. Clients that wish to preserve this behaviour may instead
search the old room state for the `m.room.tombstone` event and then jump to that.
### Potential Issues
It is not immediately obvious which server created the room in the first place. See the "Alternatives" section
for a discussion on the pros/cons of this.
The loss of `content.predecessor.event_id` may negatively impact the way clients stitch together timelines in upgraded rooms.
In particular, some clients may crash if the field is missing (possibly Element iOS?).
This proposal relies on the server being able to verify the create event in the room. This generally
means the server must be joined to the room. In particular, invites/knocks are not protected against
room confusion by this proposal alone. The security guarantees of this proposal are enhanced with
[MSC4311: Ensuring the create event is available on invites and knocks](https://github.com/matrix-org/matrix-spec-proposals/pull/4311).
Clients which were previously parsing the room ID to identify a server for `via` or similar puporposes
are not able to do so. For `m.space.child` and similar cases, the user's own server may be used to
populate `via` on the event, at least initially. For permalinks, `via` candidates are now more important
when creating links (or the use of aliases). Clients can get their own server name by parsing the
user ID they are operating under.
### Alternatives
#### Keeping the domain suffix
We could keep the colon+server suffix as it contains useful information about the creator's server,
and has historically been used as routing information / auth checks in several places:
- event auth for `m.federate` [in Synapse](https://github.com/element-hq/synapse/blob/9d43bec/synapse/event_auth.py#L312), though the specification [states]((https://spec.matrix.org/v1.15/rooms/v11/#authorization-rules)) this should be applied to the `sender` instead - Step 3.
- Its used as a last resort `?via=` candidate [in Synapse](https://github.com/element-hq/synapse/blob/v1.133.0/synapse/handlers/room_member.py#L1177).
- It's used as a last resort `?via=` candidate in [Rory&::LibMatrix](https://cgit.rory.gay/matrix/LibMatrix.git/tree/LibMatrix/RoomTypes/GenericRoom.cs?h=0a82b7e2acc18def93818d8e405bf620c328975e#n223), NeoChat and others.
It is also desirable to know the creator's server name without having to join and get the full create event
for Trust & Safety purposes. The create event in invites can be spoofed, as can the room ID, but spoofing the
room ID makes the invite unusable whereas spoofing the create event does not. We could rely on the `sender`
instead, but for this to be effective it would be important for servers to use the `sender` domain for routing
purposes, such that if the `sender` was invalid it would cause the invite to be unusable. On the contrary, users
unfamiliar with Matrix may see a room ID like `!OGEhHVWSdvArJzumhm:matrix.org` and think that `matrix.org` hosts/moderates/
is somehow responsible for the room in some way. By dropping the domain, we clearly express that the creator domain
may not be responsible for the contents of the room.
However, by adding the colon+server suffix we would allow malicious servers to create room IDs with _earlier room versions_
which have the same ID as the new proposed format. For example, a malicious server who knows of an existing
vNext room `!31hneApxJ_1o-63DmFrpeqnkFfWppnzWso1JvH3ogLM:example.com` could create a v11 room with the exact
same ID, causing confusion. We therefore need to create a new namespace for vNext room IDs which cannot conflict
with earlier room versions. This is why the colon+server suffix has been removed. We could alternatively encode the
room version along with the domain to form a new namespace e.g `!localpart:domain@version` where `@` has never been
allowed in the set of `domain` characters, but there isn't a strong enough reason to encode such information in
every event. By doing this, we would allow implementation confusion by specifying the wrong creator domain and/or
wrong room version in the ID, which is important when the room ID is read in isolation without the matching create
event (e.g invite handling, moderation tooling).
#### Removing `room_id` entirely from all events
We could remove `room_id` field from all events, and propagate it via `auth_events` instead. This
would make it harder for servers to immediately know which room an event is in as there would be
multiple potentially unknown event IDs as candidates. Its less awkward to simply keep it in the
`room_id` field and instead remove the create event from `auth_events`.
We could rename `room_id` to `create_event_id` and require servers to universally populate `room_id` for every event
(and drop `create_event_id`) for all events delivered to clients. This better encodes the fact that the
room ID _is_ the create event ID, but it's not clear this provides any advantages beyond that, whilst incurring
fixed costs to rename fields to clients, as well as update existing codebases to look in a different key,
and update the specification to conditionally say "room ID" or "create event ID" depending on the room version.
It's likely not worth the effort, despite it being a clearer key name.
#### Using an ephemeral public key as identifier instead of the create event ID
We could generate an ephemeral keypair, sign the create event with the private key and use the public
key as the room ID. [MSC1228](https://github.com/matrix-org/matrix-spec-proposals/pull/1228) proposed this.
The problem with this approach is that we cannot guarantee that servers will actually treat the keypair
as ephemeral: they could reuse the same keypair to create a spoofed room.
#### Blocking servers which eclipse their own rooms
We could make honest servers block other servers when they detect that the other server has reused a
room ID. However, this is a reactive approach compared to the proactive approach this proposal takes.
By relying on servers to "detect" when a room ID is reused, malicious servers can selectively disclose
the duplicate room to target servers. This would allow the malicious server to force servers with
admins in the room to no longer participate in the room, effectively removing the ability to moderate
the room.
### Security Considerations
This fixes a class of issues caused by confusable room IDs. Servers can currently perform a form of
eclipse attack when other servers join via them by presenting a completely different room to some
servers. This isolates the target server, controlling information that the target server sees. By
linking together the room ID (which is user-supplied e.g via `matrix:` URIs) we can guarantee that
all servers agree on the same create event, and thus the subsequent hash DAG that forms.
Servers may accidentally create the same room if a client creates >1 room in a single millisecond.
This happens because the entropy in the create event is quite small, primarily relying on the
`origin_server_ts`. Server authors concerned about this MAY add in sufficient entropy as a custom
key in the `content` of the create event. As of v11, the redaction algorithm preserves the entire
`content` so such extra keys become part of the event ID and thus the room ID. Servers may also
prefer to apply strong rate limits to prevent this scenario.
The removal of enforced server domain namespaces means event IDs truly are _global_. This means we
rely on the security of the hash function to avoid collisions (which we've always relied on _within_ a
room). This has always been implied due to the federation endpoint `/event/{eventID}`, but this change
makes the data model rely on global uniqueness. See [MSC2848](https://github.com/matrix-org/matrix-spec-proposals/pull/2848)
for more discussion.
### Unstable prefix
During development this room version is referred to as `org.matrix.hydra.11` alongside MSC4289 and MSC4297 (embargoed until Aug 14, 2025).
### Dependencies
This MSC has no dependencies.

@ -0,0 +1,268 @@
# MSC4297: State Resolution v2.1
This MSC proposes two modifications to the existing state resolution algorithm which will improve
security by reducing the frequency of "state resets". This proposal bases its changes on
room version 11.
## Background
Matrix is decentralised. This means there is no central entity which orders events. Ordering
is critical to enforce access control. For example, in order for Bob to change the room name
he needs to be a moderator/admin _first_. To model this, rooms are represented as a
directed acyclic graph (DAG) of events. State events are operations like "Bob changing the room name" or
"Bob gaining admin privileges". These events "point" to the most recent events that the server that created the event has
seen in that room. In order for Bob to change the room name, his room name event MUST point either
directly or indirectly to the event which gave him the right to change the room name. As Matrix is
decentralised, Alice could independently demote Bob without him being aware of it at the same time
he tries to change the room name. This is concurrent behaviour, and how this is managed is up to the
state resolution algorithm. The algorithm:
- selects which events are in conflict,
- determines how to order these events,
- filters out unauthorised events based on this ordering
For example, Alice's demotion may be applied first so Bob cannot change the room name.
<img width="1115" src="/proposals/images/4297-msc-1.png" />
However, the algorithm can cause surprising behaviour. If Alice cannot communicate Bob's demotion to Bob's
server quickly, then Bob may perform many more privileged operations over minutes or hours. Eventually,
Alice's demotion will arrive on Bob's server, which would cause all the operations Bob did to be
"rolled back" or reverted. This can be unexpected to users on Bob's server, but is an _expected_
consequence of Matrix being decentralised. A "state reset" is very similar to this in that it causes
unexpected behaviour. However, the defining characteristic of a state reset is that this happens
_even when there is no revocation event_ such as a demotion.
Concurrent events can occur at any point in the room DAG. This means when the DAG is put into a
total order from "oldest" to "newest", previously unseen events may appear at the "older" end of the
ordering. These unseen events could affect whether later events are authorised or not, so we need to
"replay" events from the unseen events to the latest events. To avoid replaying too many events,
the algorithm intelligently calculates the difference between the sets of concurrent events to only replay what is necessary. It is desirable to prevent
servers from adding concurrent events from an obviously long time ago, but since servers never
coordinate (e.g via a consensus algorithm) they can never be sure that they have seen all concurrent
events. The idea of making it impossible to add concurrent events to some sections of the graph is
referred to as "causal stability" or "finality".
Matrix allows servers to partially synchronise the DAG. This allows servers that have been offline for
a long time to quickly resynchronise without being forced to pull in the entire room history. To ensure
authorisation events are applied correctly, events have another DAG formed of `auth_events`, called
the "auth chain". These chains only consist of authorisation events and _are_ fully synchronised.
The `auth_events` cite all the historical events which authorise the event in question. Authorisation
events are the following state events: `m.room.create`, `m.room.member`, `m.room.power_levels` and
`m.room.join_rules`. A subset of authorisation events are [power events](https://spec.matrix.org/v1.14/rooms/v11/#definitions).
>[!NOTE]
> As a reminder, State Resolution v2.0 works by merging together sets of state across branches of
> the room DAG. State events common to both branches are called 'unconflicted'; state events which
> only exist on one branch or another or have different values are called 'conflicted'. The
> resolved state is calculated:
> * Start with the unconflicted state as our "base layer"
> * Consider the conflicted power events (PLs, kicks, bans, join_rules) and any conflicted authorisation
> events that are required to authorise said power events, use reverse topological ordering to
> provide a consistent ordering and then layer those by replaying them on top, incrementally
> authorising as you go.
> * Work out the sequence of the conflicted normal state events using mainline ordering (the
> 'backbone' of power level events through the conflicted set) and then similarly replay those
> on top too.
> * Reapply any unconflicted state keys which may have been overwritten in the previous steps.
## Problems with the existing algorithm
The algorithm relies on two pieces of ordering information, from `prev_events` and `auth_events`.
The `prev_events` ordering controls the input state sets to the algorithm. These state sets aren't
guaranteed to map correctly onto the auth chain ordering induced by `auth_events` due to partial
synchronisation. If these orderings disagree, the algorithm can select older state.
This can happen due to federation outages or due to faulty implementations. The scenarios below
require this to have happened, and are represented by "incorrect" state. This typically manifests
as _older state_ existing in a state set. State resets happen because the algorithm fails to determine
all the events that need to be replayed when _older state_ exists in a state set.
Problem A focuses on the "initial state" of the room, before the conflicted events are replayed.
This is currently set to the "unconflicted" state of the room. The core idea is that if both forks
agree on the exact event IDs for 99 members, but disagree on the exact event ID for the 100th member,
we do not need to replay all 99 member events. The problem is that there is more than one way to
"agree on the exact event IDs", which can cause state to reset under certain circumstances.
Problem B focuses on selecting _which events_ are in conflict. The core idea is that we do
not want to replay the entire history of the room every time there is a conflict, but only the
differences between each fork (the _auth difference_). These differences don't include enough events
under certain circumstances, causing state to reset.
>[!NOTE]
> The following scenarios present rooms in two ways: via the familiar `prev_events` ordering which
> represents concurrent behaviour and the more unfamiliar `auth_events` ordering which represents
> "is authorised by" relationships. The `auth_events` graph contains many redundant edges (e.g every event
> references the create event), so we will only present the _transitive reduction_ of this graph, which
> removes these edges. This helps illustrate the problems better.
>
> <img width="201" src="/proposals/images/4297-msc-2.png" />
>
> The scenarios also use coloured diamond symbols to indicate the state of the room at a particular
> edge on the `prev_events` graph. Servers may incorrectly calculate this e.g due to partial synchronisation,
> which is indicated by a dashed arrow pointing from the correct state to the incorrect state. The colour
> of the diamond only serves to distinguish between other state sets, it has no other meaning, despite similar
> colours being used to indicate the sender of an event.
>
> <img width="632" src="/proposals/images/4297-msc-3.png" />
### Problem A: Conflicting events can be unauthorised by the unconflicted state
Events can be conflicted in _two_ ways: via room state's `prev_events` and via the auth chain's `auth_events`.
The room state determines what the inputs to the state resolution algorithm are and hence what is in
the unconflicted state. The auth chains determine which extra events are pulled in and the ordering
between events. Room state can unexpectedly reset if these two orderings disagree, as outlined in
the following example[^1]:
<img width="426" src="/proposals/images/4297-msc-problem-a-1.png" />
<img width="618" src="/proposals/images/4297-msc-problem-a-2.png" />
In this scenario, the state of the room at the blue diamond is obtained via partial synchronisation,
e.g `/state{_ids}`. This response contains an outdated join rules event, meaning both join rules events
are now in conflict, even though all events on both forks agree
on what the latest join rule event is via their auth chains. This causes the join rules to be
replayed. However, both forks also agreed that Alice had left the room. As such, the unconflicted
state starts with Alice not being a member in the room. When the join rules events get replayed,
both fail since Alice (who set them) is not in the room. This causes the room to have no join
rules event.
<img width="573" src="/proposals/images/4297-msc-problem-a-3.png" />
### Problem B: Conflicting events need extra unconflicted events in order to be authorised
Similarly to Problem A, this occurs when the ordering between `prev_events` and `auth_events` differs.
In this scenario, one fork can reference newer events via the auth chain whilst claiming the room
state is an older event. When this happens, the auth difference does not include all relevant events
between the old and new events as both sides have seen the events in-between via their auth chains. Most
of the time this will not cause a state reset, but when there are chains of events which are dependent
on one another, this can cause a state reset.
<img width="432" src="/proposals/images/4297-msc-problem-b-1.png" />
<img width="554" src="/proposals/images/4297-msc-problem-b-2.png" />
Note that the state of the room at the red diamond is obtained via partial synchronisation, e.g
`/state{_ids}`. This response contains an outdated power levels event, meaning the power levels events
are now in conflict.
In this example[^1], Alice is an Admin who promotes Bob. Bob then promotes Charlie. It is critical that
Bob's promotion is applied before Charlie's promotion, or else it will be unauthorised. However, the
auth difference calculation fails to include this event, leading to a state reset.
<img width="446" src="/proposals/images/4297-msc-problem-b-3.png" />
## Proposal
Two modifications are made to the algorithm which are described below. Both changes relate to
which events are selected for replaying. They do not modify how conflicted events are sorted
nor do they modify the iterative auth checks.
### Modification 1: Begin the first phase of iterative auth checks with an empty state map
This aims to fix problem A by disregarding the `prev_events` ordering entirely for determining the
initial state. It does this by starting with an empty state map. This causes the iterative auth
checks algorithm to load the auth chains, per the [iterative auth checks definition](https://spec.matrix.org/v1.14/rooms/v11/#definitions):
> If a (event_type, state_key) key that is required for checking the authorization rules is not
present in the state, then the appropriate state event from the events `auth_events` is used if the
auth event is not rejected.
This ensures that the algorithm replays events on top of the `auth_events` histories, rather than some unrelated
history.
Step 2 of the state resolution algorithm is amended to state:
> Apply the _iterative auth checks algorithm_, starting from ~~the unconflicted state map~~
__an empty state map__, to the list of events from the previous step to get a partially resolved state.
<img width="593" src="/proposals/images/4297-msc-sol-1.png" />
Note that even though we no longer insert the unconflicted state into the partially resolved state,
Step 5 of the algorithm ensures that the unconflicted state is still in the final merged
output, even though it may not have been during the resolution process:
> Update the result by replacing any event with the event with the same key from the unconflicted
> state map, if such an event exists, to get the final resolved state.
### Modification 2: Add events _between_ the conflicted state set to the full conflicted set
This aims to fix problem B by including relevant intermediate events when performing state resolution.
This modifies the definition of the "full conflicted set" to include _all events_ which are a _descendant_
of one conflicted event and an _ancestor_ of another conflicted event. This forms a "conflicted subgraph"
which is then replayed by the algorithm.
This means the full conflicted set contains:
- the conflicted state events themselves AND
- the auth difference AND
- the events between the conflicted state events
The purpose of the auth difference is to replay the relevant auth history from each input state set.
Most of the time it does this, but when the input state sets are derived from a partial sync response
there's no guarantee that this will include the relevant history because the response may include
erroneous older events. By including the conflicted state subgraph we ensure that input state sets
with _old events_ have the auth history from those old events replayed.
<img width="549" src="/proposals/images/4297-msc-sol-2.png" />
A new term is added in the state resolution algorithm:
> **Conflicted state subgraph.** Starting from an event in the _conflicted
> state set_ and following `auth_events` edges may lead to another event in the
> conflicted state set. The union of all such paths between any pair of events
> in the conflicted state set (including endpoints) forms a subgraph of the
> original `auth_event` graph, called the _conflicted state subgraph_.
And the following modification is made to the definition of "Full conflicted set":
> **Full conflicted set.** The full conflicted set is the union of the conflicted state set,
> <ins>the conflicted state subgraph</ins> and the auth difference.
## Potential issues
### Performance
These modifications may impact performance in two ways:
- more work is done on every state resolution to calculate the conflicted state subgraph.
- potentially more events are replayed during resolution.
The data required to calculate the auth difference is also the same information required to
calculate the conflicted state subgraph, so no extra database requests are needed with these
changes. However, more CPU work needs to be performed to walk the auth chain to look for
conflicted events on every resolution.
In the common case, the conflicted state subgraph overlaps entirely with the auth difference,
meaning no extra events need to be replayed. This has been confirmed via
[partition/fault tolerance testing](https://github.com/element-hq/chaos) which tests extreme
cases with large numbers of membership changes and federation outages, producing resolutions such as:
```
additional events replayed=0 num_conflicts=17 conflicted_subgraph=271 auth_difference=263
```
## Further work
More changes are required in order to fix all cases of state resets. The changes proposed here
are based on real world scenarios where state resolution has produced undesirable results.
The underlying causes of these state resets is mismatched orderings. If the protocol had a single
ordering then this would remove this entire class of issues. This will be explored in a future MSC.
## Security considerations
The state resolution algorithm is a critical component in the overall security of a room. This proposal
is modifying the algorithm so there are inevitable risks associated with it. These risks are mitigated
because the proposal is _not_ changing how events are ordered nor how events are authorised. It is
purely _adding_ events to be replayed and relying on the auth chains as the authoritative source
to rebase changes onto.
## Unstable prefix
This algorithm is in use for room version `org.matrix.hydra.11`.
## Dependencies
This MSC has no dependencies.
[^1]: When used in conjunction with [MSC4289](https://github.com/matrix-org/matrix-spec-proposals/pull/4289)
Alice should not be present in the `m.room.power_levels` event. The examples function in the same way.

@ -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.

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 149 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 254 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 172 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 165 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 228 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 237 KiB

Loading…
Cancel
Save