|
| 1 | +# MSC4170: 403 error responses for profile APIs |
| 2 | + |
| 3 | +Matrix currently defines the following [client-server APIs] for profile look-ups: |
| 4 | + |
| 5 | +- [`GET /_matrix/client/v3/profile/{userId}`] |
| 6 | +- [`GET /_matrix/client/v3/profile/{userId}/avatar_url`] |
| 7 | +- [`GET /_matrix/client/v3/profile/{userId}/displayname`] |
| 8 | + |
| 9 | +These endpoints also support look-up over federation via the accompanying |
| 10 | +[server-server API]: |
| 11 | + |
| 12 | +- [`GET /_matrix/federation/v1/query/profile`] |
| 13 | + |
| 14 | +Each of these endpoints has a documented 404 response for the case that no profile |
| 15 | +information is available. |
| 16 | + |
| 17 | +> 404 There is no profile information for this user or this user does not exist. |
| 18 | +> |
| 19 | +> 404 There is no avatar URL for this user or this user does not exist. |
| 20 | +> |
| 21 | +> 404 There is no display name for this user or this user does not exist. |
| 22 | +> |
| 23 | +> 404 The user does not exist or does not have a profile. |
| 24 | +
|
| 25 | +However, `GET /_matrix/client/v3/profile/{userId}` additionally reserves a 403 |
| 26 | +status code that is not available on the other endpoints and can be used to deny |
| 27 | +profile look-ups. |
| 28 | + |
| 29 | +> 403 The server is unwilling to disclose whether the user exists and/or has profile information. |
| 30 | +
|
| 31 | +Unfortunately, the concrete semantics of when to respond with 403 are not fully |
| 32 | +spelled out in the spec and understanding prior proposals' intention requires some |
| 33 | +archeology (see the history section below). |
| 34 | + |
| 35 | +The current proposal aims to restore consistency among the profile endpoints |
| 36 | +by standardizing their 403 error response format and behaviour. |
| 37 | + |
| 38 | + |
| 39 | +## Proposal |
| 40 | + |
| 41 | +For the endpoints in the client-server API |
| 42 | + |
| 43 | +- [`GET /_matrix/client/v3/profile/{userId}`] |
| 44 | +- [`GET /_matrix/client/v3/profile/{userId}/avatar_url`] |
| 45 | +- [`GET /_matrix/client/v3/profile/{userId}/displayname`] |
| 46 | + |
| 47 | +homeservers MUST at a minimum allow profile look-up for users that either share a room |
| 48 | +with the requester or reside in a public room known to the homeserver (i.e, the same |
| 49 | +requirements as [`POST /_matrix/client/v3/user_directory/search`])[^3]. In all other |
| 50 | +cases, homeservers MAY deny profile look-up by responding with 403 `M_FORBIDDEN`. |
| 51 | + |
| 52 | +If a remote user is queried through the client-server endpoints and the query is not |
| 53 | +denied per the preceding paragraph, homeservers SHOULD query the remote server for the |
| 54 | +user's profile information. |
| 55 | + |
| 56 | +Homeservers MAY deny profile look-up over federation by responding with 403 `M_FORBIDDEN` |
| 57 | +to [`GET /_matrix/federation/v1/query/profile`]. To be clear: there is no requirement to return |
| 58 | +profiles of users in public or shared rooms over the federation API. |
| 59 | + |
| 60 | +Homeservers MAY choose whether to respond with 403 or 404 when the requested user does |
| 61 | +not exist. If the server denies profile look-up in all but the required cases, 403 is |
| 62 | +RECOMMENDED. |
| 63 | + |
| 64 | + |
| 65 | +## Potential issues |
| 66 | + |
| 67 | +Synapse already complies with this proposal in its default configuration. However, |
| 68 | +its `limit_profile_requests_to_users_who_share_rooms` config setting is only partially |
| 69 | +compatible with this proposal because it disallows profile look-up for users in public |
| 70 | +rooms that the requester does not share a room with. This inconsistency would need to |
| 71 | +be fixed if this proposal is accepted into the spec. |
| 72 | + |
| 73 | + |
| 74 | +## Alternatives |
| 75 | + |
| 76 | +None. |
| 77 | + |
| 78 | + |
| 79 | +## Security considerations |
| 80 | + |
| 81 | +This proposal allows server administrators to lock down profile look-ups via the |
| 82 | +client-server API for all situations except those in which the profile information |
| 83 | +is already available to the requester via room membership. This complements the |
| 84 | +existing ability to deny profile look-ups on the server-server API and, if configured |
| 85 | +accordingly, increases privacy for users. |
| 86 | + |
| 87 | + |
| 88 | +## History |
| 89 | + |
| 90 | +In [2017], the user directory API, [`POST /_matrix/client/v3/user_directory/search`], |
| 91 | +which closely relates to the profile APIs, was introduced into the spec. Since its |
| 92 | +inception, it contained the requirement for servers to consider (at least) users from |
| 93 | +shared and public rooms in the search. |
| 94 | + |
| 95 | +Later, [MSC1301] proposed a 403 `M_USER_NOT_PUBLIC` response on all four profile |
| 96 | +endpoints to optionally disallow profile look-up for users that the requester does |
| 97 | +not share a room with. This MSC was never accepted, but in 2019 |
| 98 | +was partially implemented by Synapse[^1]: it was only implemented for the client-server |
| 99 | +endpoints, and an error code of `M_FORBIDDEN` was used rather than `M_USER_NOT_PUBLIC`. |
| 100 | + |
| 101 | +In 2021, Synapse implemented[^2] a switchable feature to disable profile look-up |
| 102 | +over federation via a 403 `M_FORBIDDEN` response. [MSC3550] picked up on this |
| 103 | +feature and introduced this response type in the spec though only on the |
| 104 | +`GET /_matrix/client/v3/profile/{userId}` endpoint in the client-server API. |
| 105 | + |
| 106 | + |
| 107 | +## Unstable prefix |
| 108 | + |
| 109 | +None because this proposal only affects HTTP status codes and Matrix error codes. |
| 110 | + |
| 111 | + |
| 112 | +## Dependencies |
| 113 | + |
| 114 | +None. |
| 115 | + |
| 116 | + |
| 117 | +[^1]: https://github.com/element-hq/synapse/commit/c0e0740bef0db661abce352afaf6c958e276f11d |
| 118 | +[^2]: https://github.com/matrix-org/synapse/pull/9203/files#diff-2f70c35b9dd342bfdaaed445847e0ccabbad63aa9a208d80d38fb248cbf57602L311 |
| 119 | +[^3]: As stated in https://github.com/matrix-org/matrix-spec/issues/633, the spec currently |
| 120 | + doesn't clearly define what a public room is. This proposal does not aim to solve this |
| 121 | + problem and instead only requires that the user directory and profile APIs use the same |
| 122 | + definition. |
| 123 | + |
| 124 | +[`GET /_matrix/client/v3/profile/{userId}`]: https://spec.matrix.org/v1.11/client-server-api/#get_matrixclientv3profileuserid |
| 125 | +[`GET /_matrix/client/v3/profile/{userId}/avatar_url`]: https://spec.matrix.org/v1.11/client-server-api/#get_matrixclientv3profileuseridavatar_url |
| 126 | +[`GET /_matrix/client/v3/profile/{userId}/displayname`]: https://spec.matrix.org/v1.11/client-server-api/#get_matrixclientv3profileuseriddisplayname |
| 127 | +[`GET /_matrix/federation/v1/query/profile`]: https://spec.matrix.org/v1.11/server-server-api/#get_matrixfederationv1queryprofile |
| 128 | +[`POST /_matrix/client/v3/user_directory/search`]: https://spec.matrix.org/v1.11/client-server-api/#post_matrixclientv3user_directorysearch |
| 129 | +[2017]: https://github.com/matrix-org/matrix-spec-proposals/pull/1096/files#diff-332ce28a7277b9375050644632f99c0e606acb751adc54c64c5faabf981ac7edR35 |
| 130 | +[MSC1301]: https://github.com/matrix-org/matrix-spec-proposals/issues/1301 |
| 131 | +[MSC3550]: https://github.com/matrix-org/matrix-spec-proposals/pull/3550 |
| 132 | +[client-server APIs]: https://spec.matrix.org/v1.11/client-server-api/#profiles |
| 133 | +[server-server API]: https://spec.matrix.org/v1.11/server-server-api/#get_matrixfederationv1queryprofile |
0 commit comments