Merge remote-tracking branch 'origin/main' into quenting/stable-api

This commit is contained in:
Quentin Gliech
2025-08-04 16:38:49 +02:00
818 changed files with 9884 additions and 5291 deletions

View File

@@ -1345,7 +1345,7 @@
"user"
],
"summary": "Deactivate a user",
"description": "Calling this endpoint will lock and deactivate the user, preventing them from doing any action.\nThis invalidates any existing session, and will ask the homeserver to make them leave all rooms.",
"description": "Calling this endpoint will deactivate the user, preventing them from doing any action.\nThis invalidates any existing session, and will ask the homeserver to make them leave all rooms.",
"operationId": "deactivateUser",
"parameters": [
{
@@ -1359,6 +1359,15 @@
"style": "simple"
}
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/DeactivateUserRequest"
}
}
}
},
"responses": {
"200": {
"description": "User was deactivated",
@@ -1409,6 +1418,76 @@
}
}
},
"/api/admin/v1/users/{id}/reactivate": {
"post": {
"tags": [
"user"
],
"summary": "Reactivate a user",
"description": "Calling this endpoint will reactivate a deactivated user.\nThis DOES NOT unlock a locked user, which is still prevented from doing any action until it is explicitly unlocked.",
"operationId": "reactivateUser",
"parameters": [
{
"in": "path",
"name": "id",
"required": true,
"schema": {
"title": "The ID of the resource",
"$ref": "#/components/schemas/ULID"
},
"style": "simple"
}
],
"responses": {
"200": {
"description": "User was reactivated",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SingleResponse_for_User"
},
"example": {
"data": {
"type": "user",
"id": "01040G2081040G2081040G2081",
"attributes": {
"username": "alice",
"created_at": "1970-01-01T00:00:00Z",
"locked_at": null,
"deactivated_at": null,
"admin": false
},
"links": {
"self": "/api/admin/v1/users/01040G2081040G2081040G2081"
}
},
"links": {
"self": "/api/admin/v1/users/01040G2081040G2081040G2081/reactivate"
}
}
}
}
},
"404": {
"description": "User ID not found",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
},
"example": {
"errors": [
{
"title": "User ID 00000000000000000000000000 not found"
}
]
}
}
}
}
}
}
},
"/api/admin/v1/users/{id}/lock": {
"post": {
"tags": [
@@ -1485,6 +1564,7 @@
"user"
],
"summary": "Unlock a user",
"description": "Calling this endpoint will lift restrictions on user actions that had imposed by locking.\nThis DOES NOT reactivate a deactivated user, which will remain unavailable until it is explicitly reactivated.",
"operationId": "unlockUser",
"parameters": [
{
@@ -3872,6 +3952,17 @@
}
}
},
"DeactivateUserRequest": {
"title": "JSON payload for the `POST /api/admin/v1/users/:id/deactivate` endpoint",
"type": "object",
"properties": {
"skip_erase": {
"description": "Whether to skip requesting the homeserver to GDPR-erase the user upon deactivation.",
"default": false,
"type": "boolean"
}
}
},
"UserEmailFilter": {
"type": "object",
"properties": {

View File

@@ -1707,18 +1707,32 @@
"description": "The kind of homeserver it is.",
"oneOf": [
{
"description": "Homeserver is Synapse",
"description": "Homeserver is Synapse, using the legacy API\n\nThis will switch to using the modern API in a few releases.",
"type": "string",
"enum": [
"synapse"
]
},
{
"description": "Homeserver is Synapse, in read-only mode\n\nThis is meant for testing rolling out Matrix Authentication Service with no risk of writing data to the homeserver.",
"description": "Homeserver is Synapse, using the legacy API, in read-only mode\n\nThis is meant for testing rolling out Matrix Authentication Service with no risk of writing data to the homeserver.\n\nThis will switch to using the modern API in a few releases.",
"type": "string",
"enum": [
"synapse_read_only"
]
},
{
"description": "Homeserver is Synapse, using the legacy API,",
"type": "string",
"enum": [
"synapse_legacy"
]
},
{
"description": "Homeserver is Synapse, with the modern API available",
"type": "string",
"enum": [
"synapse_modern"
]
}
]
},
@@ -2136,6 +2150,14 @@
"description": "Whether the `login_hint` should be forwarded to the provider in the authorization request.\n\nDefaults to `false`.",
"default": false,
"type": "boolean"
},
"on_backchannel_logout": {
"description": "What to do when receiving an OIDC Backchannel logout request.\n\nDefaults to \"do_nothing\".",
"allOf": [
{
"$ref": "#/definitions/OnBackchannelLogout"
}
]
}
}
},
@@ -2353,6 +2375,14 @@
"template": {
"description": "The Jinja2 template to use for the localpart attribute\n\nIf not provided, the default template is `{{ user.preferred_username }}`",
"type": "string"
},
"on_conflict": {
"description": "How to handle conflicts on the claim, default value is `Fail`",
"allOf": [
{
"$ref": "#/definitions/OnConflict"
}
]
}
}
},
@@ -2389,6 +2419,25 @@
}
]
},
"OnConflict": {
"description": "How to handle an existing localpart claim",
"oneOf": [
{
"description": "Fails the sso login on conflict",
"type": "string",
"enum": [
"fail"
]
},
{
"description": "Adds the oauth identity link, regardless of whether there is an existing link or not",
"type": "string",
"enum": [
"add"
]
}
]
},
"DisplaynameImportPreference": {
"description": "What should be done for the displayname attribute",
"type": "object",
@@ -2435,6 +2484,32 @@
}
}
},
"OnBackchannelLogout": {
"description": "What to do when receiving an OIDC Backchannel logout request.",
"oneOf": [
{
"description": "Do nothing",
"type": "string",
"enum": [
"do_nothing"
]
},
{
"description": "Only log out the MAS 'browser session' started by this OIDC session",
"type": "string",
"enum": [
"logout_browser_only"
]
},
{
"description": "Log out all sessions started by this OIDC session, including MAS 'browser sessions' and client sessions",
"type": "string",
"enum": [
"logout_all"
]
}
]
},
"BrandingConfig": {
"description": "Configuration section for tweaking the branding of the service",
"type": "object",

View File

@@ -4,7 +4,7 @@ This document aims to get you started with contributing to the Matrix Authentica
## 1. Who can contribute to MAS?
Everyone is welcome to contribute code to [Synapse](https://github.com/element-hq/matrix-authentication-service), provided that they are willing to license their contributions to Element under a [Contributor License Agreement](https://cla-assistant.io/element-hq/matrix-authentication-service) (CLA). This ensures that their contribution will be made available under an OSI-approved open-source license, currently Affero General Public License v3 (AGPLv3).
Everyone is welcome to contribute code to [Matrix Authentication Service](https://github.com/element-hq/matrix-authentication-service), provided that they are willing to license their contributions to Element under a [Contributor License Agreement](https://cla-assistant.io/element-hq/matrix-authentication-service) (CLA). This ensures that their contribution will be made available under an OSI-approved open-source license, currently Affero General Public License v3 (AGPLv3).
Please see the [Element blog post](https://element.io/blog/synapse-now-lives-at-github-com-element-hq-synapse/) for the full rationale.

View File

@@ -117,7 +117,7 @@ At this point, the releaser should check the changelog and ensure the "Set as pr
[`translations-download` workflow]: https://github.com/element-hq/matrix-authentication-service/actions/workflows/translations-download.yaml
[`release-branch` workflow]: https://github.com/element-hq/matrix-authentication-service/actions/workflows/release-branch.yaml
[`release-bump` workflow]: https://github.com/element-hq/matrix-authentication-service/actions/workflows/release-bump.yaml
[`build` workflow]: https://github.com/element-hq/matrix-authentication-service/actions/workflows/build
[`build` workflow]: https://github.com/element-hq/matrix-authentication-service/actions/workflows/build.yaml
[translation download PR]: https://github.com/element-hq/matrix-authentication-service/pulls?q=is%3Apr+label%3AA-I18n
[CI to churn]: https://github.com/element-hq/matrix-authentication-service/actions/workflows/build.yaml?query=event%3Apush+actor%3Amatrixbot
[draft release to appear]: https://github.com/element-hq/matrix-authentication-service/releases

View File

@@ -257,8 +257,11 @@ The following key types are supported:
- ECDSA with the P-384 (`secp384r1`) curve
- ECDSA with the K-256 (`secp256k1`) curve
Each entry must have a unique (and arbitrary) `kid`, plus the key itself.
The key can either be specified inline (with the `key` property), or loaded from a file (with the `key_file` property).
Each entry must have a unique `kid`, plus the key itself.
The `kid` can be any case-sensitive string value as long as it is unique to this list;
a keys `kid` value must be stable across restarts.
The key can either be specified inline (with the `key` property),
or loaded from a file (with the `key_file` property).
The following key formats are supported:
- PKCS#1 PEM or DER-encoded RSA private key
@@ -740,6 +743,13 @@ upstream_oauth2:
# authorization request.
#forward_login_hint: false
# What to do when receiving an OIDC Backchannel logout request.
# Possible values are:
# - `do_nothing` (default): do nothing, other than validating and logging the request
# - `logout_browser_only`: Only log out the MAS 'browser session' started by this OIDC session
# - `logout_all`: Log out all sessions started by this OIDC session, including MAS 'browser sessions' and client sessions
#on_backchannel_logout: do_nothing
# How user attributes should be mapped
#
# Most of those attributes have two main properties:
@@ -769,6 +779,12 @@ upstream_oauth2:
localpart:
#action: force
#template: "{{ user.preferred_username }}"
# How to handle when localpart already exists.
# Possible values are (default: fail):
# - `add` : Adds the upstream account link to the existing user, regardless of whether there is an existing link or not.
# - `fail` : Fails the upstream OAuth 2.0 login.
#on_conflict: fail
# The display name is the user's display name.
displayname:

View File

@@ -24,6 +24,7 @@ The general configuration usually goes as follows:
- `response_type`: `code`
- `response_mode`: `query`
- `grant_type`: `authorization_code`
- (optional) `backchannel_logout_uri`: `https://<auth-service-domain>/upstream/backchannel-logout/<id>`
- fill the `upstream_oauth2` section of the configuration file with the following parameters:
- `providers`:
- `id`: the previously generated ULID
@@ -65,6 +66,30 @@ The template has the following variables available:
- `user`: an object which contains the claims from both the `id_token` and the `userinfo` endpoint
- `extra_callback_parameters`: an object with the additional parameters the provider sent to the redirect URL
## Allow linking existing user accounts
The authentication service supports linking external provider identities to existing local user accounts.
To enable this behavior, the following option must be explicitly set in the provider configuration:
```yaml
claims_imports:
localpart:
on_conflict: add
```
`on_conflict` configuration is specific to `localpart` claim_imports, it can be either:
* `add` : when a user authenticates with the provider for the first time, the system checks whether a local user already exists with a `localpart` matching the attribute mapping `localpart` , _by default `{{ user.preferred_username }}`_. If a match is found, the external identity is linked to the existing local account.
* `fail` *(default)* : fails the sso login.
To enable this option, the `localpart` mapping must be set to either `force` or `require`.
> ⚠️ **Security Notice**
> Enabling this option can introduce a risk of account takeover.
>
> To mitigate this risk, ensure that this option is only enabled for identity providers where you can guarantee that the attribute mapping `localpart` will reliably and uniquely correspond to the intended local user account.
## Multiple providers behaviour
Multiple authentication methods can be configured at the same time, in which case the authentication service will let the user choose which one to use.
@@ -73,6 +98,25 @@ In such cases, the `human_name` parameter of the provider configuration is used
If there is only one upstream provider configured and the local password database is disabled ([`passwords.enabled`](../reference/configuration.md#passwords) is set to `false`), the authentication service will automatically trigger an authorization flow with this provider.
## Backchannel logout
The service supports receiving [OpenID Connect Back-Channel Logout](https://openid.net/specs/openid-connect-backchannel-1_0.html) requests.
Those are notifications from the upstream provider that the user has logged out of the provider.
The backchannel logout URI must be configured in the provider as `https://<auth-service-domain>/upstream/backchannel-logout/<id>`, where `<id>` is the `id` of the provider.
By default, the authentication service will not perform any action when receiving a backchannel logout request.
The [`on_backchannel_logout`](../reference/configuration.md#upstream_oauth2) option can be used to configure what to do when receiving a backchannel logout request.
Possible values are:
- `do_nothing`: Do nothing, other than validating and logging the request
- `logout_browser_only`: Only log out the MAS 'browser session' started by this OIDC session
- `logout_all`: Log out all sessions started by this OIDC session, including MAS 'browser sessions' and client sessions
One important caveat is that `logout_all` will log out all sessions started by this upstream OIDC session, including 'remote' ones done through the Device Code flow.
Concretely, this means that if QR-code login is used to log in on a phone from a laptop, when MAS receives a backchannel logout request from the upstream provider for the laptop, MAS will also log out the session on the phone.
## Sample configurations
This section contains sample configurations for popular OIDC providers.
@@ -93,12 +137,11 @@ upstream_oauth2:
response_mode: "form_post"
token_endpoint_auth_method: "sign_in_with_apple"
sign_in_with_apple:
# Only one of the below should be filled for the private key
private_key_file: "<Location of the PEM-encoded private key file>" # TO BE FILLED
private_key: | # TO BE FILLED
# <Contents of the private key>
team_id: "<Team ID>" # TO BE FILLED
key_id: "<Key ID>" # TO BE FILLED
claims_imports:
@@ -386,6 +429,9 @@ Follow the [Getting Started Guide](https://www.keycloak.org/guides) to install K
| Client Protocol | `openid-connect` |
| Access Type | `confidential` |
| Valid Redirect URIs | `https://<auth-service-domain>/upstream/callback/<id>` |
| Front channel logout | `Off` |
| Backchannel logout URL | `https://<auth-service-domain>/upstream/backchannel-logout/<id>` |
| Backchannel logout session required | `On` |
5. Click `Save`
6. On the Credentials tab, update the fields:
@@ -554,4 +600,4 @@ To use a Rauthy-supported [Ephemeral Client](https://sebadob.github.io/rauthy/wo
"access_token_signed_response_alg": "RS256",
"id_token_signed_response_alg": "RS256"
}
```
```