Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MSC4133: Extending User Profile API with Key:Value Pairs #4133

Open
wants to merge 50 commits into
base: main
Choose a base branch
from
Open
Changes from 33 commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
0e85b3b
Extended profile fields
tcpipuk Sep 1, 2024
0f373db
Unstable client features
tcpipuk Sep 1, 2024
c5a3015
Clarification on limits
tcpipuk Sep 5, 2024
c8a5a1a
Warning about avatar_url and displayname limits
tcpipuk Sep 5, 2024
3157982
Error code clarification
tcpipuk Sep 5, 2024
b8ed87a
Whitespace fixes
tcpipuk Sep 6, 2024
a81f21f
Adjusted size limits
tcpipuk Sep 11, 2024
e688eb1
Clarified Canonical JSON
tcpipuk Sep 11, 2024
39d5fa2
Clarifications
tcpipuk Sep 13, 2024
e160c71
Clarifications
tcpipuk Sep 13, 2024
a9546aa
Remove UTF-16
tcpipuk Sep 13, 2024
0c43f50
Clarify key persistence
tcpipuk Sep 13, 2024
613411a
Out of date line
tcpipuk Sep 13, 2024
4a9557f
Clarify only `u.*` namespace is limited to 512 bytes
tcpipuk Sep 16, 2024
fbb4e44
Include read-only fields in capability
tcpipuk Sep 16, 2024
591999f
Change missing capability behaviour
tcpipuk Sep 16, 2024
15a0bd1
Typo correction
tcpipuk Sep 17, 2024
26c59f7
Privacy clarification for T&S
tcpipuk Sep 24, 2024
30e82aa
Consolidation and rewrite
tcpipuk Sep 25, 2024
2966c85
Whitespace fix
tcpipuk Sep 25, 2024
d97189e
Safety and security updates
tcpipuk Sep 25, 2024
ae19725
Clarify servers can hide fields
tcpipuk Sep 25, 2024
23a3a62
References to MSC4201 and MSC4202
tcpipuk Sep 26, 2024
f32932c
Clarify redacted `m.room.member` events
tcpipuk Sep 30, 2024
4afb8b8
Error codes and redundant instructions
tcpipuk Oct 1, 2024
bb4fc76
Removing custom fields
tcpipuk Oct 2, 2024
09318e8
Typo fix
tcpipuk Oct 11, 2024
9b4741e
Clarifications and readability
tcpipuk Oct 16, 2024
068d44e
Correct key length error to match common grammar limit
tcpipuk Nov 4, 2024
fa381da
Remove PATCH/PUT.
clokep Dec 20, 2024
b373a55
Merge pull request #1 from clokep/user-prof-fields
tcpipuk Dec 20, 2024
3349123
Removed redundant sections after `PUT` and `PATCH` methods removed
tcpipuk Jan 3, 2025
9fa0096
Re-add client feature for managing profile fields
tcpipuk Jan 4, 2025
da0a791
Update proposals/4133-extended-profiles.md
tcpipuk Jan 5, 2025
a948f5d
Clarify 403 error scenarios
tcpipuk Jan 5, 2025
c82dab6
Add section on caching behaviour under S-S API
tcpipuk Jan 5, 2025
21ad83f
Link to Canonical JSON in current spec
tcpipuk Jan 5, 2025
1726ef3
Cut down instructions for clients on when to display content from fed…
tcpipuk Jan 5, 2025
30d203e
Revert c82dab67d114ded78ef4b6a5a1f9f264002d6666
tcpipuk Jan 5, 2025
43e1e1a
Clarify caching and freshness challenges
tcpipuk Jan 5, 2025
af87bbe
Adjust abuse section
tcpipuk Jan 5, 2025
f686090
Authentication/rate-limiting/guest access requirements
tcpipuk Jan 5, 2025
17cc30b
Un-revert accidental revert of af87bbeb26c6d33725d970676009b52056a87f96
tcpipuk Jan 5, 2025
d620259
Simplify caching recommendations
tcpipuk Jan 7, 2025
c1b419a
Up to clients whether they check capability
tcpipuk Jan 10, 2025
4b3a8ed
Technically correct is the best kind of correct
tcpipuk Jan 10, 2025
0f41c82
Link to current federation profile endpoint
tcpipuk Jan 10, 2025
1b98d40
Mention check for spec version when using profile fields
tcpipuk Jan 10, 2025
9b2918e
Attempt to clarify what servers should not enforce about key naming
tcpipuk Jan 10, 2025
e00d2e9
Fix line wrapping after 9b2918e3735f5aec02f6309fcbc81feaca985804
tcpipuk Jan 10, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
374 changes: 374 additions & 0 deletions proposals/4133-extended-profiles.md
turt2live marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,374 @@
# MSC4133: Extending User Profile API with Custom Key:Value Pairs
tcpipuk marked this conversation as resolved.
Show resolved Hide resolved

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.

## 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.
- **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).
- **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` will mirror the client-server
tcpipuk marked this conversation as resolved.
Show resolved Hide resolved
API changes to ensure profile information is consistent between local and federated users.

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 SHOULD check for this capability before attempting to create or modify a profile field.
tcpipuk marked this conversation as resolved.
Show resolved Hide resolved

### 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. If a server intends to deny some (or all) changes, it SHOULD use
the capability to advertise this, improving the client experience.
tcpipuk marked this conversation as resolved.
Show resolved Hide resolved

- **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, including
tcpipuk marked this conversation as resolved.
Show resolved Hide resolved
the `avatar_url` and `displayname` fields.

Homeservers SHOULD NOT enforce namespaces, as future expansions may be unknown to the server, but
Copy link
Member

Choose a reason for hiding this comment

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

Homeservers SHOULD NOT enforce namespaces

I feel like homeservers SHOULD enforce at least some of the requirements of the CNIG (key length, character set, starts with [a-z])?

I notice that an error is defined for M_KEY_TOO_LARGE which implies that there is some expectation here.

Copy link
Author

@tcpipuk tcpipuk Jan 10, 2025

Choose a reason for hiding this comment

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

Ah yes, the wording of this should be clearer... homeservers should not be checking whether the key uses a known namespace, but they must still enforce the grammar. I'll try to make this a bit more explicit.

Copy link
Author

Choose a reason for hiding this comment

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

I've had a go at this - what do you think? 9b2918e

Copy link
Author

@tcpipuk tcpipuk Jan 10, 2025

Choose a reason for hiding this comment

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

Oh, I screwed up the line wrapping, so this should fix that: e00d2e9

clients SHOULD use the correct namespace when creating or updating fields.

Keys MUST follow the [Common Namespaced Identifier Grammar](https://spec.matrix.org/unstable/appendices/#common-namespaced-identifier-grammar),
tcpipuk marked this conversation as resolved.
Show resolved Hide resolved
with the following considerations:

- **Namespace `m.*`**: Reserved for fields explicitly defined in the Matrix specification. 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
Copy link
Member

Choose a reason for hiding this comment

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

Could you add a case for M_MISSING_PARAM for if the client tries to set the profile field "foobar", yet neglects to include a "foobar" field in the PUT request body JSON?

I noticed this case was handled in the Synapse implementation, but clients will not be expecting it.

Copy link
Member

Choose a reason for hiding this comment

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

I copied that from the avatar URL profile endpoint, so probably is a spec bug that it was never documented?

Copy link
Author

Choose a reason for hiding this comment

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

I'm happy to take this opportunity to document it now? 🙂

Copy link
Member

Choose a reason for hiding this comment

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

Sounds good! Was mostly implying it housing be controversial!

Copy link
Member

Choose a reason for hiding this comment

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

When it comes time to write the spec PR, the author will be trying to match up error codes to each individual endpoint.

Is it expected that all status code/error code combinations here can be used for all Client-Server and Server-Server endpoints introduced in this MSC? If so, could you explicitly say so at the beginning of this section?

Copy link
Author

Choose a reason for hiding this comment

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

My assumption was that the Server-Server endpoints would have identical errors to the current ones, as federation access is still read-only in this MSC.

I'm happy to try to make the Client-Server endpoints a bit clearer on which errors apply to each of them though!

I might not have time to work on this over the weekend as my schedule is pretty full, but I'll try to get time ASAP 🙂

Copy link
Member

Choose a reason for hiding this comment

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

My assumption was that the Server-Server endpoints would have identical errors to the current ones, as federation access is still read-only in this MSC.

That's fine! It's just not clear with the current copy. I'd explicitly state what you just said in the MSC to make it clear.

I'm happy to try to make the Client-Server endpoints a bit clearer on which errors apply to each of them though!

That would be appreciated!


### 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_PROFILE_TOO_LARGE`**: Exceeds total profile size limits.
clokep marked this conversation as resolved.
Show resolved Hide resolved

```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.
clokep marked this conversation as resolved.
Show resolved Hide resolved

```json
{
"errcode": "M_KEY_TOO_LARGE",
"error": "The key name exceeds the maximum allowed length of 255 bytes."
anoadragon453 marked this conversation as resolved.
Show resolved Hide resolved
}
```

### 403 Forbidden: User Lacks Permission

Unchanged from the [current spec](https://spec.matrix.org/v1.13/client-server-api/#server-behaviour).
turt2live marked this conversation as resolved.
Show resolved Hide resolved

### 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).

tcpipuk marked this conversation as resolved.
Show resolved Hide resolved
```json
{
"errcode": "M_NOT_FOUND",
"error": "The requested profile key does not exist."
}
```

## 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 SHOULD cache remote profiles for at least 5 minutes after retrieval. Until a method for
servers to notify each other of updates is established, it is recommended that profiles be cached
no longer than an hour to avoid displaying stale data. Servers SHOULD NOT cache profiles for
longer than 24 hours to avoid unwanted data persistence.
tcpipuk marked this conversation as resolved.
Show resolved Hide resolved

- 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 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
Half-Shot marked this conversation as resolved.
Show resolved Hide resolved

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 offer suitable defaults for displaying user-entered
content. A user MAY choose to display fields from all users globally, but *by default* profiles
SHOULD only be shown when the users share the current room and the other user is in the `join`,
`invite`, or `knock` membership states.
turt2live marked this conversation as resolved.
Show resolved Hide resolved

If future clients (or spec proposals) implement the ability to set custom user-entered text in
profiles, servers MAY require additional moderation and safety tooling on the server side to
provide better visibility of problematic content, e.g., during reports.

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.
tcpipuk marked this conversation as resolved.
Show resolved Hide resolved

## 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"
]
}
```