Specify Policy Servers (MSC4284) (#2332)
Some checks are pending
Spec / 🔎 Validate OpenAPI specifications (push) Waiting to run
Spec / 🔎 Check Event schema examples (push) Waiting to run
Spec / 🔎 Check OpenAPI definitions examples (push) Waiting to run
Spec / 🔎 Check JSON Schemas inline examples (push) Waiting to run
Spec / ⚙️ Calculate baseURL for later jobs (push) Waiting to run
Spec / 🐍 Build OpenAPI definitions (push) Blocked by required conditions
Spec / 📢 Run towncrier for changelog (push) Waiting to run
Spec / 📖 Build the spec (push) Blocked by required conditions
Spec / 🔎 Validate generated HTML (push) Blocked by required conditions
Spec / 📖 Build the historical backup spec (push) Blocked by required conditions
Spec / Create release (push) Blocked by required conditions
Spell Check / Spell Check with Typos (push) Waiting to run

* Specify Policy Servers (MSC4284)

* changelogs

* Fix placement of `required`

* Fix broken links

* Apply suggestions from code review

Co-authored-by: Kévin Commaille <76261501+zecakeh@users.noreply.github.com>
Co-authored-by: Andrew Morgan <1342360+anoadragon453@users.noreply.github.com>

* Clarify "incomplete"

* Mark ed25519 keys as required

* Add cross references throughout the spec

---------

Co-authored-by: Kévin Commaille <76261501+zecakeh@users.noreply.github.com>
Co-authored-by: Andrew Morgan <1342360+anoadragon453@users.noreply.github.com>
This commit is contained in:
Travis Ralston 2026-03-18 09:51:49 -06:00 committed by GitHub
parent 3e1cbe12f7
commit 3c9ba4a06d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 596 additions and 1 deletions

View file

@ -0,0 +1 @@
Add a "Policy Servers" module, as per [MSC4284](https://github.com/matrix-org/matrix-spec-proposals/pull/4284).

View file

@ -0,0 +1 @@
Add a concept of "Policy Servers", as per [MSC4284](https://github.com/matrix-org/matrix-spec-proposals/pull/4284).

View file

@ -469,6 +469,8 @@ The flow for auto-discovery is as follows:
{{% http-api spec="client-server" api="support" %}}
{{% http-api spec="client-server" api="policy_server" %}}
### API Versions
Upon connecting, the Matrix client and server need to negotiate which version of the specification
@ -1685,7 +1687,7 @@ For a client to be considered fully OAuth 2.0 aware it MUST:
then the client MUST redirect users to manage their account at the [account
management URL](#oauth-20-account-management), if available, instead of
providing a native UI using the legacy API endpoints.
* If the user wishes to deactivate their account then the client MUST refer
them to the account management URL.
* If the user wishes to sign out a device other than its own then the client
@ -4275,6 +4277,7 @@ that profile.
| [Read and Unread Markers](#read-and-unread-markers) | Optional | Optional | Optional | Optional | Optional |
| [Guest Access](#guest-access) | Optional | Optional | Optional | Optional | Optional |
| [Moderation Policy Lists](#moderation-policy-lists) | Optional | Optional | Optional | Optional | Optional |
| [Policy Servers](#policy-servers) | Optional | Optional | Optional | Optional | Optional |
| [OpenID](#openid) | Optional | Optional | Optional | Optional | Optional |
| [Recently used emoji](#recently-used-emoji) | Optional | Optional | Optional | Optional | Optional |
| [Reference Relations](#reference-relations) | Optional | Optional | Optional | Optional | Optional |
@ -4377,6 +4380,7 @@ systems.
{{% cs-module name="Room Upgrades" filename="room_upgrades" %}}
{{% cs-module name="Server Notices" filename="server_notices" %}}
{{% cs-module name="Moderation policy lists" filename="moderation_policies" %}}
{{% cs-module name="Policy Servers" filename="policy_servers" %}}
{{% cs-module name="Spaces" filename="spaces" %}}
{{% cs-module name="Event replacements" filename="event_replacements" %}}
{{% cs-module name="Event annotations and reactions" filename="event_annotations" %}}

View file

@ -0,0 +1,98 @@
### Policy Servers
{{% added-in v="1.18" %}}
A Policy Server is a homeserver in the room designated to proactively check events
before they are sent to the room/users. Rooms are not required to use a Policy
Server (PS). Rooms which do use a Policy Server can prevent unwanted events from
reaching users.
{{% boxes/note %}}
Room operators might prefer to use a "moderation bot" instead of a Policy Server.
Moderation bots are reactive because they typically [redact](#redactions) events
after they've already been sent.
Room operators might also prefer to layer a moderation bot with a Policy Server
for added protection.
{{% /boxes/note %}}
A room's Policy Server is designated by the [`m.room.policy`](#mroompolicy) state
event described below. If the state event is not set in the room or is missing
required fields, the room does *not* use a Policy Server. Similarly, if the server name in the state
event has zero joined users in the room, the room also does *not* use a Policy
Server.
When the room is using a Policy Server, *all* events except for the `m.room.policy`
state event itself are checked by that Policy Server. This includes membership
events, power level changes, events from before the Policy Server was enabled,
and non-state or non-empty `state_key` `m.room.policy` events.
What a Policy Server checks for on an event is left as an implementation detail.
{{% boxes/note %}}
More information about how a Policy Server operates precisely is available in
the [Server-Server API](/server-server-api/#policy-servers). Most notably, not
every homeserver is a Policy Server, and not every Policy Server is a full
homeserver.
{{% /boxes/note %}}
{{% event event="m.room.policy" %}}
#### Client behaviour
Clients do not interact with the Policy Server directly, but may need enough
information to be able to set the `m.room.policy` state event. For this, a client
can attempt to call [`/.well-known/matrix/policy_server`](#getwell-knownmatrixpolicy_server)
on a user-provided server name. The returned information can then be used to
populate the `m.room.policy` state event.
{{% boxes/note %}}
Clients are *not* required to use `/.well-known/matrix/policy_server` to populate the
`m.room.policy` state event. If they have the required information from elsewhere,
they can simply send the state event.
{{% /boxes/note %}}
#### Server behaviour
See the [Policy Servers section of the Server-Server API](/server-server-api/#policy-servers).
{{% boxes/note %}}
If implementing your own Policy Server, see [MSC4284: Policy Servers](https://github.com/matrix-org/matrix-spec-proposals/blob/main/proposals/4284-policy-servers.md)
for additional security, implementation, and safety considerations.
{{% /boxes/note %}}
#### Security considerations
{{% boxes/note %}}
Portions of this section rely on context from the [Policy Servers section of the Server-Server API](/server-server-api/#policy-servers).
{{% /boxes/note %}}
By nature of being a proactive tool for a room, Policy Server can expect to be
Denial of Service (DoS) targets. Policy Servers MUST be tolerant to DoS attacks.
The scale of attack they need to tolerate is left as an implementation/deployment
detail. A Policy Server dedicated to a small community might not have the same
requirements as a Policy Server available for many communities to use.
To help ensure that rooms can be used when their chosen Policy Server is inaccessible,
the `m.room.policy` state event can be set *without* consulting the Policy Server.
This in effect allows users with appropriate power levels to wipe the content of
`m.room.policy`, disabling the Policy Server immediately.
Policy Servers MUST have a joined user in the room to prevent rooms overloading
or forcing a given server to act as a Policy Server. The Policy Server can evict
itself from the room to also disable usage immediately.
Events sent "before" the Policy Server was enabled can end up being recommended
for exclusion by the Policy Server. This is expected behaviour to ensure new policies
apply to events which took a while to send.
Homeservers might not ask a Policy Server for a signature on an event before sending
it to the room. Other compliant homeservers will request that signature instead,
and layered tooling (like "moderation bots") can help remove events which bypass
the room's Policy Server, if desirable.
Homeservers might request and receive a valid signature for an event, but delay
or never send the event. "Moderation bots" can monitor for clock drift on signed
events, if desirable. A Policy Server implementation might also monitor for clock
drift, though does need to consider that events can be backdated in ways beyond
`origin_server_ts`.

View file

@ -473,6 +473,9 @@ server must ensure that the event:
otherwise it is rejected.
6. Passes authorization rules based on the current state of the room,
otherwise it is "soft failed".
7. {{% added-in v="1.18" %}} Is [validated](#validating-policy-server-signatures)
by the Policy Server, if the room is [using a Policy Server](#determining-if-a-policy-server-is-enabled-in-a-room),
otherwise it is "soft failed".
Further details of these checks, and how to handle failures, are
described below.
@ -689,6 +692,11 @@ then any new event `D'` will not reference `C`:
|
D'
{{% boxes/note %}}
{{% added-in v="1.18" %}}
Events can also be soft failed if they fail [Policy Server checks](#validating-policy-server-signatures).
{{% /boxes/note %}}
#### Retrieving event authorization information
The homeserver may be missing event authorization information, or wish
@ -1277,6 +1285,171 @@ endpoint MUST be protected as follows:
room ID MUST be ignored if the sending server is denied access to
the room identified by that ID.
The following endpoints MAY be protected:
- [`/_matrix/policy/v1/sign`](#post_matrixpolicyv1sign) - {{< added-in v="1.18" >}}
Protected if the server is tracking the DAG and chooses to enforce the ACL.
## Policy Servers
{{% added-in v="1.18" %}}
Policy Servers are an available tool for rooms to add proactive protections. Rooms
which use a Policy Server (PS) can prevent unwanted events from reaching users. Rooms
are not required to use a Policy Server, and can disable it any time after enabling
it.
For a homeserver to be a Policy Server, it MUST implement the following functionality
of the Server-Server API:
* [Normal server name resolution](#resolving-server-names).
* [Publishing a signing key](#publishing-keys).
* [Request authentication](#authentication).
* Being able to [make and send join requests](#joining-rooms).
* Receiving and processing [`POST /_matrix/policy/v1/sign`](#post_matrixpolicyv1sign)
requests.
All other functionality and endpoints are optional for a Policy Server.
{{% boxes/note %}}
Though a Policy Server is not required to implement the full Server-Server API
surface, some functionality may be desirable to implement anyway:
* Receiving [invites](#inviting-to-a-room) can make it easier to add the Policy
Server to a room.
* Receiving [transactions](#transactions) is recommended to avoid remote servers
flagging the Policy Server as "offline", even if the contents are discarded.
* Receiving [device lookups](#get_matrixfederationv1userdevicesuserid) can also
help reduce remote servers flagging the Policy Server as "offline".
{{% /boxes/note %}}
{{% boxes/note %}}
Policy Servers are *not* required to track the DAG for a room. Policy Servers
might be optimized for content moderation and therefore do not need knowledge of
the DAG.
{{% /boxes/note %}}
### Determining if a Policy Server is enabled in a room
For a room to be considered as "using" a Policy Server, *all* of the following
conditions MUST be true:
* The *current state* for the room has a valid [`m.room.policy`](/client-server-api/#mroompolicy)
state event with empty state key. Valid means `content` contains at least:
* A string value for `via`.
* An object value for `public_keys` containing at least a string value for
`ed25519`.
* The server name denoted by the `m.room.policy` state event's `via` has at least
one joined user in the room in *current state*. The user does not need any
special permissions or power levels in the room.
If a room has enabled a Policy Server, *all* servers in that room MUST [ask that
Policy Server](#asking-for-a-policy-server-signature-on-an-event) for a signature
before sending an event. If the Policy Server refuses to sign the event being
sent, servers SHOULD fail to send that event as per the [validation rules](#validating-policy-server-signatures).
{{% boxes/note %}}
"Current state" shares the same definition as [soft failure](#soft-failure).
{{% /boxes/note %}}
{{% boxes/note %}}
Policy Servers MUST have at least one joined user in the room to give the Policy
Server agency in whether it serves that role for the room. Otherwise, a room
would be able to force a Policy Server to participate and then overwhelm it.
{{% /boxes/note %}}
### Validating Policy Server signatures
Policy Servers use signatures to indicate whether an event was checked and is
recommended for inclusion in a room. The Policy Server's recommendation does *not*
affect the authorization rules for an event, but does affect whether homeservers
[soft fail](#soft-failure) or refuse to actually go forward with sending an event.
If a room has disabled (or never enabled) a Policy Server, events are recommended
for inclusion and subject to normal authorization rules.
{{% boxes/note %}}
Because the Policy Server is not asked to sign [`m.room.policy`](/client-server-api/#mroompolicy)
state events with empty string `state_key`s, those events will not have a Policy
Server signature. Those events are by default recommended for inclusion and still
subject to normal authorization rules.
All other events SHOULD have a valid Policy Server signature when a Policy Server
is enabled in the room, including non-state `m.room.policy` events and `m.room.policy`
state events with non-empty `state_key`s. This also includes state events like
membership and power level changes.
{{% /boxes/note %}}
If a room has enabled a Policy Server, the Policy Server's signature appears
alongside the normal [event signatures](#signing-events), though uses a public
key from the room's `m.room.policy` state event.
{{% boxes/note %}}
Currently, only Ed25519 keys are supported by homeservers. The Key ID for the
`ed25519` key in `m.room.policy` is *always* `ed25519:policy_server`.
{{% /boxes/note %}}
{{% boxes/note %}}
By embedding the Policy Server's public key into room state, the Policy Server
does not need to be online or have its keys cached by a notary in order to validate
an event.
{{% /boxes/note %}}
{{% boxes/warning %}}
The Policy Server's [published signing key](#publishing-keys) SHOULD NOT be the
same key contained in the `m.room.policy` state event. This is to keep "can send
federation traffic" and "can recommend events for inclusion" separate, and to
allow rooms to revoke the Policy Server's key without cooperation of the Policy
Server.
If the Policy Server is acting as a normal homeserver and attempting to send an
event, that event will require a signature from the server's published signing
key alongside the Policy Server signature described in this section.
{{% /boxes/warning %}}
If the Policy Server's signature is valid, the event is recommended for inclusion
in the room, and is still subject to normal authorization rules.
If the Policy Server's signature is invalid or missing, the homeserver SHOULD
[ask for a new signature](#asking-for-a-policy-server-signature-on-an-event). If
the event still does not have a valid Policy Server signature, the event is *not*
recommended for inclusion and the homeserver SHOULD:
* If applicable, reject the Client-Server API request which was generating the
event. If the Policy Server returned an error, that error SHOULD be provided
to the client verbatim. The event the client was attempting to send SHOULD be
discarded and not processed/sent any further.
* If the event was received over federation or the homeserver sends a local client's
event anyway, [soft fail](#soft-failure) the event.
{{% boxes/note %}}
For clarity, an event which lacks a valid Policy Server signature is still subject
to normal authorization rules.
{{% /boxes/note %}}
{{% boxes/note %}}
When a Policy Server's signature is invalid, a new one is requested because the
Policy Server's key may have rotated between the event being signed and the event
being checked.
Because the key is contained in the `m.room.policy` state event, if the Policy
Server rotates its key without the room also updating the state event, events
will be flagged as not recommended for inclusion. This is expected behaviour.
{{% /boxes/note %}}
### Asking for a Policy Server signature on an event
Per [above](#determining-if-a-policy-server-is-enabled-in-a-room), if a room has
a Policy Server enabled, *all* servers in the room MUST ask the Policy Server to
sign their events before sending them to clients and servers.
After asking for a signature, homeservers SHOULD [validate](#validating-policy-server-signatures)
the returned signature before continuing to send events. If the Policy Server
returns an error, the event SHOULD NOT be sent to clients and servers.
{{% http-api spec="server-server" api="room_policy" %}}
## Signing Events
Signing events is complicated by the fact that servers can choose to
@ -1300,6 +1473,12 @@ The signature is then copied back to the original event object.
For an example of a signed event, see the [room version
specification](/rooms).
{{% boxes/note %}}
{{% added-in v="1.18" %}}
Events sent in rooms with [Policy Servers](#policy-servers) MUST [ask](#asking-for-a-policy-server-signature-on-an-event)
the Policy Server for a signature too.
{{% /boxes/note %}}
### Validating hashes and signatures on received events
When a server receives an event over federation from another server, the
@ -1334,6 +1513,12 @@ only been given a redacted version of the event. To enforce this, the
receiving server should use the redacted copy it calculated rather than
the full copy it received.
{{% boxes/note %}}
{{% added-in v="1.18" %}}
Events sent in rooms with [Policy Servers](#policy-servers) have [additional](#validating-policy-server-signatures)
signature validation requirements.
{{% /boxes/note %}}
### Calculating the reference hash for an event
The *reference hash* of an event covers the essential fields of an

View file

@ -0,0 +1,82 @@
# Copyright 2026 The Matrix.org Foundation C.I.C.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
openapi: 3.1.0
info:
title: Matrix Client-Server Policy Server Discovery API
version: 1.0.0
paths:
/matrix/policy_server:
get:
summary: Gets information about a Policy Server's configuration, if available.
description: |-
Gets public key information for a [Policy Server](/client-server-api/#policy-servers).
{{% boxes/note %}}
Like the [well-known discovery URI](/client-server-api/#well-known-uris),
this endpoint should be accessed with the hostname of the Policy Server's
[server name](/appendices/#server-name) by making a
GET request to `https://hostname/.well-known/matrix/policy_server`.
{{% /boxes/note %}}
Note that this endpoint is not necessarily handled by the homeserver or
Policy Server. It may be served by another webserver.
operationId: getWellknownPolicy
x-addedInMatrixVersion: "1.18"
responses:
"200":
description: |-
Public keys for the Policy Server. Can be supplied to the [`m.room.policy`](/client-server-api/#mroompolicy)
state event.
content:
application/json:
schema:
type: object
properties:
public_keys:
type: object
description: |-
The unpadded base64-encoded public keys for the Policy Server. MUST contain
at least `ed25519`.
properties:
ed25519:
type: string
description: The unpadded base64-encoded ed25519 public key for the Policy Server.
required: ['ed25519']
additionalProperties:
type: string
description: The unpadded base64-encoded public key for the key algorithm.
required: ["public_keys"]
examples:
response:
value:
{
"public_keys": {
"ed25519": "6yhHGKhCiXTSEN2ksjV7kX_N6rBQZ3Xb-M7LlC6NS-s"
}
}
"404":
description: No policy server information available.
tags:
- Server administration
servers:
- url: "{protocol}://{hostname}{basePath}"
variables:
protocol:
enum:
- https
default: https
hostname:
default: localhost:8008
basePath:
default: /.well-known

View file

@ -0,0 +1,172 @@
# Copyright 2026 The Matrix.org Foundation C.I.C.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
openapi: 3.1.0
info:
title: Matrix Federation Room Policy API
version: 1.0.0
paths:
"/sign":
post:
summary: Asks the Policy Server to sign an event.
description: |-
A server is a Policy Server if it implements this endpoint, among
[other requirements](/server-server-api/#policy-servers). This endpoint
is otherwise optional. See [Unsupported Endpoints](/server-server-api/#unsupported-endpoints)
for details on how to exclude implementation of this endpoint.
This endpoint MUST NOT be called for events which have a type of `m.room.policy`
and an empty string `state_key`. All other events, including state events,
non-state `m.room.policy` events, and `m.room.policy` state events with
non-empty string `state_key`s are processed by this endpoint.
Whether a signature is required by a Policy Server further depends on whether
the room has [enabled a Policy Server](#determining-if-a-policy-server-is-enabled-in-a-room).
{{% boxes/note %}}
The Policy Server MAY respond with *any* of the defined errors to indicate
failure. For example, if it wishes to hide whether it knows about a room,
it MAY return `400 M_FORBIDDEN` instead (or, it MAY sign the event anyway).
{{% /boxes/note %}}
What the Policy Server checks for when calling this endpoint is left as an
implementation detail.
operationId: askPolicyServerToSign
security:
- signedRequest: []
parameters: []
requestBody:
content:
application/json:
schema:
type: object
title: PDU
description: |-
The [PDU](/server-server-api/#pdus) to request a signature for. The event format
varies depending on the room version - check the [room version specification](/rooms)
for precise event formats.
properties: {}
example:
$ref: examples/minimal_pdu.json
required: true
responses:
"200":
description: |-
The Policy Server has signed the event, indicating that it recommends the event for
inclusion in the room. Only the Policy Server's signature is returned. This signature
is to be added to the event before sending or processing the event further.
`ed25519:policy_server` is *always* used for Ed25519 signatures.
content:
application/json:
schema:
type: object
properties: {}
required: []
example: {
"policy.example.org": {
"ed25519:policy_server": "zLFxllD0pbBuBpfHh8NuHNaICpReF/PAOpUQTsw+bFGKiGfDNAsnhcP7pbrmhhpfbOAxIdLraQLeeiXBryLmBw"
}
}
"429":
$ref: '#/components/responses/rateLimited'
"400":
description: |-
The request is invalid or the Policy Server refuses to sign the event.
Error codes include:
* `M_BAD_JSON` - The supplied PDU-formatted event was improperly formatted. For example,
missing keys required for the room version.
* `M_NOT_JSON` - The body wasn't JSON.
* `M_FORBIDDEN` - The Policy Server refuses to sign the event.
content:
application/json:
schema:
# XXX: We should move error definitions into a more generic place.
$ref: ../client-server/definitions/errors/error.yaml
examples:
response:
value: {
"errcode": "M_FORBIDDEN",
"error": "The message appears to contain possible spam"
}
"403":
description: |-
The calling server is [ACL'd](/server-server-api/#server-access-control-lists-acls).
{{% boxes/note %}}
This endpoint is optionally affected by server ACLs. The Policy Server
MAY NOT apply an ACL to the request, especially if the Policy Server
is not tracking the room DAG.
{{% /boxes/note %}}
content:
application/json:
schema:
allOf:
# XXX: We should move error definitions into a more generic place.
- $ref: ../client-server/definitions/errors/error.yaml
- type: object
properties:
errcode:
description: "The `M_FORBIDDEN` error code."
required: [errcode]
examples:
response:
value: {
"errcode": "M_FORBIDDEN",
"error": "Your server is not allowed to request a signature."
}
"404":
description: |-
The server is not a Policy Server, or the room is unknown/not protected by the Policy Server.
Error codes include:
* `M_NOT_FOUND` - The room is not known or is not protected by the Policy Server.
* `M_UNRECOGNIZED` - The server is not a Policy Server. See [Unsupported Endpoints](/server-server-api/#unsupported-endpoints)
for more detail.
content:
application/json:
schema:
# XXX: We should move error definitions into a more generic place.
$ref: ../client-server/definitions/errors/error.yaml
examples:
response:
value: {
"errcode": "M_NOT_FOUND",
"error": "Unknown room"
}
servers:
- url: "{protocol}://{hostname}{basePath}"
variables:
protocol:
enum:
- http
- https
default: https
hostname:
default: localhost:8448
basePath:
default: /_matrix/policy/v1
components:
securitySchemes:
signedRequest:
$ref: definitions/security.yaml#/signedRequest
responses:
rateLimited:
description: This request was rate-limited.
content:
application/json:
schema:
# XXX: We should move error definitions into a more generic place.
$ref: ../client-server/definitions/errors/rate_limited.yaml

View file

@ -0,0 +1,11 @@
{
"$ref": "core/state_event.json",
"type": "m.room.policy",
"state_key": "",
"content": {
"via": "policy.example.org",
"public_keys": {
"ed25519": "6yhHGKhCiXTSEN2ksjV7kX_N6rBQZ3Xb-M7LlC6NS-s"
}
}
}

View file

@ -0,0 +1,41 @@
---
$schema: https://json-schema.org/draft/2020-12/schema
allOf:
- $ref: core-event-schema/state_event.yaml
description: |-
A [Policy Server](/client-server-api/#policy-servers) configuration. If invalid
or not set, the room does not use a Policy Server.
properties:
content:
properties:
via:
description: |-
The server name to use as a Policy Server. MUST have a joined user in
the room.
type: string
public_keys:
description: |-
The unpadded base64-encoded public keys for the Policy Server. MUST contain at
least `ed25519`.
type: object
properties:
ed25519:
type: string
description: The unpadded base64-encoded ed25519 public key for the Policy Server.
required: ['ed25519']
additionalProperties:
description: The unpadded base64-encoded public key for the key algorithm.
type: string
type: object
required:
- via
- public_keys
state_key:
description: An empty string.
type: string
type:
enum:
- m.room.policy
type: string
type: object