From df1e799c517a9bbdcc96e3f381fd6116d4136040 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> Date: Wed, 8 May 2024 14:51:18 +0100 Subject: [PATCH] Spec terms of service at registration (MSC1692) (#1812) Spec for matrix-org/matrix-spec-proposals#1692 Co-authored-by: Hubert Chathi --- .../client_server/newsfragments/1812.feature | 1 + content/client-server-api/_index.md | 153 ++++++++++++++++-- .../definitions/m.login.terms_params.yaml | 82 ++++++++++ 3 files changed, 226 insertions(+), 10 deletions(-) create mode 100644 changelogs/client_server/newsfragments/1812.feature create mode 100644 data/api/client-server/definitions/m.login.terms_params.yaml diff --git a/changelogs/client_server/newsfragments/1812.feature b/changelogs/client_server/newsfragments/1812.feature new file mode 100644 index 000000000..baa9aa7d6 --- /dev/null +++ b/changelogs/client_server/newsfragments/1812.feature @@ -0,0 +1 @@ +Specify terms of services at registration, as per [MSC1692](https://github.com/matrix-org/matrix-spec-proposals/pull/1692). diff --git a/content/client-server-api/_index.md b/content/client-server-api/_index.md index ba5272755..b0ce72896 100644 --- a/content/client-server-api/_index.md +++ b/content/client-server-api/_index.md @@ -546,8 +546,10 @@ request parameter. A client should first make a request with no `auth` parameter. The homeserver returns an HTTP 401 response, with a JSON body, as follows: - HTTP/1.1 401 Unauthorized - Content-Type: application/json +``` +HTTP/1.1 401 Unauthorized +Content-Type: application/json +``` ```json { @@ -590,8 +592,10 @@ given. It also contains other keys dependent on the auth type being attempted. For example, if the client is attempting to complete auth type `example.type.foo`, it might submit something like this: - POST /_matrix/client/v3/endpoint HTTP/1.1 - Content-Type: application/json +``` +POST /_matrix/client/v3/endpoint HTTP/1.1 +Content-Type: application/json +``` ```json { @@ -611,8 +615,10 @@ along with the same object as when no authentication was attempted, with the addition of the `completed` key which is an array of auth types the client has completed successfully: - HTTP/1.1 401 Unauthorized - Content-Type: application/json +``` +HTTP/1.1 401 Unauthorized +Content-Type: application/json +``` ```json { @@ -643,8 +649,10 @@ but the client may make a second attempt, it returns the same HTTP status 401 response as above, with the addition of the standard `errcode` and `error` fields describing the error. For example: - HTTP/1.1 401 Unauthorized - Content-Type: application/json +``` +HTTP/1.1 401 Unauthorized +Content-Type: application/json +``` ```json { @@ -671,8 +679,10 @@ status 401 response as above, with the addition of the standard If the request fails for a reason other than authentication, the server returns an error message in the standard format. For example: - HTTP/1.1 400 Bad request - Content-Type: application/json +``` +HTTP/1.1 400 Bad request +Content-Type: application/json +``` ```json { @@ -970,6 +980,129 @@ in the registration process that their token has expired. {{% http-api spec="client-server" api="registration_tokens" %}} +##### Terms of service at registration + +{{% added-in v="1.11" %}} + +| Type | Description | +|--------------------------|--------------------------------------------------------------------------| +| `m.login.terms` | Authentication requires the user to accept a set of policy documents. | + +{{% boxes/note %}} +The `m.login.terms` authentication type is only valid on the +[`/register`](#post_matrixclientv3register) endpoint. +{{% /boxes/note %}} + +This authentication type is used when the homeserver requires new users to +accept a given set of policy documents, such as a terms of service and a privacy +policy. There may be many different types of documents, all of which are +versioned and presented in (potentially) multiple languages. + +When the server requires the user to accept some terms, it does so by returning +a 401 response to the `/register` request, where the response body includes +`m.login.terms` in the `flows` list, and the `m.login.terms` property in the +`params` object has the structure [shown below](#definition-mloginterms-params). + +If a client encounters an invalid parameter, registration should stop with an +error presented to the user. + +The client should present the user with a checkbox to accept each policy, +including a link to the provided URL. Once the user has done so, the client +submits an `auth` dict with just the `type` and `session`, as follows, to +indicate that all of the policies have been accepted: + +```json +{ + "type": "m.login.terms", + "session": "" +} +``` + +The server is expected to track which document versions it presented to the +user during registration, if applicable. + + +**Example** + +1. A client might submit a registration request as follows: + + ``` + POST /_matrix/client/v3/register + ``` + ```json + { + "username": "cheeky_monkey", + "password": "ilovebananas" + } + ``` + +2. The server requires the user to accept some terms of service before + registration, so returns the following response: + + ``` + HTTP/1.1 401 Unauthorized + Content-Type: application/json + ``` + ```json + { + "flows": [ + { "stages": [ "m.login.terms" ] } + ], + "params": { + "m.login.terms": { + "policies": { + "terms_of_service": { + "version": "1.2", + "en": { + "name": "Terms of Service", + "url": "https://example.org/somewhere/terms-1.2-en.html" + }, + "fr": { + "name": "Conditions d'utilisation", + "url": "https://example.org/somewhere/terms-1.2-fr.html" + } + } + } + } + }, + "session": "kasgjaelkgj" + } + ``` + +3. The client presents the list of documents to the user, inviting them to + accept the polices. + +4. The client repeats the registration request, confirming that the user has + accepted the documents: + ``` + POST /_matrix/client/v3/register + ``` + ```json + { + "username": "cheeky_monkey", + "password": "ilovebananas", + "auth": { + "type": "m.login.terms", + "session": "kasgjaelkgj" + } + } + ``` + +5. All authentication steps have now completed, so the request is successful: + ``` + HTTP/1.1 200 OK + Content-Type: application/json + ``` + ```json + { + "access_token": "abc123", + "device_id": "GHTYAJCE", + "user_id": "@cheeky_monkey:matrix.org" + } + ``` + +{{% definition path="api/client-server/definitions/m.login.terms_params" %}} + #### Fallback Clients cannot be expected to be able to know how to process every diff --git a/data/api/client-server/definitions/m.login.terms_params.yaml b/data/api/client-server/definitions/m.login.terms_params.yaml new file mode 100644 index 000000000..67001c189 --- /dev/null +++ b/data/api/client-server/definitions/m.login.terms_params.yaml @@ -0,0 +1,82 @@ +# Copyright 2024 The Matrix.org Foundation C.I.C. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +type: object +title: m.login.terms params +description: Schema for `m.login.terms` entry in the `params` object in a User-Interactive Authentication response. +required: ['policies'] +properties: + policies: + type: object + description: | + A map from "Policy ID" to the current definition of this policy document. The Policy ID is a unique + identifier for a given policy document, using the [Opaque Identifier Grammar](/appendices/#opaque-identifiers). + additionalProperties: + type: object + title: Policy Definition + required: [version] + properties: + version: + type: string + description: | + The version of this policy document. This is provided as a convenience for the client, + and uses the [Opaque Identifier Grammar](/appendices/#opaque-identifiers). + additionalProperties: + type: object + title: Policy Translation + required: [name, url] + description: | + Map from language codes to details of the document in that language. + Language codes SHOULD be formatted as per [Section 2.2 of RFC + 5646](https://datatracker.ietf.org/doc/html/rfc5646#section-2.2), + though some implementations may use an underscore instead of dash + (for example, `en_US` instead of `en-US`). + properties: + name: + type: string + description: | + The name of this document, in the appropriate language. An + arbitrary string with no specified maximum length. + url: + type: string + description: | + A link to the text of this document, in the appropriate + language. MUST be a valid URI with scheme `https://` or + `http://`. Insecure HTTP is discouraged. +example: { + "policies": { + "terms_of_service": { + "version": "1.2", + "en": { + "name": "Terms of Service", + "url": "https://example.org/somewhere/terms-1.2-en.html" + }, + "fr": { + "name": "Conditions d'utilisation", + "url": "https://example.org/somewhere/terms-1.2-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" + } + } + } +} \ No newline at end of file