You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
matrix-spec-proposals/proposals/4369-capability-error-code.md

133 lines
7.3 KiB
Markdown

# MSC4369: M_CAPABILITY_NOT_ENABLED error code for when capability is not enabled on an API endpoint
The [capabilities negotiation] feature in the [Client-Server API] provides a mechanism for clients
to discover whether specific capabilities are available to a user.
However, the endpoints that use capabilities do not currently specify what error response a client
should expect if they try to use an API that does not have the capability enabled for the user.
I believe this is an omission in the current spec that should be addressed for existing capabilities
and be checked for future MSCs that use capabilities.
For background: this MSC originates from a
[spec PR](https://github.com/matrix-org/matrix-spec/pull/2212) that has since been closed.
## Proposal
Define a new [other error code] of `M_CAPABILITY_NOT_ENABLED`.
Define the following behaviour for existing API endpoints that use capabilities:
Capability|Endpoint(s)|Current spec|Proposed behaviour
-|-|-|-
[`m.change_password`]|[`POST /_matrix/client/v3/account/password`]|Not defined|Return `403` with `M_CAPABILITY_NOT_ENABLED` if `m.change_password`.`enabled` is `false`
[`m.profile_fields`]|[`PUT /_matrix/client/v3/profile/{userId}/{keyName}`] [`DELETE /_matrix/client/v3/profile/{userId}/{keyName}`]|`403` for `PUT`. Maybe `403` for `DELETE`. Error code not specified for either|Return `403` with `M_CAPABILITY_NOT_ENABLED` if: `m.profile_fields`.`enabled` is `false`; or, `m.profile_fields`.`disallowed` contains `{keyName}`;
[`m.set_displayname`]|As per `m.profile_fields`|As per `m.profile_fields`|Return `403` with `M_CAPABILITY_NOT_ENABLED` if: `m.profile_fields`.`enabled` is `false`; or, `m.profile_fields`.`disallowed` contains `{keyName}`; or, `m.set_displayname`.`enabled` is `false`;
[`m.set_avatar_url`]|As per `m.profile_fields`|As per `m.profile_fields`|Return `403` with `M_CAPABILITY_NOT_ENABLED` if: `m.profile_fields`.`enabled` is `false`; or, `m.profile_fields`.`disallowed` contains `{keyName}`; or, `m.set_avatar_url`.`enabled` is `false`;
[`m.3pid_changes`]|[`POST /_matrix/client/v3/account/3pid`] [`POST /_matrix/client/v3/account/3pid/add`] [`POST /_matrix/client/v3/account/3pid/delete`]|Not defined|Return `403` with `M_CAPABILITY_NOT_ENABLED` if `m.3pid_changes`.`enabled` is `false`
[`m.get_login_token`]|[`POST /_matrix/client/v1/login/get_token`]|Maybe `400` with undefined error code if `m.get_login_token`.`enabled` is `false`|`403` with `M_CAPABILITY_NOT_ENABLED` if `m.get_login_token`.`enabled` is `false`
## Potential issues
### Possible change in behaviour on `m.get_login_token`
The spec for [`POST /_matrix/client/v1/login/get_token`] says:
> **Status** 400
> The request was malformed, or the user does not have an ability to generate tokens for their devices, as implied by
> the User-Interactive Authentication API.
> Clients should verify whether the user has an ability to call this endpoint with the m.get_login_token capability.
So, it doesn't explicitly say that `400` is the expected response if the capability is not available to the user. But,
it might imply it and it is possible that some implementations might rely on this.
However, a mitigation is that since [`POST /_matrix/client/v1/login/get_token`] was introduced by [MSC3882] it has
always had a capability associated with it and so clients should know to check the capability in advance.
### Changes from implementations in the wild
This is what Synapse currently returns:
Endpoint(s)|Synapse current
-|-
[`POST /_matrix/client/v3/account/password`]|`403` with `M_FORBIDDEN`
[`PUT /_matrix/client/v3/profile/{userId}/{keyName}`] [`DELETE /_matrix/client/v3/profile/{userId}/{keyName}`]|`400` with `M_FORBIDDEN`
[`POST /_matrix/client/v3/account/3pid`] [`POST /_matrix/client/v3/account/3pid/add`] [`POST /_matrix/client/v3/account/3pid/delete`]|`400` with `M_FORBIDDEN`
[`POST /_matrix/client/v1/login/get_token`]|`404` with `M_UNRECOGNIZED`
The [`POST /_matrix/client/v1/login/get_token`] one is interesting as it suggests that the `400` from the previous
section isn't used in the wild.
## Alternatives
### Codify existing Synapse behaviour
We could simply codify what is in the existing Synapse implementation (see above). This is what was originally proposed
in https://github.com/matrix-org/matrix-spec/pull/2212.
However, that doesn't consider non-Synapse implementations.
### Increment version on affected endpoints
Deprecate the old version and introduce a new version with the updated error responses.
e.g.
`POST /_matrix/client/`**`v3`**`/account/password` would be deprecated and continue to return `403` with `M_FORBIDDEN` and
`POST /_matrix/client/`**`v4`**`/account/password` would return `403` with `M_CAPABILITY_NOT_ENABLED`
### Allow client to specify versions
Perhaps this has been discussed elsewhere previously, but clients could specify a spec version alongside each request
(perhaps in an HTTP header) and the server used that to determine what error code to return.
e.g.
```http
POST /_matrix/client/v3/account/password
Host: example.com
Matrix-Version: v1.16
```
Would return `403` with `M_FORBIDDEN`. But if a later version specified then the new error code is given:
```http
POST /_matrix/client/v3/account/password
Host: example.com
Matrix-Version: v1.17
```
Could return `403` with `M_CAPABILITY_NOT_ENABLED`.
That way clients effectively opt-in to the change in format.
## Security considerations
None.
## Unstable prefix
Whilst this proposal is under development the `IO.ELEMENT.MSC4369_CAPABILITY_NOT_ENABLED` value
should be used instead of `CAPABILITY_NOT_ENABLED`.
## Dependencies
None.
[capabilities negotiation]: https://spec.matrix.org/v1.16/client-server-api/#capabilities-negotiation
[Client-Server API]: https://spec.matrix.org/v1.16/client-server-api/
[other error code]: https://spec.matrix.org/v1.16/client-server-api/#other-error-codes
[MSC3882]: https://github.com/matrix-org/matrix-spec-proposals/pull/3882
[`m.change_password`]: https://spec.matrix.org/v1.16/client-server-api/#mchange_password-capability
[`m.profile_fields`]: https://spec.matrix.org/v1.16/client-server-api/#mprofile_fields-capability
[`m.set_displayname`]: https://spec.matrix.org/v1.16/client-server-api/#mset_displayname-capability
[`m.set_avatar_url`]: https://spec.matrix.org/v1.16/client-server-api/#mset_avatar_url-capability
[`m.3pid_changes`]: https://spec.matrix.org/v1.16/client-server-api/#m3pid_changes-capability
[`m.get_login_token`]: https://spec.matrix.org/v1.16/client-server-api/#mget_login_token-capability
[`POST /_matrix/client/v3/account/password`]: https://pr2212--matrix-spec-previews.netlify.app/client-server-api/#post_matrixclientv3accountpassword
[`PUT /_matrix/client/v3/profile/{userId}/{keyName}`]: https://spec.matrix.org/v1.16/client-server-api/#put_matrixclientv3profileuseridkeyname
[`DELETE /_matrix/client/v3/profile/{userId}/{keyName}`]: https://spec.matrix.org/v1.16/client-server-api/#delete_matrixclientv3profileuseridkeyname
[`POST /_matrix/client/v3/account/3pid`]: https://spec.matrix.org/v1.16/client-server-api/#post_matrixclientv3account3pid
[`POST /_matrix/client/v3/account/3pid/add`]: https://spec.matrix.org/v1.16/client-server-api/#post_matrixclientv3account3pidadd
[`POST /_matrix/client/v3/account/3pid/delete`]: https://spec.matrix.org/v1.16/client-server-api/#post_matrixclientv3account3piddelete
[`POST /_matrix/client/v1/login/get_token`]: https://spec.matrix.org/v1.16/client-server-api/#post_matrixclientv1loginget_token