Compare commits

...

38 commits

Author SHA1 Message Date
Tom Foster 91abdb19e0
Merge 6646146f8c into b278a4e0ec 2025-06-20 15:51:35 +01:00
Kévin Commaille b278a4e0ec
Clarify the differences between the two authentication APIs (#2159)
Some checks failed
Spec / 🔎 Validate OpenAPI specifications (push) Has been cancelled
Spec / 🔎 Check Event schema examples (push) Has been cancelled
Spec / 🔎 Check OpenAPI definitions examples (push) Has been cancelled
Spec / 🔎 Check JSON Schemas inline examples (push) Has been cancelled
Spec / ⚙️ Calculate baseURL for later jobs (push) Has been cancelled
Spec / 📢 Run towncrier for changelog (push) Has been cancelled
Spell Check / Spell Check with Typos (push) Has been cancelled
Spec / 🐍 Build OpenAPI definitions (push) Has been cancelled
Spec / 📖 Build the spec (push) Has been cancelled
Spec / 🔎 Validate generated HTML (push) Has been cancelled
Spec / 📖 Build the historical backup spec (push) Has been cancelled
I tried to summarize MSC3861, and add sections to be able to find quickly how to do something with either API.

Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2025-06-20 14:50:14 +00:00
Kévin Commaille ccd9e50eb1
Add OAuth 2.0 token revocation (#2151)
As per MSC4254

Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2025-06-20 10:51:17 +01:00
Kévin Commaille e4740e36e8
Add OAuth 2.0 authorization code and refresh token grant types (#2150)
As per MSC2964

Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2025-06-20 10:45:17 +01:00
Patrick Cloke 6646146f8c
Accept minor suggestions from code review
Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
2025-06-13 10:26:20 -04:00
Tom Foster 6183f2410f Clarify value validation requirements 2025-02-21 10:32:28 +00:00
Tom Foster dd4ea948b6 Clarify why avatar_url and displayname can't be returned as null 2025-02-21 09:53:43 +00:00
Tom Foster 50eab3501e Standardise line-wrapping and update avatar_url format to mx-mxc-uri 2025-02-21 09:28:46 +00:00
Tom Foster 37b1362bc1 Attempt to describe variable payload content 2025-02-20 18:08:10 +00:00
Tom Foster d8cc250d20 Tag x-addedInMatrixVersion on additionalProperties in entire profile GET 2025-02-20 17:02:23 +00:00
Tom Foster b5e2edf2e5 Add x-addedInMatrixVersion 2025-02-20 16:59:44 +00:00
Tom Foster 7ef1d9d0ec Add x-changedInMatrixVersion 2025-02-20 16:56:53 +00:00
Tom Foster 3a5e5555fa Correct PUT/GET payload definitions 2025-02-20 16:48:20 +00:00
Tom Foster 9889fe3584 Use more accessible terminology than "glob" 2025-02-20 16:40:07 +00:00
Tom Foster 013502b0c0 Mention replacement for m.set_displayname and m.set_avatar_url capability deprecation 2025-02-20 16:35:26 +00:00
Tom Foster 9859e20927 Don't use reference for capability. 2025-02-20 16:31:27 +00:00
Tom Foster 7a3b0c0804 Clarify in change log that m.set_avatar_url and m.set_displayname capabilities are now deprecated 2025-02-14 15:03:17 +00:00
Tom Foster 0b0942d192 Clarify capability lists should support wildcards 2025-02-14 15:00:53 +00:00
Tom Foster 1cc93ec951 Attempt to make descriptions look better in HTML rendered spec 2025-02-14 14:53:29 +00:00
Tom Foster 79af78022e Camel case for endpoint variables 2025-02-14 13:47:49 +00:00
Tom Foster 17af55ddce Fix broken link 2025-02-14 13:30:33 +00:00
Tom Foster 79a1cded02 Remove reference to spec version in m.profile_field capability 2025-02-14 12:57:51 +00:00
Tom Foster 76b48e25d0 Specify CNIG pattern for custom fields 2025-02-14 12:56:16 +00:00
Tom Foster 5d5b561140 Deprecate m.set_displayname and m.set_avatar_url capabilities 2025-02-14 12:47:14 +00:00
Tom Foster 9327793007 Inline information from MSC4133, remove links 2025-02-14 12:39:19 +00:00
Tom Foster f3c269d951 Added capability 2025-02-14 12:20:25 +00:00
Tom Foster 3311b084bf Alphabetise avatar_url and displayname and remove redundant descriptions on displayname 2025-02-14 12:03:49 +00:00
Tom Foster 992cf9dc35 Clarify null behaviour for PUT and DELETE 2025-02-14 11:53:19 +00:00
Tom Foster 4f8999be0a Tweak wording on full profile GET 2025-02-14 11:32:39 +00:00
Tom Foster 82adcec491 Clarify avatar_url should be MXC 2025-02-14 11:21:45 +00:00
Tom Foster 41c64c877b Linkify MSC4133 in change log 2025-02-14 11:16:40 +00:00
Tom Foster 8e9874ad22 Simplify change log 2025-02-14 11:15:00 +00:00
Tom Foster ee9b5ddcca Correct types and errors 2025-02-14 11:02:11 +00:00
Tom Foster 59d2c62d2d Link to MSC4133 in endpoint descriptions 2025-02-14 10:40:09 +00:00
Tom Foster b2e122f308 Update changelog from clarification to feature 2025-02-14 10:12:29 +00:00
Tom Foster 1fc01189f3 2071 change log 2025-02-14 09:59:22 +00:00
Tom Foster 212377e393
Merge branch 'matrix-org:main' into MSC4133 2025-02-14 09:50:59 +00:00
Tom Foster fdc012ac01 Describe MSC4133 profile endpoint changes 2025-02-13 17:54:21 +00:00
8 changed files with 687 additions and 162 deletions

View file

@ -0,0 +1 @@
Feature: Update profile endpoints to become generic to support [MSC4133](https://github.com/matrix-org/matrix-spec-proposals/pull/4133) extended fields. Extended profile fields are now supported via the new `m.profile_fields` capability, which deprecates the previous `m.set_avatar_url` and `m.set_displayname` capabilities. Stabilised keys are explicitly enumerated, and custom keys must conform to the Common Namespaced Identifier Grammar.

View file

@ -0,0 +1 @@
Add the OAuth 2.0 based authentication API, as per [MSC3861](https://github.com/matrix-org/matrix-spec-proposals/pull/3861) and its sub-proposals.

View file

@ -0,0 +1 @@
Add the OAuth 2.0 based authentication API, as per [MSC3861](https://github.com/matrix-org/matrix-spec-proposals/pull/3861) and its sub-proposals.

View file

@ -0,0 +1 @@
Add the OAuth 2.0 based authentication API, as per [MSC3861](https://github.com/matrix-org/matrix-spec-proposals/pull/3861) and its sub-proposals.

View file

@ -292,9 +292,8 @@ and the two requests would be considered distinct because the two are
considered separate endpoints. Similarly, if a client logs out and back in
between two requests using the same transaction ID, the requests are distinct
because the act of logging in and out creates a new device (unless an existing
`device_id` is passed to [`POST
/_matrix/client/v3/login`](#post_matrixclientv3login)). On the other hand, if a
client re-uses a transaction ID for the same endpoint after
`device_id` is given during the [login](#login) process). On the other hand, if
a client re-uses a transaction ID for the same endpoint after
[refreshing](#refreshing-access-tokens) an access token, it will be assumed to
be a duplicate request and ignored. See also
[Relationship between access tokens and devices](#relationship-between-access-tokens-and-devices).
@ -436,6 +435,8 @@ endpoints it supports.
## Client Authentication
{{% changed-in v="1.15" %}} OAuth 2.0 API added to the specification.
Most API endpoints require the user to identify themselves by presenting
previously obtained credentials in the form of an access token.
An access token is typically obtained via the [Login](#login) or
@ -449,6 +450,60 @@ free to choose an appropriate format. Server implementors may like to
investigate [macaroons](http://research.google.com/pubs/pub41892.html).
{{% /boxes/note %}}
Since Matrix 1.15, the Client-Server specification supports two authentication
APIs:
* The [legacy API](#legacy-api)
* The [OAuth 2.0 API](#oauth-20-api)
The legacy API has existed since the first version of the Matrix specification,
while the OAuth 2.0 API has been introduced to rely on a industry standard and
its experience rather than implementing a custom protocol that might not follow
the best practices.
A homeserver may support one of those two APIs, or both. The two APIs are
mutually incompatible, which means that after logging in, clients MUST only use
the API that was used to obtain their current access token.
{{% boxes/note %}}
Currently the OAuth 2.0 API doesn't cover all the use cases of the legacy API,
such as automated applications that cannot use a web browser, or
user management by [application services](application-service-api/#server-admin-style-permissions).
{{% /boxes/note %}}
### Authentication API discovery
To discover if a homeserver supports the legacy API, the [`GET /login`](#get_matrixclientv3login)
endpoint can be used.
To discover if a homeserver supports the OAuth 2.0 API, the
[`GET /auth_metadata`](#get_matrixclientv1auth_metadata) endpoint can be used.
In both cases, the server SHOULD respond with 404 and an `M_UNRECOGNIZED` error
code if the corresponding API is not supported.
### Account registration
With the legacy API, a client can register a new account with the
[`/register`](#post_matrixclientv3register) endpoint.
With the OAuth 2.0 API, a client can't register a new account directly. The end
user must do that directly in the homeserver's web UI. However, the client can
signal to the homeserver that the user wishes to create a new account with the
[`prompt=create`](#user-registration) parameter during authorization.
### Login
With the legacy API, a client can obtain an access token by using one of the
[login](#legacy-login) methods supported by the homeserver at the [`POST /login`](#post_matrixclientv3login)
endpoint. To invalidate the access token the client must call the [`/logout`](#post_matrixclientv3logout)
endpoint.
With the OAuth 2.0 API, a client can obtain an access token by using one of the
[grant types](#grant-types) supported by the homeserver and authorizing the
proper [scope](#scope), as demonstrated in the [login flow](#login-flow). To
invalidate the access token the client must use [token revocation](#token-revocation).
### Using access tokens
Access tokens may be provided via a request header, using the Authentication
@ -494,12 +549,14 @@ used to generate a new access token and refresh token, the new access
and refresh tokens are now bound to the device associated with the
initial refresh token.
By default, the [Login](#login) and [Registration](#account-registration)
processes auto-generate a new `device_id`. A client is also free to
generate its own `device_id` or, provided the user remains the same,
reuse a device: in either case the client should pass the `device_id` in
the request body. If the client sets the `device_id`, the server will
invalidate any access and refresh tokens previously assigned to that device.
During login or registration, the generated access token should be associated
with a `device_id`. The legacy [Login](#legacy-login) and [Registration](#legacy-account-registration)
processes auto-generate a new `device_id`, but a client is also free to provide
its own `device_id`. With the OAuth 2.0 API, the `device_id` is always provided
by the client. The client can generate a new `device_id` or, provided the user
remains the same, reuse an existing device. If the client sets the `device_id`,
the server will invalidate any access and refresh tokens previously assigned to
that device.
### Refreshing access tokens
@ -508,14 +565,13 @@ invalidate any access and refresh tokens previously assigned to that device.
Access tokens can expire after a certain amount of time. Any HTTP calls that
use an expired access token will return with an error code `M_UNKNOWN_TOKEN`,
preferably with `soft_logout: true`. When a client receives this error and it
has a refresh token, it should attempt to refresh the access token by calling
[`/refresh`](#post_matrixclientv3refresh). Clients can also refresh their
access token at any time, even if it has not yet expired. If the token refresh
succeeds, the client should use the new token for future requests, and can
re-try previously-failed requests with the new token. When an access token is
refreshed, a new refresh token may be returned; if a new refresh token is
given, the old refresh token will be invalidated, and the new refresh token
should be used when the access token needs to be refreshed.
has a refresh token, it should attempt to refresh the access token. Clients can
also refresh their access token at any time, even if it has not yet expired. If
the token refresh succeeds, the client should use the new token for future
requests, and can re-try previously-failed requests with the new token. When an
access token is refreshed, a new refresh token may be returned; if a new refresh
token is given, the old refresh token will be invalidated, and the new refresh
token should be used when the access token needs to be refreshed.
The old refresh token remains valid until the new access token or refresh token
is used, at which point the old refresh token is revoked. This ensures that if
@ -528,6 +584,7 @@ and attempt to obtain a new access token by re-logging in. If the error
response does not include a `soft_logout: true` property, the client should
consider the user as being logged out.
With the legacy API, refreshing access tokens is done by calling [`/refresh`](#post_matrixclientv3refresh).
Handling of clients that do not support refresh tokens is up to the homeserver;
clients indicate their support for refresh tokens by including a
`refresh_token: true` property in the request body of the
@ -537,6 +594,11 @@ may allow the use of non-expiring access tokens, or may expire access tokens
anyways and rely on soft logout behaviour on clients that don't support
refreshing.
With the OAuth 2.0 API, refreshing access tokens is done with the [refresh token
grant type](#refresh-token-grant), as demonstrated in the [token refresh
flow](#token-refresh-flow). Support for refreshing access tokens is mandatory
with this API.
### Soft logout
A client can be in a "soft logout" state if the server requires
@ -560,8 +622,24 @@ specifying the device ID it is already using to the login API.
with an `M_USER_LOCKED` error code, cannot obtain a new access token until
the account has been [unlocked](#account-locking).
### Account management
With the legacy API, a client can use several endpoints to allow the user to
manage their account like [changing their password](#password-management),
[managing their devices](#device-management) or
[deactivating their account](#account-deactivation).
With the OAuth 2.0 API, all account management is done via the homeserver's web
UI.
### Legacy API
This is the original authentication API that was introduced in the first version
of the Client-Server specification and uses custom APIs. Contrary to the OAuth
2.0 API, account management is primarily done in the client's interface and as
such it does not usually require the end user to be redirected to a web UI in
their browser.
#### User-Interactive Authentication API
##### Overview
@ -1329,7 +1407,7 @@ The `country` is the two-letter uppercase ISO-3166-1 alpha-2 country
code that the number in `phone` should be parsed as if it were dialled
from.
#### Login
#### Login {id="legacy-login"}
A client can obtain access tokens using the [`/login`](#post_matrixclientv3login) API.
@ -1458,11 +1536,11 @@ forwarded to the login endpoint during the login process. For example:
GET /_matrix/static/client/login/?device_id=GHTYAJCE
#### Account registration
#### Account registration {id="legacy-account-registration"}
{{% http-api spec="client-server" api="registration" %}}
#### Account management
#### Account management {id="legacy-account-management"}
##### Password management
@ -1481,6 +1559,205 @@ MAY reject weak passwords with an error code `M_WEAK_PASSWORD`.
### OAuth 2.0 API
{{% added-in v="1.15" %}}
Contrary to the legacy API that uses custom endpoints and UIA, this
authentication API is based on the [OAuth 2.0](https://oauth.net/2/) industry
standard introduced in [RFC 6749](https://datatracker.ietf.org/doc/html/rfc6749)
and extended by other RFCs, with a few features from [OpenID Connect](https://openid.net/connect/).
This allows us to benefit from its experience and from any further enhancements
or best practice recommendations.
The main change for end users with this API is that all the account management
occurs in their browser on the homeserver's web UI. This is where they will
register a new account or log into an existing account and authorize a client to
access their Matrix account. This means that the homeserver has complete control
over the requirements to create a new account and is not limited by the steps
defined in this specification. It also means that less trust is given to clients
because they don't have access to the user's credentials anymore.
{{% boxes/warning %}}
The [User-Interactive Authentication API](#user-interactive-authentication-api)
is not compatible with the OAuth 2.0 API, so the endpoints that depend on it for
authentication can't be used when an access token is obtained with this API.
{{% /boxes/warning %}}
**Sample flow**
1. [Discover the OAuth 2.0 server metadata](#server-metadata-discovery).
2. [Register the client with the homeserver](#client-registration).
3. [Obtain an access token](#login-flow) by authorizing a [scope](#scope) for the client with the [authorization code grant](#authorization-code-grant).
4. [Refresh the access token](#token-refresh-flow) with the [refresh token grant](#refresh-token-grant) when it expires.
5. [Revoke the tokens](#token-revocation) when the users wants to log out of the client.
#### Login flow
Logging in with the OAuth 2.0 API should be done with the [authorization code
grant](#authorization-code-grant). In the context of the Matrix specification,
this means requesting a [scope](#scope) including full client-server API
read/write access and allocating a device ID.
Once the client has retrieved the [server metadata](#server-metadata-discovery),
it needs to generate the following values:
- `device_id`: a unique identifier for this device; see the
[`urn:matrix:client:device:<device_id>`](#device-id-allocation) scope token.
- `state`: a unique opaque identifier, like a [transaction ID](#transaction-identifiers),
that will allow the client to maintain state between the authorization request
and the callback.
- `code_verifier`: a cryptographically random value that will allow to make sure
that the client that makes the token request for a given `code` is the same
one that made the authorization request.
It is defined in [RFC 7636](https://datatracker.ietf.org/doc/html/rfc7636) as
a high-entropy cryptographic random string using the characters `[A-Z]`,
`[a-z]`, `[0-9]`, `-`, `.`, `_` and `~` with a minimum length of 43 characters
and a maximum length of 128 characters.
**Authorization request**
The client then constructs the authorization request URL using the
`authorization_endpoint` value, with the following query parameters:
| Parameter | Value |
|-------------------------|----------------------------------------------------|
| `response_type` | `code` |
| `client_id` | The client ID returned from client registration. |
| `redirect_uri` | The redirect URI that MUST match one of the values registered in the client metadata |
| `scope` | `urn:matrix:client:api:* urn:matrix:client:device:<device_id>` with the `device_id` generated previously. |
| `state` | The `state` value generated previously. |
| `response_mode` | `fragment` or `query` (see "[Callback](#callback)" below). |
| `code_challenge` | Computed from the `code_verifier` value generated previously using the SHA-256 algorithm, as described in [RFC 7636](https://datatracker.ietf.org/doc/html/rfc7636). |
| `code_challenge_method` | `S256` |
This authorization request URL must be opened in the user's browser:
- For web-based clients, this can be done through a redirection or by opening
the URL in a new tab.
- For native clients, this can be done by opening the URL using the system
browser, or, when available, through platform-specific APIs such as
[`ASWebAuthenticationSession`](https://developer.apple.com/documentation/authenticationservices/aswebauthenticationsession)
on iOS or [Android Custom Tabs](https://developer.chrome.com/docs/android/custom-tabs).
Sample authorization request, with extra whitespaces for readability:
```
https://account.example.com/oauth2/auth?
client_id = s6BhdRkqt3 &
response_type = code &
response_mode = fragment &
redirect_uri = https://app.example.com/oauth2-callback &
scope = urn:matrix:client:api:* urn:matrix:client:device:AAABBBCCCDDD &
state = ewubooN9weezeewah9fol4oothohroh3 &
code_challenge = 72xySjpngTcCxgbPfFmkPHjMvVDl2jW1aWP7-J6rmwU &
code_challenge_method = S256
```
<a id="callback"></a> **Callback**
Once completed, the user is redirected to the `redirect_uri`, with either a
successful or failed authorization in the URL fragment or query parameters.
Whether the parameters are in the URL fragment or query parameters is determined
by the `response_mode` value:
- If set to `fragment`, the parameters will be placed in the URL fragment, like
`https://example.com/callback#param1=value1&param2=value2`.
- If set to `query`, the parameters will be in placed the query string, like
`com.example.app:/callback?param1=value1&param2=value2`.
To avoid disclosing the parameters to the web server hosting the `redirect_uri`,
clients SHOULD use the `fragment` response mode if the `redirect_uri` is an
HTTPS URI with a remote host.
In both success and failure cases, the parameters will include the `state` value
used in the authorization request.
A successful authorization will have a `code` value, for example:
```
https://app.example.com/oauth2-callback#state=ewubooN9weezeewah9fol4oothohroh3&code=iuB7Eiz9heengah1joh2ioy9ahChuP6R
```
A failed authorization will have the following values:
- `error`: the error code
- `error_description`: the error description (optional)
- `error_uri`: the URI where the user can find more information about the error (optional)
For example:
```
https://app.example.com/oauth2-callback#state=ewubooN9weezeewah9fol4oothohroh3&error=access_denied&error_description=The+resource+owner+or+authorization+server+denied+the+request.&error_uri=https%3A%2F%2Ferrors.example.com%2F
```
**Token request**
The client then exchanges the authorization code to obtain an access token using
the token endpoint.
This is done by making a POST request to the `token_endpoint` with the following
parameters, encoded as `application/x-www-form-urlencoded` in the body:
| Parameter | Value |
|-----------------|------------------------------------------------------------|
| `grant_type` | `authorization_code` |
| `code` | The value of `code` obtained from the callback. |
| `redirect_uri` | The same `redirect_uri` used in the authorization request. |
| `client_id` | The client ID returned from client registration. |
| `code_verifier` | The value generated at the start of the authorization flow. |
The server replies with a JSON object containing the access token, the token
type, the expiration time, and the refresh token.
Sample token request:
```
POST /oauth2/token HTTP/1.1
Host: account.example.com
Content-Type: application/x-www-form-urlencoded
Accept: application/json
grant_type=authorization_code
&code=iuB7Eiz9heengah1joh2ioy9ahChuP6R
&redirect_uri=https://app.example.com/oauth2-callback
&client_id=s6BhdRkqt3
&code_verifier=ogie4iVaeteeKeeLaid0aizuimairaCh
```
Sample response:
```json
{
"access_token": "2YotnFZFEjr1zCsicMWpAA",
"token_type": "Bearer",
"expires_in": 299,
"refresh_token": "tGz3JOkF0XG5Qx2TlKWIA",
"scope": "urn:matrix:client:api:* urn:matrix:client:device:AAABBBCCCDDD"
}
```
Finally, the client can call the [`/whoami`](#get_matrixclientv3accountwhoami)
endpoint to get the user ID that owns the access token.
#### Token refresh flow
Refreshing a token with the OAuth 2.0 API should be done with the [refresh token
grant](#refresh-token-grant).
When the access token expires, the client must refresh it by making a `POST`
request to the `token_endpoint` with the following parameters, encoded as
`application/x-www-form-urlencoded` in the body:
| Parameter | Value |
|-----------------|------------------------------------------------------------|
| `grant_type` | `refresh_token` |
| `refresh_token` | The `refresh_token` obtained from the token response during the last token request. |
| `client_id` | The client ID returned from client registration. |
The server replies with a JSON object containing the new access token, the token
type, the expiration time, and a new refresh token, like in the authorization
flow.
#### Server metadata discovery
{{% http-api spec="client-server" api="oauth_server_metadata" %}}
@ -1778,6 +2055,162 @@ This definition matches:
- alphanumeric characters: `A-Z`, `a-z`, `0-9`
- the following characters: ``! # $ % & ' ( ) * + , - . / : ; < = > ? @ [ ] ^ _ ` { | } ~``
#### Grant types
[RFC 6749](https://datatracker.ietf.org/doc/html/rfc6749) and other RFCs define
several "grant types": ways to obtain an ["access token"](#using-access-tokens).
All these grants types require the client to know the following [authorization
server metadata](#server-metadata-discovery):
- `token_endpoint`
- `grant_types_supported`
The client must also have obtained a `client_id` by [registering with the server](#client-registration).
This specification supports the following grant types:
- [Authorization code grant](#authorization-code-grant)
- [Refresh token grant](#refresh-token-grant)
##### Authorization code grant
As per [RFC 6749 section 4.1](https://datatracker.ietf.org/doc/html/rfc6749#section-4.1),
the authorization code grant lets the client obtain an access token through a
browser redirect.
This grant requires the client to know the following [authorization server
metadata](#server-metadata-discovery):
- `authorization_endpoint`
- `response_types_supported`
- `response_mode_supported`
To use this grant, homeservers and clients MUST:
- Support the authorization code grant as per [RFC 6749 section 4.1](https://datatracker.ietf.org/doc/html/rfc6749#section-4.1).
- Support the [refresh token grant](#refresh-token-grant).
- Support PKCE using the `S256` code challenge method as per [RFC 7636](https://datatracker.ietf.org/doc/html/rfc7636).
- Use [pre-registered](#client-registration), strict redirect URIs.
- Use the `fragment` response mode as per [OAuth 2.0 Multiple Response Type
Encoding Practices](https://openid.net/specs/oauth-v2-multiple-response-types-1_0.html)
for clients with an HTTPS redirect URI.
###### User registration
Clients can signal to the server that the user desires to register a new account
by initiating the authorization code grant with the `prompt=create` parameter
set in the authorization request as defined in [Initiating User Registration via
OpenID Connect 1.0](https://openid.net/specs/openid-connect-prompt-create-1_0.html).
Whether the homeserver supports this parameter is advertised by the
`prompt_values_supported` authorization server metadata.
Servers that support this parameter SHOULD show the account registration UI in
the browser.
##### Refresh token grant
As per [RFC 6749 section 6](https://datatracker.ietf.org/doc/html/rfc6749#section-6),
the refresh token grant lets the client exchange a refresh token for an access
token.
When authorization is granted to a client, the homeserver MUST issue a refresh
token to the client in addition to the access token.
The access token MUST be short-lived and SHOULD be refreshed using the
`refresh_token` when expired.
The homeserver SHOULD issue a new refresh token each time an old one is used,
and invalidate the old one. However, it MUST ensure that the client is able to
retry the refresh request in the case that the response to the request is lost.
The homeserver SHOULD consider that the session is compromised if an old,
invalidated refresh token is used, and SHOULD revoke the session.
The client MUST handle access token refresh failures as follows:
- If the refresh fails due to network issues or a `5xx` HTTP status code from
the server, the client should retry the request with the old refresh token
later.
- If the refresh fails due to a `4xx` HTTP status code from the server, the
client should consider the session logged out.
#### Token revocation
When a user wants to log out from a client, the client SHOULD use OAuth 2.0
token revocation as defined in [RFC 7009](https://datatracker.ietf.org/doc/html/rfc7009).
The client makes a `POST` request to the `revocation_endpoint` that can be found
in the [authorization server metadata](#server-metadata-discovery).
The body of the request includes the following parameters, encoded as
`application/x-www-form-urlencoded`:
<table>
<thead>
<tr>
<th>Parameter</th>
<th>Value</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>token</code></td>
<td>
<strong>Required.</strong> MUST contain either the access token or the
refresh token to be revoked.
</td>
</tr>
<tr>
<td><code>token_type_hint</code></td>
<td>
<strong>Optional.</strong> If present, MUST have a value of either
<code>access_token</code> or <code>refresh_token</code>. The server MAY
use this value to optimize the token lookup process.
</td>
</tr>
<tr>
<td><code>client_id</code></td>
<td>
<p>
<strong>Optional.</strong> The client identifier obtained during
<a href="#client-registration">client registration</a>.
</p>
<p>
If the <code>client_id</code> is not provided, or does not match the
client associated with the token, the server SHOULD still revoke the
token. This behavior is meant to help good actors like secret scanning
tools to proactively revoke leaked tokens. The server MAY also warn
the user that one of their sessions may be compromised in this
scenario.
</p>
</td>
</tr>
</tbody>
</table>
For example, revoking using the access token:
```
POST /oauth2/revoke HTTP/1.1
Host: auth.example.com
Content-Type: application/x-www-form-urlencoded
token=mat_ooreiPhei2wequu9fohkai3AeBaec9oo&
token_type_hint=access_token&
client_id=s6BhdRkqt3
```
The server MUST revoke both the access token and refresh token associated with
the token provided in the request.
The server SHOULD return one of the following responses:
- If the token is already revoked or invalid, the server returns a `200 OK`
response
- If the client is not authorized to revoke the token, the server returns a
`401 Unauthorized` response
- For other errors, the server returns a `400 Bad Request` response with error
details
### Account moderation
#### Account locking

View file

@ -63,7 +63,7 @@ for sending events:
The following API endpoints are allowed to be accessed by guest accounts
for their own account maintenance:
* [PUT /profile/{userId}/displayname](#put_matrixclientv3profileuseriddisplayname)
* [PUT /profile/{userId}/{keyName}](#put_matrixclientv3profileuseridkeyname)
* [GET /devices](#get_matrixclientv3devices)
* [GET /devices/{deviceId}](#get_matrixclientv3devicesdeviceid)
* [PUT /devices/{deviceId}](#put_matrixclientv3devicesdeviceid)

View file

@ -73,11 +73,17 @@ paths:
- default
- available
m.set_displayname:
deprecated: true
$ref: '#/components/schemas/booleanCapability'
description: Capability to indicate if the user can change their display name.
description: |
**Deprecated:** Capability to indicate if the user can change their display name.
Refer to `m.profile_fields` for extended profile management.
m.set_avatar_url:
deprecated: true
$ref: '#/components/schemas/booleanCapability'
description: Capability to indicate if the user can change their avatar.
description: |
**Deprecated:** Capability to indicate if the user can change their avatar.
Refer to `m.profile_fields` for extended profile management.
m.3pid_changes:
$ref: '#/components/schemas/booleanCapability'
description: Capability to indicate if the user can change 3PID associations
@ -86,6 +92,40 @@ paths:
$ref: '#/components/schemas/booleanCapability'
description: Capability to indicate if the user can generate tokens to log further
clients into their account.
m.profile_fields:
x-addedInMatrixVersion: "1.14"
type: object
title: ProfileFieldsCapability
description: Capability to indicate if the user can set or modify extended profile fields via
[`PUT /_matrix/client/v3/profile/{userId}/{keyName}`](/client-server-api/#put_matrixclientv3profileuseridkeyname).
If absent, clients should assume custom profile fields are supported, provided the
response from [`/versions`](/client-server-api/#get_matrixclientversions) indicates
support for a sufficiently recent spec version.
properties:
allowed:
type: array
description: List of allowed additional custom profile field keys. A `*` can be used as a
wildcard to match any sequence of characters. This list takes precedence over the
disallowed list if both are provided.
items:
type: string
example:
- "m.example_field"
- "org.example/job_title"
disallowed:
type: array
description: List of disallowed additional custom profile field keys. A `*` can be used as
a wildcard to match any sequence of characters. Ignored if an allowed list is provided.
items:
type: string
example:
- "org.example.secret_field"
enabled:
type: boolean
description: `true` if the user can set or modify any extended profile fields, `false` otherwise.
example: true
required:
- enabled
examples:
response:
value: {

View file

@ -16,48 +16,105 @@ info:
title: Matrix Client-Server Profile API
version: 1.0.0
paths:
"/profile/{userId}/displayname":
"/profile/{userId}/{keyName}":
put:
summary: Set the user's display name.
x-changedInMatrixVersion:
"1.14": Endpoint now accepts variable `keyName` parameter.
summary: Set a profile field for a user.
description: |-
This API sets the given user's display name. You must have permission to
set this user's display name, e.g. you need to have their `access_token`.
operationId: setDisplayName
Set or update a profile field for a user. Must be authenticated with an
access token authorised to make changes. Servers MAY impose size limits
on individual fields, and the total profile MUST be under 64 KiB.
**Note**: Setting a field to `null` keeps the key but with a `null` value,
which some servers may reject. To remove a field completely, use the
`DELETE` endpoint instead.
operationId: setProfileField
security:
- accessTokenQuery: []
- accessTokenBearer: []
parameters:
- in: path
name: userId
description: The user whose display name to set.
description: The user whose profile field should be set.
required: true
example: "@alice:example.com"
schema:
type: string
- in: path
name: keyName
description: The profile field key name to set. It must be either
`avatar_url`, `displayname`, or a custom field following the
[Common Namespaced Identifier Grammar](/appendices/#common-namespaced-identifier-grammar).
required: true
example: "displayname"
schema:
type: string
pattern: '^(avatar_url|displayname|[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)+)$'
requestBody:
description: A JSON object containing the property whose name matches
the `keyName` specified in the URL. See `additionalProperties` for
further details.
required: true
content:
application/json:
schema:
type: object
example: {
"displayname": "Alice Margatroid"
}
properties:
displayname:
type: string
description: The new display name for this user.
description: The new display name information.
required: true
minProperties: 1
additionalProperties:
description: The JSON object must include a property whose key
matches the `keyName` specified in the URL. For `avatar_url`,
the value must be an MXC URI string. For `displayname`, the value
must be a string. For custom keys, any JSON type is allowed -
servers may not validate these values, but clients should follow
the format defined for that key.
example: { "displayname": "Alice Wonderland" }
responses:
"200":
description: The display name was set.
description: The profile field was set.
content:
application/json:
schema:
type: object # empty json object
type: object # empty JSON object
examples:
response:
value: {}
"400":
description: The request is malformed, contains invalid JSON, missing
a required parameter, specifies an invalid key, or exceeds allowed
size limits.
content:
application/json:
schema:
$ref: definitions/errors/error.yaml
examples:
bad_json:
value:
{
"errcode": "M_BAD_JSON",
"error": "Malformed JSON payload.",
}
invalid_key:
value:
{
"errcode": "M_INVALID_PARAM",
"error": "Invalid profile key.",
}
"403":
description: The server is unwilling to perform the operation, either
due to insufficient permissions or because profile modifications
are disabled.
content:
application/json:
schema:
$ref: definitions/errors/error.yaml
examples:
forbidden:
value:
{
"errcode": "M_FORBIDDEN",
"error": "Profile modification is not permitted.",
}
"429":
description: This request was rate-limited.
content:
@ -67,98 +124,133 @@ paths:
tags:
- User data
get:
summary: Get the user's display name.
description: |-
Get the user's display name. This API may be used to fetch the user's
own displayname or to query the name of other users; either locally or
on remote homeservers.
operationId: getDisplayName
x-changedInMatrixVersion:
"1.14": Endpoint now accepts variable `keyName` parameter.
summary: Get a profile field for a user.
description: Get the value of a profile field for a user. Any individual
field must be within the total profile limit of 64 KiB.
operationId: getProfileField
parameters:
- in: path
name: userId
description: The user whose display name to get.
description: The user whose profile field should be returned.
required: true
example: "@alice:example.com"
schema:
type: string
- in: path
name: keyName
description: The profile field key name to retrieve. It must be either
`avatar_url`, `displayname`, or a custom field following the
[Common Namespaced Identifier Grammar](/appendices/#common-namespaced-identifier-grammar).
required: true
example: "displayname"
schema:
type: string
pattern: '^(avatar_url|displayname|[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)+)$'
responses:
"200":
description: The display name for this user.
description: The profile field value was retrieved.
content:
application/json:
schema:
type: object
properties:
displayname:
type: string
description: The user's display name if they have set one, otherwise not
present.
minProperties: 1
additionalProperties:
description: The JSON response includes a property whose key
matches the `keyName` specified in the URL. For `avatar_url`,
the value will be an MXC URI string. For `displayname`, the
value will be a string. For custom keys, any JSON type is
possible - clients should expect the format defined for that key.
examples:
response:
value: {
"displayname": "Alice Margatroid"
}
value: { "displayname": "Alice" }
"403":
x-addedInMatrixVersion: "1.12"
description: The server is unwilling to disclose whether the user exists and/or
has a display name.
description: The server is unwilling to disclose whether the user
exists and/or has the specified profile field.
content:
application/json:
schema:
$ref: definitions/errors/error.yaml
examples:
response:
value: {
"errcode": "M_FORBIDDEN",
"error": "Profile lookup is disabled on this homeserver"
}
value:
{
"errcode": "M_FORBIDDEN",
"error": "Profile lookup is disabled on this homeserver",
}
"404":
description: There is no display name for this user or this user does not exist.
description: There is no profile field with this key for this user, or
the user does not exist.
tags:
- User data
"/profile/{userId}/avatar_url":
put:
summary: Set the user's avatar URL.
description: |-
This API sets the given user's avatar URL. You must have permission to
set this user's avatar URL, e.g. you need to have their `access_token`.
operationId: setAvatarUrl
delete:
x-addedInMatrixVersion: "1.14"
summary: Remove a profile field from a user.
description: Remove a specific field from a user's profile.
operationId: deleteProfileField
security:
- accessTokenQuery: []
- accessTokenBearer: []
parameters:
- in: path
name: userId
description: The user whose avatar URL to set.
description: The user whose profile field should be deleted.
required: true
example: "@alice:example.com"
schema:
type: string
requestBody:
content:
application/json:
schema:
type: object
example: {
"avatar_url": "mxc://matrix.org/wefh34uihSDRGhw34"
}
properties:
avatar_url:
type: string
format: uri
description: The new avatar URL for this user.
description: The new avatar information.
required: true
- in: path
name: keyName
description: The key name of the profile field to delete. It must be either
`avatar_url`, `displayname`, or a custom field following the
[Common Namespaced Identifier Grammar](/appendices/#common-namespaced-identifier-grammar).
required: true
example: "displayname"
schema:
type: string
pattern: '^(avatar_url|displayname|[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)+)$'
responses:
"200":
description: The avatar URL was set.
description: The profile field was deleted.
content:
application/json:
schema:
type: object # empty json object
type: object
examples:
response:
value: {}
"400":
description: The request is malformed, contains invalid JSON, or
specifies an invalid key.
content:
application/json:
schema:
$ref: definitions/errors/error.yaml
examples:
bad_json:
value:
{ "errcode": "M_BAD_JSON", "error": "Malformed request." }
invalid_key:
value:
{
"errcode": "M_INVALID_PARAM",
"error": "Invalid profile key.",
}
"403":
description: The user is not authorised to delete this profile field.
content:
application/json:
schema:
$ref: definitions/errors/error.yaml
examples:
forbidden:
value:
{
"errcode": "M_FORBIDDEN",
"error": "Profile deletion is not permitted.",
}
"429":
description: This request was rate-limited.
content:
@ -167,63 +259,15 @@ paths:
$ref: definitions/errors/rate_limited.yaml
tags:
- User data
get:
summary: Get the user's avatar URL.
description: |-
Get the user's avatar URL. This API may be used to fetch the user's
own avatar URL or to query the URL of other users; either locally or
on remote homeservers.
operationId: getAvatarUrl
parameters:
- in: path
name: userId
description: The user whose avatar URL to get.
required: true
example: "@alice:example.com"
schema:
type: string
responses:
"200":
description: The avatar URL for this user.
content:
application/json:
schema:
type: object
properties:
avatar_url:
type: string
format: uri
description: The user's avatar URL if they have set one, otherwise not present.
examples:
response:
value: {
"avatar_url": "mxc://matrix.org/SDGdghriugerRg"
}
"403":
x-addedInMatrixVersion: "1.12"
description: The server is unwilling to disclose whether the user exists and/or
has an avatar URL.
content:
application/json:
schema:
$ref: definitions/errors/error.yaml
examples:
response:
value: {
"errcode": "M_FORBIDDEN",
"error": "Profile lookup is disabled on this homeserver"
}
"404":
description: There is no avatar URL for this user or this user does not exist.
tags:
- User data
"/profile/{userId}":
get:
summary: Get this user's profile information.
summary: Get all profile information for a user.
description: |-
Get the combined profile information for this user. This API may be used
to fetch the user's own profile information or other users; either
locally or on remote homeservers.
Get the complete profile for a user. The response includes `avatar_url`
and `displayname` (unless set to `null`, as they can only be strings)
plus any custom profile fields.
**Note**: The complete profile must be under 64 KiB.
operationId: getUserProfile
parameters:
- in: path
@ -243,45 +287,49 @@ paths:
properties:
avatar_url:
type: string
format: uri
description: The user's avatar URL if they have set one, otherwise not present.
format: mx-mxc-uri
description: "Avatar URL value (MXC URI format)."
displayname:
type: string
description: The user's display name if they have set one, otherwise not
present.
additionalProperties:
x-addedInMatrixVersion: "1.14"
description: Any additional profile field value; may be any
valid JSON type, with keys following the
[Common Namespaced Identifier Grammar](/appendices/#common-namespaced-identifier-grammar).
examples:
response:
value: {
"avatar_url": "mxc://matrix.org/SDGdghriugerRg",
"displayname": "Alice Margatroid"
}
value:
{
"avatar_url": "mxc://matrix.org/SDGdghriugerRg",
"displayname": "Alice Margatroid",
"m.example_field": "custom_value",
}
"403":
x-addedInMatrixVersion: "1.2"
description: The server is unwilling to disclose whether the user exists and/or
has profile information.
description: The server is unwilling to disclose whether the user
exists and/or has profile information.
content:
application/json:
schema:
$ref: definitions/errors/error.yaml
examples:
response:
value: {
"errcode": "M_FORBIDDEN",
"error": "Profile lookup is disabled on this homeserver"
}
value:
{
"errcode": "M_FORBIDDEN",
"error": "Profile lookup is disabled on this homeserver",
}
"404":
description: There is no profile information for this user or this user does not
exist.
description: There is no profile information for this user or this
user does not exist.
content:
application/json:
schema:
$ref: definitions/errors/error.yaml
examples:
response:
value: {
"errcode": "M_NOT_FOUND",
"error": "Profile not found"
}
value:
{ "errcode": "M_NOT_FOUND", "error": "Profile not found" }
tags:
- User data
servers: