Skip to content

MSC4140: Cancellable delayed events#4140

Open
toger5 wants to merge 221 commits into
mainfrom
toger5/expiring-events-keep-alive
Open

MSC4140: Cancellable delayed events#4140
toger5 wants to merge 221 commits into
mainfrom
toger5/expiring-events-keep-alive

Conversation

@toger5

@toger5 toger5 commented May 7, 2024

Copy link
Copy Markdown

Rendered

This could also supersede MSC2228 (by making it possible to send a redaction with the /send endpoint. This is the case as mentioned here)

Implementations

Known differences between current implementations and the proposal

  • The implementations use the error code M_MAX_DELAY_EXCEEDED, HTTP 400, and a response property max_delay when the server refuses to schedule an event because the requested delay is too large. The proposal has since switched to the error code M_FORBIDDEN, HTTP 403, and publishes the maximum allowed delay in the m.delayed_events capability (so that clients can discover it ahead of making the request).
  • The implementations use the existing endpoints /send and /state with a new query parameter delay for scheduling delayed events. The proposal has since switched to a dedicated endpoint PUT /_matrix/client/v3/rooms/{roomId}/delayed_event/{eventType}/{txnId} where the delay is included in the request body.
  • The implementations use delay and max_delay rather than delay_ms and max_delay_ms.
  • The implementations use running_since rather than scheduled_at.

Implementations in Element Call via the Widget API

These are only informational and shouldn't be relevant for the proposal process. The MSC doesn't depend on widgets and widgets are themselves not part of the spec.


SCT stuff:

MSC checklist

FCP tickyboxes

Designated reviewers:

  • Security team (requested out of band)
  • @anoadragon453 with Backend experience

toger5 added 2 commits May 7, 2024 18:52
Signed-off-by: Timo K <toger5@hotmail.de>
Signed-off-by: Timo K <toger5@hotmail.de>
@toger5 toger5 force-pushed the toger5/expiring-events-keep-alive branch from 2bc07c4 to 0eb1abc Compare May 7, 2024 17:03
Signed-off-by: Timo K <toger5@hotmail.de>
@toger5 toger5 force-pushed the toger5/expiring-events-keep-alive branch from 0eb1abc to 8bf6db7 Compare May 8, 2024 15:49
Signed-off-by: Timo K <toger5@hotmail.de>
Comment thread proposals/4140-expiring-events-with-keep-alive-endpoint.md Outdated
Comment thread proposals/4140-expiring-events-with-keep-alive-endpoint.md Outdated
Comment thread proposals/4140-expiring-events-with-keep-alive-endpoint.md Outdated
Comment thread proposals/4140-expiring-events-with-keep-alive-endpoint.md Outdated
Comment thread proposals/4140-expiring-events-with-keep-alive-endpoint.md Outdated
Comment thread proposals/4140-expiring-events-with-keep-alive-endpoint.md Outdated
Comment thread proposals/4140-expiring-events-with-keep-alive-endpoint.md Outdated
Comment thread proposals/4140-expiring-events-with-keep-alive-endpoint.md Outdated
Comment thread proposals/4140-expiring-events-with-keep-alive-endpoint.md Outdated
Signed-off-by: Timo K <toger5@hotmail.de>
@turt2live turt2live changed the title Draft for expiring event PR MSC4140: Expiring events with keep alive endpoint May 9, 2024
@turt2live turt2live added proposal A matrix spec change proposal. Process state. A-Client Server Client-Server API kind:feature MSC for not-core and not-maintenance stuff needs-implementation This MSC does not have a qualifying implementation for the SCT to review. The MSC cannot enter FCP. labels May 9, 2024
@toger5 toger5 force-pushed the toger5/expiring-events-keep-alive branch from 3e54c2a to c82adf7 Compare May 10, 2024 17:54
Signed-off-by: Timo K <toger5@hotmail.de>
@toger5 toger5 force-pushed the toger5/expiring-events-keep-alive branch from c82adf7 to 54fff99 Compare May 10, 2024 18:08
toger5 added 3 commits May 13, 2024 16:56
…is used to trigger on of the actions

Signed-off-by: Timo K <toger5@hotmail.de>
Signed-off-by: Timo K <toger5@hotmail.de>
Add event type to the body
Add event id template variable
Comment thread proposals/4140-delayed-events-futures.md Outdated
Comment thread proposals/4140-delayed-events-futures.md Outdated
Comment thread proposals/4140-delayed-events-futures.md
Comment thread proposals/4140-delayed-events-futures.md Outdated
Comment thread proposals/4140-delayed-events-futures.md Outdated
Comment thread proposals/4140-delayed-events-futures.md Outdated
Comment thread proposals/4140-delayed-events-futures.md Outdated
Comment thread proposals/4140-delayed-events-futures.md Outdated
Comment thread proposals/4140-delayed-events-futures.md Outdated
Comment thread proposals/4140-delayed-events-futures.md Outdated
Comment thread proposals/4140-delayed-events-futures.md Outdated
Comment thread proposals/4140-delayed-events-futures.md Outdated
Comment thread proposals/4140-delayed-events-futures.md Outdated
Comment thread proposals/4140-delayed-events-futures.md Outdated
Comment thread proposals/4140-delayed-events-futures.md Outdated
toger5 and others added 2 commits May 31, 2024 09:20
Co-authored-by: Andrew Ferrazzutti <af_0_af@hotmail.com>

### Alternative to `running_since` field

Some alternatives for the `running_since` field on the `GET` response are:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At the risk of bikeshedding, how does scheduled_at sound? Or at least something suffixed with _at, which the spec uses for a few other timestamp-valued fields.

I also feel that scheduled_at is less likely than scheduled_ts to be misinterpreted as the intended send time of the event, and thus is a good opportunity to put scheduled in the name, which is an existing keyword used elsewhere in this module, instead of having to introduce a new term (like "running" or "created").

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Made the leap to prefer scheduled_at with f184579.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've documented this in the known implementation differences in the PR description (and hopefully did so correctly).

This targets:
- the "delay" field of the POST request body
- the "delay" field of the GET response body
- the "max_delay" field of the capability object
Also update the section on alternatives to that field

@turt2live turt2live left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall this looks good to go for FCP - thank you! (and sorry for the review delay)

Before I send it into that stage though, I'd like to see the query string argument alternative explored a bit more. I'm hoping this is as easy as linking to a (rejected/reverted) PR which added such functionality, but it could also be notes from a team discussion which backs up the claim that it's difficult to do. If there's prior conversation on this MSC about it, linking to those threads would also be good.

For a bit of process visibility: I'm going to ask the Security team to look at this MSC too. There are novel authentication mechanisms introduced here which need a more qualified opinion.

Comment thread proposals/4140-delayed-events-futures.md Outdated
Comment thread proposals/4140-delayed-events-futures.md Outdated
Comment on lines +123 to +125
As a special case, if the homeserver has set either of these limits such that scheduling delayed events is disallowed
(i.e. it sets the maximum allowed delay to 0 seconds, or a limit of 0 scheduled delayed events per user), it may respond
to event scheduling requests with HTTP 400 and a standard error response with an `errcode` of `M_UNKNOWN`.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be M_FORBIDDEN as the maximum delay condition is impossible to satisfy?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. I was under the impression that M_FORBIDDEN was to be used only for insufficient permissions.

On that note, I thought the same was true for HTTP 403 as well, but it turns out that it can be used for "reasons unrelated to the credentials [of the request]" (reference).

So it may be most appropriate for this error response to use both M_FORBIDDEN and HTTP 403. That change is made by d91a932.

Comment thread proposals/4140-delayed-events-futures.md Outdated
Comment thread proposals/4140-delayed-events-futures.md Outdated
Comment thread proposals/4140-delayed-events-futures.md Outdated
Comment thread proposals/4140-delayed-events-futures.md Outdated
Comment on lines +503 to +504
The main benefit of reusing the endpoints as described is the potential for code reuse in homeserver implementations.
However, this could be negated by the complexity of having to support multiple response body formats.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have evidence of this being attempted? It seems like a great alternative (we aren't that worried about different response formats, generally speaking).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The currently merged implementations (element-hq/synapse#17326 & matrix-org/matrix-js-sdk#4294) use query strings. There are follow-up unmerged PRs that switch to dedicated endpoints (element-hq/synapse#19354 & matrix-org/matrix-js-sdk#5133).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm, I'm worried that there's seemingly viable implementations for both the MSC and the alternative. Where was the motivation to switch to a dedicated endpoint discussed? (links please)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mentioned on a call: there was a discussion thread a few months ago which requested the split. On the call, multiple teams nodded in approval to the sentiments of having a different endpoint.

The ask is to incorporate a link into the MSC for that discussion, and include context in case links break/change (again).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

955ecf5 adds a link to the criticisms of the shared endpoint that motivated the move to a dedicated endpoint, and expands upon it lest the deep link gets lost & so that the MSC alone may be sufficient in communicating what the criticisms were.

Comment thread proposals/4140-delayed-events-futures.md Outdated
- `last_restart` - but this feels less clear than `running_since` for a delayed event that hasn't been restarted
- `send_time` - with a value of `delay` + the start time of the timer

### Syncing failed delayed events

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(+1 to pushing syncing failed delayed events out to its own MSC if/when needed rather than build it up front)

Johennes and others added 10 commits June 29, 2026 09:03
Co-authored-by: Travis Ralston <travisr@matrix.org>
Co-authored-by: Travis Ralston <travisr@matrix.org>
Co-authored-by: Travis Ralston <travisr@matrix.org>
Co-authored-by: Travis Ralston <travisr@matrix.org>
Co-authored-by: Travis Ralston <travisr@matrix.org>
Co-authored-by: Travis Ralston <travisr@matrix.org>
Co-authored-by: Travis Ralston <travisr@matrix.org>
Co-authored-by: Travis Ralston <travisr@matrix.org>
Co-authored-by: Travis Ralston <travisr@matrix.org>
Co-authored-by: Travis Ralston <travisr@matrix.org>
Comment thread proposals/4140-delayed-events-futures.md Outdated
@turt2live

Copy link
Copy Markdown
Member

With the assumption that the alternative gets further information added into the MSC, this appears ready to go (though there's no comments on the M_FORBIDDEN thread 😇)

@mscbot fcp merge

@mscbot

mscbot commented Jun 30, 2026

Copy link
Copy Markdown
Collaborator

Team member @turt2live has proposed to merge this. The next step is review by the rest of the tagged people:

Once at least 75% of reviewers approve (and there are no outstanding concerns), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up!

See this document for information about what commands tagged team members can give me.

@mscbot mscbot added proposed-final-comment-period Currently awaiting signoff of a majority of team members in order to enter the FCP. Process state. disposition-merge Process state. labels Jun 30, 2026
@turt2live

Copy link
Copy Markdown
Member

MSCs proposed for Final Comment Period (FCP) should meet the requirements outlined in the checklist prior to being accepted into the spec. This checklist is a bit long, but aims to reduce the number of follow-on MSCs after a feature lands.

SCT members: please check off things you check for, and raise a concern against FCP if the checklist is incomplete. If an item doesn't apply, prefer to check it rather than remove it. Unchecking items is encouraged where applicable.

MSC authors: feel free to ask in a thread on your MSC or in the#matrix-spec:matrix.org room for clarification of any of these points.

  • Are appropriate implementation(s) specified in the MSC’s PR description?
  • Are all MSCs that this MSC depends on already accepted?
  • For each new endpoint that is introduced:
    • Have authentication requirements been specified?
    • Have rate-limiting requirements been specified?
    • Have guest access requirements been specified?
    • Are error responses specified?
      • 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?
  • 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, 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 the endpoint conventions honoured?
    • Do HTTP endpoints use_underscores_like_this?
    • Will the endpoint return unbounded data? If so, has pagination been considered?
    • If the endpoint utilises pagination, is it consistent with the appendices?
  • 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 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:
    • Introduction
    • Proposal text
    • Potential issues
    • Alternatives
    • Dependencies
  • Stable identifiers are used throughout the proposal, except for the unstable prefix section
    • Unstable prefixes consider the awkward accepted-but-not-merged state
    • Chosen unstable prefixes do not pollute any global namespace (use “org.matrix.mscXXXX”, not “org.matrix”).
  • Changes have applicable 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 for things to think about, but in particular pay attention to the OWASP Top Ten.

Comment on lines +96 to +98
If a requested delay exceeds this maximum, the homeserver will respond with HTTP 400
and a [standard error response](https://spec.matrix.org/v1.18/client-server-api/#standard-error-response)
with an `errcode` of `M_INVALID_PARAM`.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To go even further with #4140 (comment), how about returning M_FORBIDDEN & HTTP 403 even for this case of requesting a delay longer than allowed?

This would prevent needing a special case error response for delayed events being entirely disallowed, as both that case & this one would then both give the same response.

It also looks like the spec uses M_INVALID_PARAM only for parameter values that are always invalid (like a malformed room alias or MXID), as opposed to values that are disallowed by server config that may change later.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Erm, actually, the special case would still be needed for when the maximum per-user amount of delayed events is 0, lest the response would be M_LIMIT_EXCEEDED & HTTP 429 for a limit that can never be satisfied.

But the point stands about M_FORBIDDEN & HTTP 403 potentially being more appropriate than M_INVALID_PARAM / HTTP 400.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the interest of progressing with the Synapse implementation of MSC4140 error codes (PR), I've committed this change as 9447ee0.

I've also updated the PR description accordingly.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But the point stands about M_FORBIDDEN & HTTP 403 potentially being more appropriate than M_INVALID_PARAM / HTTP 400.

This sounds sensible to me.

Also reword the special case error response now that only the 0-limit
case is special

The `delay_id` is an [opaque identifier](https://spec.matrix.org/v1.18/appendices/#opaque-identifiers)
generated by the homeserver.
It MUST be globally unique and SHOULD be cryptographically secure (in the sense that it is infeasible to predict).

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a mismatch here with the wording in the Security considerations – Authentication section below, which says

As such, generated delay_ids MUST be cryptographically random such that they are difficult to guess.

  1. "cryptographically random" vs. "cryptographically secure" – I think a more accurate and unambiguous wording in both places would be something like

    generated using a CSPRNG (Cryptographically Secure Pseudorandom Number Generator) and has sufficient entropy

  2. MUST vs. SHOULD – I would change the SHOULD here to MUST, because that's what the authentication for these endpoints through knowledge of delay_id relies on.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A bit later, "the cryptographic security of the delay_id" is mentioned again, which reads a bit weird to me. Alternatives that would sound better to me are for example

  • the CSPRNG-generated delay_id, or
  • the cryptographic randomness of the delay_id, or
  • the unpredictability of the delay_id.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A bit later, "the cryptographic security of the delay_id" is mentioned again, which reads a bit weird to me. Alternatives that would sound better to me are for example

* the CSPRNG-generated `delay_id`, or

* the cryptographic randomness of the `delay_id`, or

* the unpredictability of the `delay_id`.

This part was resolved in 5dac49c. The original comment above is still open though.

Comment thread proposals/4140-delayed-events-futures.md Outdated
Comment thread proposals/4140-delayed-events-futures.md Outdated
Comment thread proposals/4140-delayed-events-futures.md Outdated
Comment thread proposals/4140-delayed-events-futures.md Outdated
Comment on lines +246 to +248
A new authenticated Client-Server API endpoint at
`GET /_matrix/client/v1/delayed_events/{delay_id}` responds with
details on the delayed event with the specified `delay_id` owned by the requesting user.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a sort of duplicate authentication here: That of the requesting user via the standard authenticated endpoint mechanism, and through knowledge of the delay_id as explained in this MSC. While the management endpoints above only check for the latter, this GET endpoint should also check that the requesting, authenticated user owns the specified delay_id. This is somewhat suggested by the wording "the specified delay_id owned by the requesting user", but not entirely clear. I think it should be made explicit what happens if the given delay_id exists, but is not owned by the requesting user.

However, this is not strictly necessary for delayed events to be usable, and may thus be discussed in a separate MSC
in the interest of keeping this MSC focused on the core functionality of delayed events.

## Security considerations

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An aspect I'm missing here is the fact that the POST /delayed_events/{delay_id}/{action} and GET /_matrix/client/v1/delayed_events/{delay_id} endpoints are including the delay_id, which is aptly described to "behave as a scoped access token". This risks a delay_id, i.e. an access token, getting leaked to various logs.

Can this risk be avoided / reduced by putting the delay_id in a header field or the request body instead? If there's technical reasons to not do that, this should at least be mentioned in the Security Considerations.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suspect the main reason is that in the path in makes for a very natural REST API shape.

I think putting it into the body would require changing GET /_matrix/client/v1/delayed_events/{delay_id} to POST. It's not as nice an API but would probably work.

As a header, we could leave the HTTP method unchanged. The API shape strikes me as equally odd but technically it should also be possible.

@AndrewFerr curious what you think? Have I missed any reasons why this needs to be in the path?


#### `delay_id` in `unsigned` event data
The `delay_id` of a sent delayed event MUST be included in the resulting room event's `unsigned` data
if, and only if, the client being given the event is authenticated as the event's sender.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm also quite confused by this paragraph. I might be missing some general background knowledge, but I think what might be missing is a mention of the context that "the client being given the event" happens in. It's also not made explicit that the homeserver (I guess?) is doing the "giving" here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

00-weekly-pings Tracking for weekly pings in the SCT office. 00 to make it first in the labels list. A-Client Server Client-Server API A-VOIP disposition-merge Process state. kind:feature MSC for not-core and not-maintenance stuff matrix-2.0 Required for Matrix 2.0 (note: do not rename - used in reports/links) proposal A matrix spec change proposal. Process state. proposed-final-comment-period Currently awaiting signoff of a majority of team members in order to enter the FCP. Process state.

Projects

Status: Ready for FCP ticks

Development

Successfully merging this pull request may close these issues.