From ff141cb5c1bede3727f23a5ec1836752857385ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Commaille?= Date: Thu, 29 Jan 2026 16:19:10 +0100 Subject: [PATCH 1/7] Spec for MSC4380: Invite blocking MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Kévin Commaille --- content/client-server-api/_index.md | 1 + .../modules/invite_permission.md | 52 +++++++++++++++++++ data/api/client-server/create_room.yaml | 12 ++++- data/api/client-server/inviting.yaml | 10 +++- data/api/client-server/room_state.yaml | 8 ++- data/api/server-server/invites-v1.yaml | 8 ++- data/api/server-server/invites-v2.yaml | 8 ++- .../examples/m.invite_permission_config.yaml | 7 +++ .../schema/m.invite_permission_config.yaml | 21 ++++++++ 9 files changed, 121 insertions(+), 6 deletions(-) create mode 100644 content/client-server-api/modules/invite_permission.md create mode 100644 data/event-schemas/examples/m.invite_permission_config.yaml create mode 100644 data/event-schemas/schema/m.invite_permission_config.yaml diff --git a/content/client-server-api/_index.md b/content/client-server-api/_index.md index cb7e7391..294bf9ad 100644 --- a/content/client-server-api/_index.md +++ b/content/client-server-api/_index.md @@ -4159,3 +4159,4 @@ systems. {{% cs-module name="Recently used emoji" filename="recent_emoji" %}} {{% cs-module name="Threading" filename="threading" %}} {{% cs-module name="Reference relations" filename="reference_relations" %}} +{{% cs-module name="Invite permission" filename="invite_permission" %}} diff --git a/content/client-server-api/modules/invite_permission.md b/content/client-server-api/modules/invite_permission.md new file mode 100644 index 00000000..0f292d47 --- /dev/null +++ b/content/client-server-api/modules/invite_permission.md @@ -0,0 +1,52 @@ + +### Invite permission + +{{% added-in v="1.18" %}} + +Users may want to control who is allowed to invite them to new rooms. This module defines how +clients and servers can implement invite permission. + +#### Events + +{{% event event="m.invite_permission_config" %}} + +#### Client behaviour + +To reject invites from all users automatically, clients MUST add an [`m.invite_permission_config`](#minvite_permission_config) +event in the user's [account data](#client-config) with the `default_action` property set to +`block`. To stop rejecting all invites, the same event without the `default_action` property MUST be +added to the account data. + +When the `default_action` field is unset, other parts of the specification might still have effects +on invites seen by clients, like [ignoring users](#ignoring-users). + +When sending an invite to a user that blocks invites, clients SHOULD receive an error response with +the `M_INVITE_BLOCKED` error code. + +#### Server behaviour + +When invites to a given user are blocked, the user's homeserver MUST respond to the following +endpoints with an HTTP 403 status code, with the Matrix error code `M_INVITE_BLOCKED`, if the user +is invited: + +* [`PUT /_matrix/federation/v1/invite/{roomId}/{eventId}`](/server-server-api/#put_matrixfederationv1inviteroomideventid) +* [`PUT /_matrix/federation/v2/invite/{roomId}/{eventId}`](/server-server-api/#put_matrixfederationv2inviteroomideventid) +* [`POST /_matrix/client/v3/rooms/{roomId}/invite`](#post_matrixclientv3roomsroomidinvite) +* [`POST /_matrix/client/v3/createRoom`](#post_matrixclientv3createroom), due to a user in the + `invite` list. It is possible for one of the invited users to be rejected whilst the room creation + as a whole succeeds. +* [`PUT /_matrix/client/v3/rooms/{roomId}/state/m.room.member/{stateKey}`](#put_matrixclientv3roomsroomidstateeventtypestatekey), + when the `membership` is set to `invite`. + +In addition, existing events already in the database MUST NOT be served over client synchronisation +endpoints such as [`GET /sync`](#get_matrixclientv3sync). Invite events received over federation +should likewise not be served over `GET /sync` requests. + +Servers MAY return any suppressed invite events over `GET /sync` if invite blocking is later +disabled. + +Other endpoints, such as [`GET /rooms/{roomId}/state`](#get_matrixclientv3roomsroomidstate), are not +affected by invite blocking: invite events are returned as normal. + +The Application Services API is also unaffected by invite blocking: invite events are sent over +[`PUT /_matrix/app/v1/transactions/{txnId}`](/application-service-api/#put_matrixappv1transactionstxnid). diff --git a/data/api/client-server/create_room.yaml b/data/api/client-server/create_room.yaml index 2f9d3449..2abe963f 100644 --- a/data/api/client-server/create_room.yaml +++ b/data/api/client-server/create_room.yaml @@ -250,7 +250,6 @@ paths: } "400": description: |- - The request is invalid. A meaningful `errcode` and description error text will be returned. Example reasons for rejection include: @@ -274,6 +273,17 @@ paths: application/json: schema: $ref: definitions/errors/error.yaml + "403": + description: |- + Creating the room is not allowed. + + {{% added-in v="1.18"%}} The `M_INVITE_BLOCKED` error code is used to + indicate that one of the homeservers of the invited users rejected + the invite due to [invite blocking](/client-server-api/#invite-permission). + content: + application/json: + schema: + $ref: definitions/errors/error.yaml tags: - Room creation servers: diff --git a/data/api/client-server/inviting.yaml b/data/api/client-server/inviting.yaml index 6aa9e08a..89e3e08e 100644 --- a/data/api/client-server/inviting.yaml +++ b/data/api/client-server/inviting.yaml @@ -83,7 +83,7 @@ paths: value: {} "400": description: |- - + The request is invalid. A meaningful `errcode` and description error text will be returned. Example reasons for rejection include: @@ -99,12 +99,18 @@ paths: $ref: definitions/errors/error.yaml "403": description: |- - You do not have permission to invite the user to the room. A meaningful `errcode` and description error text will be returned. Example reasons for rejections are: + You do not have permission to invite the user to the room. A + meaningful `errcode` and description error text will be returned. + Example reasons for rejections are: - The invitee has been banned from the room. - The invitee is already a member of the room. - The inviter is not currently in the room. - The inviter's power level is insufficient to invite users to the room. + + {{% added-in v="1.18"%}} The `M_INVITE_BLOCKED` error code is used to + indicate that the homeserver rejected the invite due to + [invite blocking](/client-server-api/#invite-permission). content: application/json: schema: diff --git a/data/api/client-server/room_state.yaml b/data/api/client-server/room_state.yaml index 7096f511..015f8f9d 100644 --- a/data/api/client-server/room_state.yaml +++ b/data/api/client-server/room_state.yaml @@ -116,7 +116,13 @@ paths: "error": "The alias '#hello:example.org' does not point to this room." } "403": - description: The sender doesn't have permission to send the event into the room. + description: |- + The sender doesn't have permission to send the event into the room. + + {{% added-in v="1.18"%}} If the `eventType` is `m.room.member` and + the `membership` is `invite`, the `M_INVITE_BLOCKED` error code is + used to indicate that the homeserver rejected the invite due to + [invite blocking](/client-server-api/#invite-permission). content: application/json: schema: diff --git a/data/api/server-server/invites-v1.yaml b/data/api/server-server/invites-v1.yaml index beb44b84..ec2e56a6 100644 --- a/data/api/server-server/invites-v1.yaml +++ b/data/api/server-server/invites-v1.yaml @@ -155,11 +155,17 @@ paths: ] "403": description: |- - The invite is not allowed. This could be for a number of reasons, including: + The invite is not allowed. + + The `M_FORBIDDEN` error code is used to indicate one of the following: * The sender is not allowed to send invites to the target user/homeserver. * The homeserver does not permit anyone to invite its users. * The homeserver refuses to participate in the room. + + {{% added-in v="1.18"%}} The `M_INVITE_BLOCKED` error code is used to + indicate that the homeserver rejected the invite due to + [invite blocking](/client-server-api/#invite-permission). content: application/json: schema: diff --git a/data/api/server-server/invites-v2.yaml b/data/api/server-server/invites-v2.yaml index 7b71b472..9355d00c 100644 --- a/data/api/server-server/invites-v2.yaml +++ b/data/api/server-server/invites-v2.yaml @@ -192,11 +192,17 @@ paths: } "403": description: |- - The invite is not allowed. This could be for a number of reasons, including: + The invite is not allowed. + + The `M_FORBIDDEN` error code is used to indicate one of the following: * The sender is not allowed to send invites to the target user/homeserver. * The homeserver does not permit anyone to invite its users. * The homeserver refuses to participate in the room. + + {{% added-in v="1.18"%}} The `M_INVITE_BLOCKED` error code is used to + indicate that the homeserver rejected the invite due to + [invite blocking](/client-server-api/#invite-permission). content: application/json: schema: diff --git a/data/event-schemas/examples/m.invite_permission_config.yaml b/data/event-schemas/examples/m.invite_permission_config.yaml new file mode 100644 index 00000000..c7bb9ee7 --- /dev/null +++ b/data/event-schemas/examples/m.invite_permission_config.yaml @@ -0,0 +1,7 @@ +{ + "$ref": "core/event.json", + "type": "m.invite_permission_config", + "content": { + "default_action": "block" + } +} diff --git a/data/event-schemas/schema/m.invite_permission_config.yaml b/data/event-schemas/schema/m.invite_permission_config.yaml new file mode 100644 index 00000000..ae08cc82 --- /dev/null +++ b/data/event-schemas/schema/m.invite_permission_config.yaml @@ -0,0 +1,21 @@ +--- +$schema: https://json-schema.org/draft/2020-12/schema +allOf: + - $ref: core-event-schema/event.yaml + - title: Invite Permission + type: object + description: |- + The permission configuration for receiving invites for the current account. + properties: + content: + type: object + properties: + default_action: + type: string + description: |- + When set to `block`, the user does not wish to receive *any* room invites, and they + should be rejected automatically by the homeserver. + + A missing, invalid or unsupported value means that the user wants to receive invites + as normal. Other parts of the specification might still have effects on invites, like + [ignoring users](/client-server-api/#ignoring-users). From da5f111d12da6387a46f59914ed820e37f5ec6f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Commaille?= Date: Thu, 29 Jan 2026 16:21:14 +0100 Subject: [PATCH 2/7] Add changelog MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Kévin Commaille --- changelogs/client_server/newsfragments/2305.feature | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelogs/client_server/newsfragments/2305.feature diff --git a/changelogs/client_server/newsfragments/2305.feature b/changelogs/client_server/newsfragments/2305.feature new file mode 100644 index 00000000..2282230f --- /dev/null +++ b/changelogs/client_server/newsfragments/2305.feature @@ -0,0 +1 @@ +Add invite blocking, as per [MSC4380](https://github.com/matrix-org/matrix-spec-proposals/pull/4380). From ec694eff1e1ed501770eb3cdfa6671434f7de52d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Commaille?= Date: Fri, 30 Jan 2026 19:44:05 +0100 Subject: [PATCH 3/7] Add module to summary MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Kévin Commaille --- content/client-server-api/_index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/content/client-server-api/_index.md b/content/client-server-api/_index.md index 294bf9ad..13d3ab6d 100644 --- a/content/client-server-api/_index.md +++ b/content/client-server-api/_index.md @@ -4071,6 +4071,7 @@ that profile. | [Sticker Messages](#sticker-messages) | Optional | Optional | Optional | Optional | Optional | | [Third-party Networks](#third-party-networks) | Optional | Optional | Optional | Optional | Optional | | [Threading](#threading) | Optional | Optional | Optional | Optional | Optional | +| [Invite blocking](#invite-blocking) | Optional | Optional | Optional | Optional | Optional | *Please see each module for more details on what clients need to implement.* From 8ea6744ae0fcee94db32cc8edfdebc0a33653fde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Commaille?= Date: Fri, 30 Jan 2026 19:47:11 +0100 Subject: [PATCH 4/7] Fix section name and fragment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Kévin Commaille --- content/client-server-api/_index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/client-server-api/_index.md b/content/client-server-api/_index.md index 13d3ab6d..168eb833 100644 --- a/content/client-server-api/_index.md +++ b/content/client-server-api/_index.md @@ -4071,7 +4071,7 @@ that profile. | [Sticker Messages](#sticker-messages) | Optional | Optional | Optional | Optional | Optional | | [Third-party Networks](#third-party-networks) | Optional | Optional | Optional | Optional | Optional | | [Threading](#threading) | Optional | Optional | Optional | Optional | Optional | -| [Invite blocking](#invite-blocking) | Optional | Optional | Optional | Optional | Optional | +| [Invite permission](#invite-permission) | Optional | Optional | Optional | Optional | Optional | *Please see each module for more details on what clients need to implement.* From e3133f05862ef955f5e2882302de6e6a443a1d4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Commaille?= Date: Wed, 4 Feb 2026 09:31:52 +0100 Subject: [PATCH 5/7] Change section position MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Kévin Commaille --- content/client-server-api/_index.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/content/client-server-api/_index.md b/content/client-server-api/_index.md index 168eb833..90fd2879 100644 --- a/content/client-server-api/_index.md +++ b/content/client-server-api/_index.md @@ -4071,7 +4071,7 @@ that profile. | [Sticker Messages](#sticker-messages) | Optional | Optional | Optional | Optional | Optional | | [Third-party Networks](#third-party-networks) | Optional | Optional | Optional | Optional | Optional | | [Threading](#threading) | Optional | Optional | Optional | Optional | Optional | -| [Invite permission](#invite-permission) | Optional | Optional | Optional | Optional | Optional | +| [Invite permission](#invite-permission) | Optional | Optional | Optional | Optional | Optional | *Please see each module for more details on what clients need to implement.* @@ -4145,6 +4145,7 @@ systems. {{% cs-module name="SSO client login/authentication" filename="sso_login" %}} {{% cs-module name="Direct Messaging" filename="dm" %}} {{% cs-module name="Ignoring Users" filename="ignore_users" %}} +{{% cs-module name="Invite permission" filename="invite_permission" %}} {{% cs-module name="Sticker Messages" filename="stickers" %}} {{% cs-module name="Reporting Content" filename="report_content" %}} {{% cs-module name="Third-party Networks" filename="third_party_networks" %}} @@ -4160,4 +4161,3 @@ systems. {{% cs-module name="Recently used emoji" filename="recent_emoji" %}} {{% cs-module name="Threading" filename="threading" %}} {{% cs-module name="Reference relations" filename="reference_relations" %}} -{{% cs-module name="Invite permission" filename="invite_permission" %}} From 6097642bf981bf59ed71ddc7fe8491d7de49959d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Commaille?= Date: Wed, 4 Feb 2026 09:32:07 +0100 Subject: [PATCH 6/7] Apply suggestions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Kévin Commaille --- .../client-server-api/modules/invite_permission.md | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/content/client-server-api/modules/invite_permission.md b/content/client-server-api/modules/invite_permission.md index 0f292d47..5e5b2ac3 100644 --- a/content/client-server-api/modules/invite_permission.md +++ b/content/client-server-api/modules/invite_permission.md @@ -6,13 +6,13 @@ Users may want to control who is allowed to invite them to new rooms. This module defines how clients and servers can implement invite permission. -#### Events +#### Account data {{% event event="m.invite_permission_config" %}} #### Client behaviour -To reject invites from all users automatically, clients MUST add an [`m.invite_permission_config`](#minvite_permission_config) +To reject invites from all users automatically, clients MAY add an [`m.invite_permission_config`](#minvite_permission_config) event in the user's [account data](#client-config) with the `default_action` property set to `block`. To stop rejecting all invites, the same event without the `default_action` property MUST be added to the account data. @@ -20,8 +20,8 @@ added to the account data. When the `default_action` field is unset, other parts of the specification might still have effects on invites seen by clients, like [ignoring users](#ignoring-users). -When sending an invite to a user that blocks invites, clients SHOULD receive an error response with -the `M_INVITE_BLOCKED` error code. +Attempting to send an invite to a user that blocks invites will result in an error response with the +`M_INVITE_BLOCKED` error code. #### Server behaviour @@ -38,9 +38,8 @@ is invited: * [`PUT /_matrix/client/v3/rooms/{roomId}/state/m.room.member/{stateKey}`](#put_matrixclientv3roomsroomidstateeventtypestatekey), when the `membership` is set to `invite`. -In addition, existing events already in the database MUST NOT be served over client synchronisation -endpoints such as [`GET /sync`](#get_matrixclientv3sync). Invite events received over federation -should likewise not be served over `GET /sync` requests. +In addition, invite events for this user already in the database, or received over federation, MUST +NOT be served over client synchronisation endpoints such as [`GET /sync`](#get_matrixclientv3sync). Servers MAY return any suppressed invite events over `GET /sync` if invite blocking is later disabled. From 4ee7a84b9edd3a9e65c82cceb7f48f902d7530e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Commaille?= Date: Wed, 4 Feb 2026 09:34:35 +0100 Subject: [PATCH 7/7] Add error code to third-party invite MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Kévin Commaille --- data/api/client-server/third_party_membership.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/data/api/client-server/third_party_membership.yaml b/data/api/client-server/third_party_membership.yaml index 67caa387..87b47e1d 100644 --- a/data/api/client-server/third_party_membership.yaml +++ b/data/api/client-server/third_party_membership.yaml @@ -97,6 +97,10 @@ paths: - The invitee is already a member of the room. - The inviter is not currently in the room. - The inviter's power level is insufficient to invite users to the room. + + {{% added-in v="1.18"%}} The `M_INVITE_BLOCKED` error code is used to + indicate that the homeserver rejected the invite due to + [invite blocking](/client-server-api/#invite-permission). content: application/json: schema: