Skip to content

MSC4503: External Protocol Handles - #4503

Open
q-TheDog wants to merge 4 commits into
matrix-org:mainfrom
Haven-Organization:msc-external-handles
Open

MSC4503: External Protocol Handles#4503
q-TheDog wants to merge 4 commits into
matrix-org:mainfrom
Haven-Organization:msc-external-handles

Conversation

@q-TheDog

@q-TheDog q-TheDog commented Jul 11, 2026

Copy link
Copy Markdown

q-TheDog added 3 commits July 10, 2026 14:22
Defines m.external_handle, an optional field usable both as an
MSC4133 profile field and as an event content key, for showing an
account's identifier on whatever external network it came from
(e.g. a Fediverse @user@server handle).

Primary motivation is matrix-appservice-activitypub: ghost users
representing remote Fediverse actors already use displayname for the
actor's ActivityPub display name and have opaque bridge-generated
MXIDs, with nowhere standard to put the actual handle. The event-level
copy is a point-in-time snapshot, useful since a handle can change
(e.g. Fediverse account migration) after a message is sent.

protocol reuses MSC2346's protocol object shape (id/displayname/
avatar_url) rather than inventing a second convention, so a client
can show a protocol-appropriate label and icon.
@q-TheDog q-TheDog changed the title MSCXXXX: External Protocol Handles MSC4503: External Protocol Handles Jul 11, 2026

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.

Implementation requirements:

  • Client (rendering)
  • Appservice (sending)

@turt2live turt2live added proposal A matrix spec change proposal. Process state. A-Application Services Relates to the appservices spec 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 Jul 13, 2026

@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.

Early review with my SCT hat.

to tell one Fediverse "Alice" from another, or to know they're looking at a bridged account at all.

This proposal defines a small, optional field, `m.external_handle`, usable both on a user's profile
(via [MSC4133](https://github.com/matrix-org/matrix-spec-proposals/pull/4133) Extensible Profiles) and

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.

once an MSC is merged to the spec, we refer to that MSC by the spec rather than their MSC number.

present) as a generic external identifier/link, falling back to `protocol.id` itself as a label when
`protocol.displayname` is absent, rather than hiding the field entirely.

## Alternatives

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.

This needs a comparison to #4144

@q-TheDog q-TheDog Jul 13, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Reviewed MSC4144, and while there is some overlap that could be used for my use case I don't think it's quite the same and would be missing room for some data.

MSC4144 purpose: To specify a different ID, displayname, and avatar than the
sender of an event to be shown in place of the sender's information.

MSC4144 proposed use case: When you are using a single-user or "light" bridge that is intended to represent many different users. Basically an equivalent of "webhooks" from Discord. You can have one @bridge:example.com user that speaks for multiple users from an outside network.

Compare to this MSC:

MSC4503 Purpose: To specify a user's external handle, url, and protocol name/avatar on events and the user's profile. Intended to be shown in addition to the sender's Matrix ID, not in place of it.

MSC4503 proposed use case: When using an appservice bridge with a ghost user representing each external user. For messages sent by the ghost user AND on that user's profile: I want to be able to display that ghost user's handle, an icon that shows what network the user/message came from, the name of the network (e.g. "Fediverse), and also be able to include the link to their identity on the external network (e.g. their Fediverse profile).

Why MSC4144 doesn't cover this MSC:

  • MSC4144 would give me a place to store their handle, but this would not be the correct usage of it. I am not trying to replace or mask the sender's true ID/displayname/avatar as that MSC seems to be intended for. I am trying to include a 2nd ID to show alongside their Matrix ID, along with information about where it came from.

  • MSC4144 does not include a section to store the protocol block information I have here. This would leave me unable to store the protocol's ID/Name/Avatar (in my case activitypub/Fediverse/[fediverse logo]) on the event so I could have the icon near their handle like I have in my screenshots below.

  • MSC4144 does not have a place to put url for the user's external profile link

  • MSC4144 does not include being able to store the information in the user's /profile data.

Takeaways from this:

  • If MSC4144 added the protocol block and the url I could use it for events instead of what I have here. Happy to try suggesting this to tulir there if you think these would be a good fit to add there. Or would the convention be to update this MSC to simply say you can include protocol and url in m.per_message_profile?

  • I would still want to propose being able to have this information in /profile. 4144 is specifically centered around events so if needed I could just take out the event level stuff here and use this just for the /profile proposal

Comment on lines +10 to +17
[matrix-appservice-activitypub](https://github.com/Haven-Organization/matrix-appservice-activitypub), a
Matrix/ActivityPub (Fediverse) bridge, is a concrete case of this: a ghost user representing a remote
Fediverse actor already uses `displayname` for that actor's ActivityPub display name (which is
free-text and often not unique, e.g. multiple accounts named "Alice"), and its Matrix ID is an internal,
bridge-generated identifier, not the actor's real handle. There is currently nowhere standard to put
`@alice@mastodon.social`, the identifier that actually lets someone find or verify who this ghost
represents, so a client showing only `displayname` and the ghost's MXID gives a viewer no reliable way
to tell one Fediverse "Alice" from another, or to know they're looking at a bridged account at all.

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.

Bridges are given a namespace of user IDs to work within to represent other users for this reason. It's not expected that a bridge would use a single Matrix User ID to represent a remote network.

Other use cases may need this functionality, but the use case of bridges sounds like a bridge design bug.

@q-TheDog q-TheDog Jul 13, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I am currently using a namespace of @fedi_ to bridge in Fediverse users each with their own individual ghost user, so I have that part covered of not using a single Matrix ID. The problem is I can't store their external handle of @user@example.com on their user Matrix ID. Matrix localparts cannot contain "@", so I am using the convention of @fedi_user_example.com:myserver.com. Sure, a Matrix user can look at that and derive that it means @user@example.com, but that's an ugly format vs being able to just see @user@example.com. The only other place to fit a custom name is displayname, but I'm already using that for their Fediverse display name.

@Henry-Hiles

Henry-Hiles commented Jul 13, 2026

Copy link
Copy Markdown

I feel personally like this usecase is served by either Appservices (they can have a namespace for user IDs, and therefore use the external protocol user ID there), or Per-message Profiles (One account can send messages with different profiles)?

@q-TheDog

q-TheDog commented Jul 13, 2026

Copy link
Copy Markdown
Author

Including some screenshots of my use cases so far to help visualize what I'm using them for:

external_handle on an event (Hovering over the Fediverse icon next to the name shows their handle @fsf@hostux.social):
pic-selected-260713-1417-54

external_handle on user's /profile data. The link icon next to the handle brings the user to their fediverse profile of https://hostux.social/@fsf. Hovering over the fediverse icon will say "Fediverse":
pic-selected-260713-1416-59

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

Labels

A-Application Services Relates to the appservices spec 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. proposal A matrix spec change proposal. Process state.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants