Compare commits

...

9 commits

Author SHA1 Message Date
Kévin Commaille 1c5eeab77e
Merge e9526c7564 into 979264e923 2025-06-17 18:43:42 +01:00
Richard van der Hoff 979264e923
Fix example for ExportedSessionData (#2154)
Some checks are pending
Spec / 🔎 Validate OpenAPI specifications (push) Waiting to run
Spec / 🔎 Check Event schema examples (push) Waiting to run
Spec / 🔎 Check OpenAPI definitions examples (push) Waiting to run
Spec / 🔎 Check JSON Schemas inline examples (push) Waiting to run
Spec / ⚙️ Calculate baseURL for later jobs (push) Waiting to run
Spec / 🐍 Build OpenAPI definitions (push) Blocked by required conditions
Spec / 📢 Run towncrier for changelog (push) Waiting to run
Spec / 📖 Build the spec (push) Blocked by required conditions
Spec / 🔎 Validate generated HTML (push) Blocked by required conditions
Spec / 📖 Build the historical backup spec (push) Blocked by required conditions
Spell Check / Spell Check with Typos (push) Waiting to run
Currently, the example for `ExportedSessionData` is missing values for
`room_id` and `session_id`.

Move the example field values for `KeyBackupSessionData` into the field
definitions, so that an example for the object as a whole is built
automatically, and when we extend it to form `ExportedSessionData` the
explicit example does not override the more complete autogenerated one.
2025-06-17 18:43:40 +01:00
Richard van der Hoff e9526c7564
Merge branch 'main' into oauth2-grant-types 2025-06-17 18:19:44 +01:00
Kévin Commaille 51ccbbd240
Add the OAuth 2.0 server metadata discovery endpoint (#2147)
As per MSC2965.
2025-06-17 17:47:30 +01:00
Kévin Commaille 1c32e21b69
Move up login and token refresh flows in hierarchy
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2025-06-16 12:27:29 +02:00
Kévin Commaille e8c2f9a2a2
Apply text suggestions
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2025-06-16 12:15:34 +02:00
Kévin Commaille a2a9a02efa
Add OAuth 2.0 scopes (#2149)
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
As per MSC2967

Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2025-06-11 09:40:17 +01:00
Kévin Commaille 0c50195a32
Add changelog
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2025-06-03 20:13:39 +02:00
Kévin Commaille 101d0fe34f
Add OAuth 2.0 authorization code and refresh token grant types
As per MSC2964

Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2025-06-03 20:13:39 +02:00
7 changed files with 524 additions and 11 deletions

View file

@ -0,0 +1 @@
Add `GET /_matrix/client/v1/auth_metadata`, as per [MSC2965](https://github.com/matrix-org/matrix-spec-proposals/pull/2965).

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 missing fields in example for `ExportedSessionData`.

View file

@ -1481,6 +1481,345 @@ MAY reject weak passwords with an error code `M_WEAK_PASSWORD`.
### OAuth 2.0 API
#### Server metadata discovery
{{% http-api spec="client-server" api="oauth_server_metadata" %}}
#### Scope
The client requests a scope in the OAuth 2.0 authorization flow, which is then
associated to the generated access and refresh tokens. This provides a framework
for obtaining user consent.
A scope is defined in [RFC 6749 section 3.3](https://datatracker.ietf.org/doc/html/rfc6749#section-3.3)
as a string containing a list of space-separated scope tokens.
{{% boxes/note %}}
The framework encourages the practice of obtaining additional user consent when
a client asks for a new scope that was not granted previously. This could be
used by future MSCs to replace the legacy [User-Interactive Authentication API](#user-interactive-authentication-api).
{{% /boxes/note %}}
##### Scope token format
All scope tokens related to Matrix should start with `urn:matrix:` and use the
`:` delimiter for further sub-division.
Scope tokens related to mapping of Client-Server API access levels should start
with `urn:matrix:client:`.
{{% boxes/note %}}
For MSCs that build on this namespace, unstable subdivisions should be used
whilst in development. For example, if MSCXXXX wants to introduce the
`urn:matrix:client:foo` scope, it could use
`urn:matrix:client:com.example.mscXXXX.foo` during development.
If it needs to introduce multiple scopes, like `urn:matrix:client:foo` and
`urn:matrix:client:bar`, it could use
`urn:matrix:client:com.example.mscXXXX:foo` and
`urn:matrix:client:com.example.mscXXXX:bar`.
{{% /boxes/note %}}
##### Allocated scope tokens
This specification defines the following scope tokens:
- [`urn:matrix:client:api:*`](#full-client-server-api-readwrite-access)
- [`urn:matrix:client:device:<device_id>`](#device-id-allocation)
###### Full client-server API read/write access
| Scope | Purpose |
|---------------------------|---------------------------------------------|
| `urn:matrix:client:api:*` | Grants full access to the Client-Server API. |
{{% boxes/note %}}
This token matches the behavior of the legacy authentication API. Future MSCs
could introduce more fine-grained scope tokens like
`urn:matrix:client:api:read:*` for read-only access.
{{% /boxes/note %}}
###### Device ID allocation
| Scope | Purpose |
|----------------------------------------|----------------------------------------------------------------------------------------------|
| `urn:matrix:client:device:<device_id>` | Allocates the given `device_id` and associates it to the generated access and refresh tokens. |
Contrary to the legacy login and registration APIs where the homeserver is
typically the one generating a `device_id` and providing it to the client, with
the OAuth 2.0 API, the client is responsible for allocating the `device_id`.
There MUST be exactly one `urn:matrix:client:device:<device_id>` token in the
requested scope in the login flow.
When generating a new `device_id`, the client SHOULD generate a random string
with enough entropy. It SHOULD only use characters from the unreserved character
list defined by [RFC 3986 section 2.3](https://datatracker.ietf.org/doc/html/rfc3986#section-2.3):
```
unreserved = a-z / A-Z / 0-9 / "-" / "." / "_" / "~"
```
Using this alphabet, a 10 character string is enough to stand a sufficient
chance of being unique per user. The homeserver MAY reject a request for a
`device_id` that is not long enough or contains characters outside the
unreserved list.
In any case it MUST only use characters allowed by the OAuth 2.0 scope
definition in [RFC 6749 section 3.3](https://datatracker.ietf.org/doc/html/rfc6749#section-3.3),
which is defined as the following ASCII ranges:
```
%x21 / %x23-5B / %x5D-7E
```
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:
- `token_endpoint`
- `grant_types_supported`
The client must also have obtained a `client_id` by registering with the server.
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:
- `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, 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.
#### 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.
First, the client needs to generate the following values:
- `device_id`: a unique identifier for this device; see the
[`urn:matrix:client:device:<device_id>`] scope.
- `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.
### Account moderation
#### Account locking

View file

@ -23,6 +23,7 @@ properties:
type: string
description: |-
The end-to-end message encryption algorithm that the key is for. Must be `m.megolm.v1.aes-sha2`.
example: "m.megolm.v1.aes-sha2"
forwarding_curve25519_key_chain:
type: array
items:
@ -30,31 +31,24 @@ properties:
description: |-
Chain of Curve25519 keys through which this session was forwarded, via [m.forwarded_room_key](/client-server-api/#mforwarded_room_key)
events.
example: [ "hPQNcabIABgGnx3/ACv/jmMmiQHoeFfuLB17tzWp6Hw" ]
sender_key:
type: string
description: |-
Unpadded base64-encoded device Curve25519 key.
example: "RF3s+E7RkTQTGF2d8Deol0FkQvgII2aJDf3/Jp5mxVU"
sender_claimed_keys:
type: object
additionalProperties:
type: string
description: |-
A map from algorithm name (`ed25519`) to the Ed25519 signing key of the sending device.
example: { "ed25519": "aj40p+aw64yPIdsxoog8jhPu9i7l7NcFRecuOQblE3Y" }
session_key:
type: string
description: |-
Unpadded base64-encoded session key in [session-export format](https://gitlab.matrix.org/matrix-org/olm/blob/master/docs/megolm.md#session-export-format).
example: {
"algorithm": "m.megolm.v1.aes-sha2",
"forwarding_curve25519_key_chain": [
"hPQNcabIABgGnx3/ACv/jmMmiQHoeFfuLB17tzWp6Hw"
],
"sender_key": "RF3s+E7RkTQTGF2d8Deol0FkQvgII2aJDf3/Jp5mxVU",
"sender_claimed_keys": {
"ed25519": "aj40p+aw64yPIdsxoog8jhPu9i7l7NcFRecuOQblE3Y",
},
"session_key": "AgAAAADxKHa9uFxcXzwYoNueL5Xqi69IkD4sni8Llf..."
}
example: "AgAAAADxKHa9uFxcXzwYoNueL5Xqi69IkD4sni8Llf..."
required:
- algorithm
- forwarding_curve25519_key_chain

View file

@ -0,0 +1,176 @@
# Copyright 2025 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.
openapi: 3.1.0
info:
title: Matrix Client-Server OAuth 2.0 Server Metadata Discovery API
version: 1.0.0
paths:
"/auth_metadata":
get:
summary: Get the OAuth 2.0 authorization server metadata.
description: |-
Gets the OAuth 2.0 authorization server metadata, as defined in
[RFC 8414](https://datatracker.ietf.org/doc/html/rfc8414), including the
endpoint URLs and the supported parameters that can be used by the
clients.
This endpoint definition includes only the fields that are meaningful in
the context of the Matrix specification. The full list of possible
fields is available in the [OAuth Authorization Server Metadata
registry](https://www.iana.org/assignments/oauth-parameters/oauth-parameters.xhtml#authorization-server-metadata),
and normative definitions of them are available in their respective
RFCs.
{{% boxes/note %}}
The authorization server metadata is relatively large and may change
over time. Clients should:
- Cache the metadata appropriately based on HTTP caching headers
- Refetch the metadata if it is stale
{{% /boxes/note %}}
operationId: getAuthMetadata
responses:
"200":
description: The OAuth 2.0 authorization server metadata.
content:
application/json:
schema:
type: object
properties:
issuer:
type: string
format: uri
description: |-
The authorization server's issuer identifier, which is a URL that uses the
`https` scheme and has no query or fragment components.
This is not used in the context of the Matrix specification, but is required
by [RFC 8414](https://datatracker.ietf.org/doc/html/rfc8414).
authorization_endpoint:
type: string
format: uri
description: |-
URL of the authorization endpoint, necessary to use the authorization code
grant.
token_endpoint:
type: string
format: uri
description: |-
URL of the token endpoint, necessary to use the authorization code grant and
the refresh token grant.
revocation_endpoint:
type: string
format: uri
description: |-
URL of the revocation endpoint, necessary to log out a client by invalidating
its access and refresh tokens.
registration_endpoint:
type: string
format: uri
description: |-
URL of the client registration endpoint, necessary to perform dynamic
registration of a client.
response_types_supported:
type: array
description: |-
List of OAuth 2.0 response type strings that the server supports at the
authorization endpoint.
This array MUST contain at least the `code` value, for clients to be able to
use the authorization code grant.
items:
type: string
description: A response type that the server supports.
grant_types_supported:
type: array
description: |-
List of OAuth 2.0 grant type strings that the server supports at the token
endpoint.
This array MUST contain at least the `authorization_code` and `refresh_token`
values, for clients to be able to use the authorization code grant and refresh
token grant, respectively.
items:
type: string
description: A grant type that the server supports.
response_modes_supported:
type: array
description: |-
List of OAuth 2.0 response mode strings that the server supports at the
authorization endpoint.
This array MUST contain at least the `query` and `fragment` values, for
improved security in the authorization code grant.
items:
type: string
description: A response mode that the server supports.
code_challenge_methods_supported:
type: array
description: |-
List of OAuth 2.0 Proof Key for Code Exchange (PKCE) code challenge methods
that the server supports at the authorization endpoint.
This array MUST contain at least the `S256` value, for improved security in
the authorization code grant.
items:
type: string
description: A PKCE code challenge method that the server supports.
prompt_values_supported:
type: array
description: |-
List of OpenID Connect prompt values that the server supports at the
authorization endpoint.
Only the `create` value defined in [Initiating User Registration via OpenID
Connect](https://openid.net/specs/openid-connect-prompt-create-1_0.html) is
supported, for a client to signal to the server that the user desires to
register a new account.
items:
type: string
description: A prompt value that the server supports.
required:
- issuer
- authorization_endpoint
- token_endpoint
- revocation_endpoint
- registration_endpoint
- response_types_supported
- grant_types_supported
- response_modes_supported
- code_challenge_methods_supported
example: {
"issuer": "https://account.example.com/",
"authorization_endpoint": "https://account.example.com/oauth2/auth",
"token_endpoint": "https://account.example.com/oauth2/token",
"registration_endpoint": "https://account.example.com/oauth2/clients/register",
"revocation_endpoint": "https://account.example.com/oauth2/revoke",
"response_types_supported": ["code"],
"grant_types_supported": ["authorization_code", "refresh_token"],
"response_modes_supported": ["query", "fragment"],
"code_challenge_methods_supported": ["S256"],
}
tags:
- Session management
servers:
- url: "{protocol}://{hostname}{basePath}"
variables:
protocol:
enum:
- http
- https
default: https
hostname:
default: localhost:8008
basePath:
default: /_matrix/client/v1