From 22bfe79ea6a3328e5ba66c9830c5d0a6b1062d40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Commaille?= Date: Sun, 8 Jun 2025 10:48:57 +0200 Subject: [PATCH 1/7] Add introduction to OAuth 2.0 API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Kévin Commaille --- content/client-server-api/_index.md | 37 +++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/content/client-server-api/_index.md b/content/client-server-api/_index.md index b478a0c99..bca98b7a6 100644 --- a/content/client-server-api/_index.md +++ b/content/client-server-api/_index.md @@ -1481,6 +1481,43 @@ 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. + +Homeservers may provide alternatives to those endpoints in their web UI (like +[MSC4191](https://github.com/matrix-org/matrix-spec-proposals/pull/4191) for +account management), or disable UIA in certain circumstances (like +[MSC4190](https://github.com/matrix-org/matrix-spec-proposals/pull/4190) for +managing devices for application services). +{{% /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 by authorizing a [scope](#scope) for the client with the [authorization code grant](#authorization-code-grant). +4. Refresh the access token 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. + ### Account moderation #### Account locking From 3971252184dea66f561d4b364ecf369213580cb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Commaille?= Date: Sun, 8 Jun 2025 11:09:51 +0200 Subject: [PATCH 2/7] Add introduction for the legacy API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Kévin Commaille --- content/client-server-api/_index.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/content/client-server-api/_index.md b/content/client-server-api/_index.md index bca98b7a6..92e59e47c 100644 --- a/content/client-server-api/_index.md +++ b/content/client-server-api/_index.md @@ -562,6 +562,14 @@ the account has been [unlocked](#account-locking). ### Legacy API +{{% changed-in v="1.15" %}} + +This is the first authentication API that was introduced since 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 might not require the end user to be redirected to a web UI in their +browser. + #### User-Interactive Authentication API ##### Overview From d40d781cfdddb0f4ea6f6a2d63a2c4edaa27dc0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Commaille?= Date: Sun, 8 Jun 2025 13:01:44 +0200 Subject: [PATCH 3/7] Clarify differences between both authentication APIs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Kévin Commaille --- content/client-server-api/_index.md | 126 +++++++++++++++++++++++----- 1 file changed, 106 insertions(+), 20 deletions(-) diff --git a/content/client-server-api/_index.md b/content/client-server-api/_index.md index 92e59e47c..983ff961f 100644 --- a/content/client-server-api/_index.md +++ b/content/client-server-api/_index.md @@ -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 passed 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" %}} + 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,68 @@ 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. Both APIs are +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, +like ones that don't rely on a web browser for automation or for endpoints used +by application services that depend on the [UIA API](#user-interactive-authentication-api). +{{% /boxes/note %}} + +{{% boxes/note %}} +[MSC3824](https://github.com/matrix-org/matrix-spec-proposals/pull/3824) +specifies a way for servers to implement the OAuth 2.0 API while staying +backwards-compatible with existing clients by using the [`m.login.sso`](#sso-client-loginauthentication) +method, and for clients to improve their compatibility with the OAuth 2.0 API +with minimal changes. +{{% /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). 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 +557,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 access token should be associated to 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 +573,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 +592,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 +602,10 @@ 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-type). 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,6 +629,23 @@ 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. + +{{% boxes/note %}} +[MSC4191](https://github.com/matrix-org/matrix-spec-proposals/pull/4191) +provides a way for homeservers to provide the URL of their account management UI, +which can be used by clients to redirect the users to the relevant part of the +interface depending on the action that the user wishes to take. +{{% /boxes/note %}} + ### Legacy API {{% changed-in v="1.15" %}} @@ -1337,7 +1423,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. @@ -1466,11 +1552,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 From 1e75a97e737aa21f27290db3d67f5c2e1158b187 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Commaille?= Date: Sun, 8 Jun 2025 13:09:59 +0200 Subject: [PATCH 4/7] Add changelog MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Kévin Commaille --- changelogs/client_server/newsfragments/2159.feature | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelogs/client_server/newsfragments/2159.feature diff --git a/changelogs/client_server/newsfragments/2159.feature b/changelogs/client_server/newsfragments/2159.feature new file mode 100644 index 000000000..6eff5607c --- /dev/null +++ b/changelogs/client_server/newsfragments/2159.feature @@ -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. From ed1b3d7d57faa0ea5b25fcdac262aafccf73b1d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Commaille?= Date: Wed, 18 Jun 2025 12:06:00 +0200 Subject: [PATCH 5/7] Apply review suggestions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Kévin Commaille --- content/client-server-api/_index.md | 56 +++++++++-------------------- 1 file changed, 17 insertions(+), 39 deletions(-) diff --git a/content/client-server-api/_index.md b/content/client-server-api/_index.md index a36bd0518..29731d276 100644 --- a/content/client-server-api/_index.md +++ b/content/client-server-api/_index.md @@ -292,7 +292,7 @@ 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 during the [login](#login) process). On the other hand, if +`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 @@ -435,7 +435,7 @@ endpoints it supports. ## Client Authentication -{{% changed-in v="1.15" %}} +{{% 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. @@ -461,9 +461,9 @@ 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. Both APIs are -incompatible, which means that after logging in, clients MUST only use the API -that was used to obtain their current access token. +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, @@ -471,14 +471,6 @@ like ones that don't rely on a web browser for automation or for endpoints used by application services that depend on the [UIA API](#user-interactive-authentication-api). {{% /boxes/note %}} -{{% boxes/note %}} -[MSC3824](https://github.com/matrix-org/matrix-spec-proposals/pull/3824) -specifies a way for servers to implement the OAuth 2.0 API while staying -backwards-compatible with existing clients by using the [`m.login.sso`](#sso-client-loginauthentication) -method, and for clients to improve their compatibility with the OAuth 2.0 API -with minimal changes. -{{% /boxes/note %}} - ### Authentication API discovery To discover if a homeserver supports the legacy API, the [`GET /login`](#get_matrixclientv3login) @@ -509,8 +501,8 @@ 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). To invalidate the access token the client must use -[token revocation](#token-revocation). +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 @@ -557,8 +549,8 @@ 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. -During login or registration, the access token should be associated to a -`device_id`. The legacy [Login](#legacy-login) and [Registration](#legacy-account-registration) +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 @@ -603,8 +595,9 @@ 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-type). Support for refreshing access tokens is -mandatory with this API. +grant type](#refresh-token-grant-type), as demonstrated in the [token refresh +flow](#token-refresh-flow). Support for refreshing access tokens is mandatory +with this API. ### Soft logout @@ -639,22 +632,13 @@ manage their account like [changing their password](#password-management), With the OAuth 2.0 API, all account management is done via the homeserver's web UI. -{{% boxes/note %}} -[MSC4191](https://github.com/matrix-org/matrix-spec-proposals/pull/4191) -provides a way for homeservers to provide the URL of their account management UI, -which can be used by clients to redirect the users to the relevant part of the -interface depending on the action that the user wishes to take. -{{% /boxes/note %}} - ### Legacy API -{{% changed-in v="1.15" %}} - -This is the first authentication API that was introduced since the first version +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 might not require the end user to be redirected to a web UI in their -browser. +such it does not usually require the end user to be redirected to a web UI in +their browser. #### User-Interactive Authentication API @@ -1596,20 +1580,14 @@ because they don't have access to the user's credentials anymore. 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. - -Homeservers may provide alternatives to those endpoints in their web UI (like -[MSC4191](https://github.com/matrix-org/matrix-spec-proposals/pull/4191) for -account management), or disable UIA in certain circumstances (like -[MSC4190](https://github.com/matrix-org/matrix-spec-proposals/pull/4190) for -managing devices for application services). {{% /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 by authorizing a [scope](#scope) for the client with the [authorization code grant](#authorization-code-grant). -4. Refresh the access token with the [refresh token grant](#refresh-token-grant) when it expires. +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. #### Server metadata discovery From bfc06034bd9361d60d72adb449d99d1b79b55aae Mon Sep 17 00:00:00 2001 From: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> Date: Fri, 20 Jun 2025 11:52:44 +0100 Subject: [PATCH 6/7] Update content/client-server-api/_index.md --- content/client-server-api/_index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/client-server-api/_index.md b/content/client-server-api/_index.md index ee9dd66ae..ea2708b11 100644 --- a/content/client-server-api/_index.md +++ b/content/client-server-api/_index.md @@ -595,7 +595,7 @@ 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-type), as demonstrated in the [token refresh +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. From 2260c89af4c2585bc726de291722085ed75f09d1 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> Date: Fri, 20 Jun 2025 15:48:53 +0100 Subject: [PATCH 7/7] Update content/client-server-api/_index.md --- content/client-server-api/_index.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/content/client-server-api/_index.md b/content/client-server-api/_index.md index ea2708b11..fbf678a6a 100644 --- a/content/client-server-api/_index.md +++ b/content/client-server-api/_index.md @@ -467,8 +467,8 @@ 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, -like ones that don't rely on a web browser for automation or for endpoints used -by application services that depend on the [UIA API](#user-interactive-authentication-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