429 lines
18 KiB
Markdown
429 lines
18 KiB
Markdown
# 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. This does not affect
|
|
`avatar_url` and `displayname` fields, which are allowed for compatibility purposes.
|
|
|
|
- **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"
|
|
]
|
|
}
|
|
```
|