Merge pull request #2140 from matrix-org/dbkr/tos_2
MSC2140: Terms of Service for ISes and IMspull/977/head
commit
356350de91
@ -0,0 +1,335 @@
|
||||
# MSC2140: Terms of Service API for Identity Servers and Integration Managers
|
||||
|
||||
[MSC1692](https://github.com/matrix-org/matrix-doc/issues/1692) introduces a
|
||||
method for homeservers to require that users read and agree to certain
|
||||
documents before being permitted to use the service. This proposal introduces a
|
||||
corresponding method that can be used with Identity Servers and Integration
|
||||
Managers.
|
||||
|
||||
Requirements for this proposal are:
|
||||
* ISes and IMs should be able to give multiple documents a user must agree to
|
||||
abide by
|
||||
* Each document shoud be versioned
|
||||
* ISes and IMs must, for each request that they handle, know that the user
|
||||
making the request has agreed to their data being used. This need not be
|
||||
absolute proof (we will always have to trust that the client actually
|
||||
showed the document to the user) but it must be reasonably demonstrable that
|
||||
the user has given informed consent for the client to use that service.
|
||||
* ISes and IMs must be able to prevent users from using the service if they
|
||||
have not provided agreement.
|
||||
* A user should only have to agree to each version of each document once for
|
||||
their Matrix ID, ie. having agreed to a set of terms in one client, they
|
||||
should not have to agree to them again when using a different client.
|
||||
* Documents should be de-duplicated between services. If two or more services
|
||||
are hosted by the same organisation, the organisation should have the
|
||||
option to give their users a single document that encompasses both services
|
||||
(bearing in mind that the user must be able to opt-out of components of a
|
||||
service whilst still being able to use the service without that component).
|
||||
|
||||
Identity Servers do not currently require any kind of user login to access the
|
||||
service and so are unable to track what users have agreed to what terms in the
|
||||
way that Homeservers do.
|
||||
|
||||
## Proposal
|
||||
|
||||
Throuhgout this proposal, $prefix will be used to refer to the prefix of the
|
||||
API in question, ie. `/_matrix/identity/v2` for the IS API and
|
||||
`/_matrix/integrations/v1` for the IM API.
|
||||
|
||||
Note the removal of the `/api` prefix and migration to v2 in the IS API
|
||||
following convention from
|
||||
[MSC2134](https://github.com/matrix-org/matrix-doc/issues/2134).
|
||||
|
||||
This proposal introduces:
|
||||
* A v2 API prefix, with authentication, for the Identity Service
|
||||
* The `$prefix/terms` endpoint
|
||||
* The `m.accepted_terms` section in account data
|
||||
* `POST /_matrix/client/r0/account/3pid/unbind` endpoints on the client/server
|
||||
API
|
||||
|
||||
This proposal removes:
|
||||
* The `bind_email` and `bind_msisdn` on the Homeserver `/register` endpoint
|
||||
|
||||
This proposal relies on both Integration Managers and Identity Servers being
|
||||
able to identify users by their MXID and store the fact that a given MXID has
|
||||
indicated that they accept the terms given. Integration Managers already
|
||||
identify users in this way by authenticating them using the OpenID endpoint on
|
||||
the Homeserver. This proposal introduces the same mechanism to Identity Servers
|
||||
and adds authentication across the Identity Service API.
|
||||
|
||||
### IS API Authentication
|
||||
|
||||
All current endpoints within `/_matrix/identity/api/v1/` will be duplicated
|
||||
into `/_matrix/identity/v2`, noting that MSC2134 changes the behaviour of
|
||||
lookups. Authentication is still expected on MSC2134's proposed endpoints.
|
||||
Support for `application/x-form-www-urlencoded` parameters in requests will
|
||||
be dropped from all endpoints.
|
||||
|
||||
Any request to any endpoint within `/_matrix/identity/v2`, with the exception
|
||||
of:
|
||||
* `/_matrix/identity/v2`
|
||||
* `/_matrix/identity/v2/pubkey/*`
|
||||
* The new `$prefix/account/register` endpoint
|
||||
* The new `GET /_matrix/identity/v2/terms`
|
||||
* `$prefix/account/logout`
|
||||
|
||||
...may return an error with `M_UNAUTHORIZED` errcode with HTTP status code 401.
|
||||
This indicates that the user must authenticate with OpenID and supply a valid
|
||||
`access_token`.
|
||||
|
||||
Clients authenticate either via an `Authorization` header with a `Bearer` token
|
||||
or an `access_token` query parameter.
|
||||
|
||||
The existing endpoints under `/_matrix/identity/api/v1/` continue to be
|
||||
unauthenticated but will be deprecated. ISes may support the old v1 API for as
|
||||
long as they wish. Once ISes remove support for the old APIs, those endpoints
|
||||
must return HTTP Status 404. Clients must update to use the v2 API as soon as
|
||||
possible.
|
||||
|
||||
OpenID authentication in the IS API will work the same as in the Integration Manager
|
||||
API, as specified in [MSC1961](https://github.com/matrix-org/matrix-doc/issues/1961).
|
||||
|
||||
When clients supply an identity server to the Homeserver in order for the
|
||||
Homeserver to make calls to the IS on its behalf, it must also supply its
|
||||
access token for the Identity Server alongside in the `id_access_token` key of
|
||||
the same JSON object. That is, in the main request object for `requestToken`
|
||||
and `/_matrix/client/r0/rooms/{roomId}/invite` requests and in the
|
||||
`threepidCreds` object when supplying 3PID credentials (eg. in the
|
||||
`m.email.identity` UI auth stage). The server must also relay
|
||||
`M_TERMS_NOT_SIGNED` errors back to the client. Exceptions to this are any
|
||||
requests where the only IS operation the Homeserver may perform is unbinding,
|
||||
ie. `/_matrix/client/r0/account/deactivate` and
|
||||
`/_matrix/client/r0/account/3pid/delete`, in which case the unbind will be
|
||||
authenticated by a signed request from the Homeserver.
|
||||
|
||||
### HS Register API
|
||||
|
||||
The `bind_email` and `bind_msisdn` options to `/_matrix/client/r0/register` in
|
||||
the client/server API will be removed. Due to the fact that
|
||||
`/_matrix/identity/v2/3pid/bind` requires authentication, it will no longer be
|
||||
possible for the Homeserver to bind 3PIDs as part of the registration process.
|
||||
|
||||
### IS Register API
|
||||
|
||||
The following new APIs will be introduced to support OpenID auth as per
|
||||
[MSC1961](https://github.com/matrix-org/matrix-doc/issues/1961):
|
||||
|
||||
* `/_matrix/identity/v2/account/register`
|
||||
* `/_matrix/identity/v2/account`
|
||||
* `/_matrix/identity/v2/account/logout`
|
||||
|
||||
Note again the removal of the `/api` prefix and migration to v2 following
|
||||
convention from
|
||||
[MSC2134](https://github.com/matrix-org/matrix-doc/issues/2134).
|
||||
|
||||
### Terms API
|
||||
|
||||
New API endpoints will be introduced:
|
||||
|
||||
#### `GET $prefix/terms`:
|
||||
This returns a set of documents that the user must agree to abide by in order
|
||||
to use the service. Its response is similar to the structure used in the
|
||||
`m.terms` UI auth flow of the Client/Server API:
|
||||
|
||||
```json
|
||||
{
|
||||
"policies": {
|
||||
"terms_of_service": {
|
||||
"version": "2.0",
|
||||
"en": {
|
||||
"name": "Terms of Service",
|
||||
"url": "https://example.org/somewhere/terms-2.0-en.html"
|
||||
},
|
||||
"fr": {
|
||||
"name": "Conditions d'utilisation",
|
||||
"url": "https://example.org/somewhere/terms-2.0-fr.html"
|
||||
}
|
||||
},
|
||||
"privacy_policy": {
|
||||
"version": "1.2",
|
||||
"en": {
|
||||
"name": "Privacy Policy",
|
||||
"url": "https://example.org/somewhere/privacy-1.2-en.html"
|
||||
},
|
||||
"fr": {
|
||||
"name": "Politique de confidentialité",
|
||||
"url": "https://example.org/somewhere/privacy-1.2-fr.html"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Each document (ie. key/value pair in the 'policies' object) MUST be
|
||||
uniquely identified by its URL. It is therefore strongly recommended
|
||||
that the URL contains the version number of the document. The name
|
||||
and version keys, however, are used only to provide a human-readable
|
||||
description of the document to the user.
|
||||
|
||||
This endpoint does *not* require authentication.
|
||||
|
||||
#### `POST $prefix/terms`:
|
||||
Requests to this endpoint have a single key, `user_accepts` whose value is
|
||||
a list of URLs (given by the `url` field in the GET response) of documents that
|
||||
the user has agreed to:
|
||||
|
||||
```json
|
||||
{
|
||||
"user_accepts": ["https://example.org/somewhere/terms-2.0-en.html"]
|
||||
}
|
||||
```
|
||||
|
||||
This endpoint requires authentication.
|
||||
|
||||
The clients MUST include the correct URL for the language of the document that
|
||||
was presented to the user and they agreed to. Servers should accept agreement
|
||||
of any one language of each document as sufficient, regardless of what language
|
||||
a client is operating in: users should not have to re-consent to documents if
|
||||
they change their client to a different language.
|
||||
|
||||
The server responds with an empty JSON object. The server must not assume that
|
||||
the client will agree to all documents in a single request.
|
||||
|
||||
### Accepted Terms Account Data
|
||||
|
||||
This proposal also defines the `m.accepted_terms` section in User Account
|
||||
Data in the client/server API that clients SHOULD use to track what sets of
|
||||
terms the user has consented to. This has an array of URLs under the 'accepted'
|
||||
key to which the user has agreed to.
|
||||
|
||||
An `m.accepted_terms` section therefore resembles the following:
|
||||
|
||||
```json
|
||||
{
|
||||
"accepted": [
|
||||
"https://example.org/somewhere/terms-1.2-en.html",
|
||||
"https://example.org/somewhere/privacy-1.2-en.html"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Whenever a client submits a `POST $prefix/terms` request to an IS or IM or
|
||||
completes an `m.terms` flow on the HS (or as soon as possible afterwards, ie.
|
||||
after registration is complete), it SHOULD update this account data section
|
||||
adding any the URLs of any additional documents that the user agreed to to this
|
||||
list.
|
||||
|
||||
### Terms Acceptance in the API
|
||||
|
||||
Before any requests are made to an Identity Server or Integration Manager,
|
||||
the client must use the `GET $prefix/terms` endpoint to fetch the set of
|
||||
documents that the user must agree to in order to use the service.
|
||||
|
||||
It then cross-references this set of documents against the `m.accepted_terms`
|
||||
account data and presents to the user any documents that they have not already
|
||||
agreed to, along with UI for them to indicate their agreement. If there are no
|
||||
such documents (ie. if the `policies` dict is empty or the user has already
|
||||
agreed to all documents) the client proceeds to perform the OpenID
|
||||
registration. If there are new terms documents, the client prompts the user for
|
||||
agreement, then once the user has indicated their agreement, it adds these URLs
|
||||
to `m.accepted_terms` account data and then proceeds with OpenID
|
||||
authentication, getting a token from the Homeserver and submitting this to the
|
||||
service using the `register` endpoint.
|
||||
|
||||
Having done this, if the user agreed to any new documents, it performs a `POST
|
||||
$prefix/terms` request to signal to the server the set of documents that the
|
||||
user has agreed to.
|
||||
|
||||
Any request to any endpoint in the IM API, and the `/_matrix/identity/v2/`
|
||||
namespace of the IS API, with the exception of `/_matrix/identity/v2` itself,
|
||||
may return:
|
||||
|
||||
* `M_UNAUTHORIZED` errcode with HTTP status code 401. This indicates that
|
||||
the user must authenticate with OpenID and supply a valid `access_token`.
|
||||
* `M_TERMS_NOT_SIGNED` errcode with HTTP status code 403. This indicates
|
||||
that the user must agree to (new) terms in order to use or continue to
|
||||
use the service.
|
||||
|
||||
The `/_matrix/identity/v2/3pid/unbind` endpoint must not return either of these
|
||||
errors if the request has a valid signature from a Homeserver, and is being authenticated as such.
|
||||
|
||||
In summary, the process for using a service that has not previously been used
|
||||
in the current login session is:
|
||||
|
||||
* `GET $prefix/terms`
|
||||
* Compare result with `m.accepted_terms` account data, get set of documents
|
||||
pending agreement.
|
||||
* If non-empty, show this set of documents to the user and wait for the user
|
||||
to indicate their agreement.
|
||||
* Add the newly agreed documents to `m.accepted_terms`.
|
||||
* On success, or if there were no documents pending agreement, get an OpenID
|
||||
token from the Homeserver and submit this token to the `register` endpoint.
|
||||
Store the resulting access token.
|
||||
* If the set of documents pending agreement was non-empty, Perform a
|
||||
`POST $prefix/terms` request to the service with these documents.
|
||||
|
||||
### `POST /_matrix/client/r0/account/3pid/unbind`
|
||||
|
||||
A client uses this client/server API endpoint to request that the Homeserver
|
||||
removes the given 3PID from the given Identity Server, or all Identity Servers.
|
||||
Takes the same parameters as
|
||||
`POST /_matrix/client/r0/account/3pid/delete`, ie. `id_server`, `medium`,
|
||||
`address` and the newly added `is_token`.
|
||||
|
||||
Returns the same as `POST /_matrix/client/r0/account/3pid/delete`.
|
||||
|
||||
Clients may add IS bindings for 3PIDs that already exist on the user's
|
||||
Homeserver account by using the `POST /_matrix/client/r0/account/3pid`
|
||||
to re-add the 3PID.
|
||||
|
||||
## Tradeoffs
|
||||
|
||||
The Identity Service API previously did not require authentication, and OpenID
|
||||
is reasonably complex, adding a significant burden to both clients and servers.
|
||||
A custom HTTP header was also considered that could be added to assert that the
|
||||
client agrees to a particular set of terms. We decided against this in favour
|
||||
of re-using existing primitives that already exist in the Matrix ecosystem.
|
||||
Custom HTTP headers are not used anywhere else within Matrix. This also gives a
|
||||
very simple and natural way for ISes to enforce that users may only bind 3PIDs
|
||||
to their own MXIDs.
|
||||
|
||||
This introduces a different way of accepting terms from the client/server API
|
||||
which uses User-Interactive Authentication. In the client/server API, the use
|
||||
of UI auth allows terms acceptance to be integrated into the registration flow
|
||||
in a simple and backwards-compatible way. Another option here would be to use
|
||||
UI Auth on the register endpoint. This would also not allow users to register
|
||||
before accepting the terms. However, this would then make the OpenID
|
||||
registration process different and non-standard.
|
||||
|
||||
The `m.accepted_terms` section contains only URLs of the documents that
|
||||
have been agreed to. This loses information like the name and version of
|
||||
the document, but:
|
||||
* It would be up to the clients to copy this information correctly into
|
||||
account data.
|
||||
* Having just the URLs makes it much easier for clients to make a list
|
||||
of URLs and find documents not already agreed to.
|
||||
|
||||
## Potential issues
|
||||
|
||||
This change deprecates all v1 endpoints and so will require clients to update
|
||||
to continue working.
|
||||
|
||||
## Security considerations
|
||||
|
||||
Requiring authentication on the IS API means it will no longer be possible to
|
||||
use it anonymously.
|
||||
|
||||
It is assumed that once servers publish a given version of a document at a
|
||||
given URL, the contents of that URL will not change. This could be mitigated by
|
||||
identifying documents based on a hash of their contents rather than their URLs.
|
||||
Agreement to terms in the client/server API makes this assumption, so this
|
||||
proposal aims to be consistent.
|
||||
|
||||
|
||||
## Conclusion
|
||||
|
||||
This proposal adds an error response to all endpoints on the API and a custom
|
||||
HTTP header on all requests that is used to signal agreement to a set of terms
|
||||
and conditions. The use of the header is only necessary if the server has no
|
||||
other means of tracking acceptance of terms per-user. The IS API is not
|
||||
authenticated so ISes will have no choice but to use the header. The IM API is
|
||||
authenticated so IMs may either use the header or store acceptance per-user.
|
||||
|
||||
A separate endpoint is specified with a GET request for retrieving the set
|
||||
of terms required and a POST to indicate that the user consents to those
|
||||
terms.
|
Loading…
Reference in New Issue