Merge remote-tracking branch 'origin/main' into quenting/schemars-0.9

This commit is contained in:
Quentin Gliech
2025-11-06 17:34:43 +01:00
890 changed files with 27640 additions and 10097 deletions

View File

@@ -21,6 +21,7 @@
- [Policy engine](./topics/policy.md)
- [Authorization and sessions](./topics/authorization.md)
- [Use the Admin API](./topics/admin-api.md)
- [Get an access token](./topics/access-token.md)
# Reference

File diff suppressed because it is too large Load Diff

View File

@@ -240,8 +240,13 @@
"type": "string",
"nullable": true
},
"client_secret_file": {
"description": "Path to the file containing the client secret. The client secret is used\n by the `client_secret_basic`, `client_secret_post` and\n `client_secret_jwt` authentication methods.",
"type": "string",
"nullable": true
},
"client_secret": {
"description": "The client secret, used by the `client_secret_basic`,\n `client_secret_post` and `client_secret_jwt` authentication methods",
"description": "Alternative to `client_secret_file`: Reads the client secret directly\n from the config.",
"type": "string",
"nullable": true
},
@@ -1561,7 +1566,9 @@
"type": "object",
"properties": {
"kid": {
"type": "string"
"description": "The key ID `kid` of the key as used by JWKs.\n\n If not given, `kid` will be the keys RFC 7638 JWK Thumbprint.",
"type": "string",
"nullable": true
},
"password_file": {
"type": "string",
@@ -1579,10 +1586,7 @@
"type": "string",
"nullable": true
}
},
"required": [
"kid"
]
}
},
"PasswordsConfig": {
"description": "User password hashing config",
@@ -1701,9 +1705,13 @@
"type": "string",
"default": "localhost:8008"
},
"secret_file": {
"type": "string",
"nullable": true
},
"secret": {
"description": "Shared secret to use for calls to the admin API",
"type": "string"
"type": "string",
"nullable": true
},
"endpoint": {
"description": "The base URL of the homeserver's client API",
@@ -1711,23 +1719,30 @@
"format": "uri",
"default": "http://localhost:8008/"
}
},
"required": [
"secret"
]
}
},
"HomeserverKind": {
"description": "The kind of homeserver it is.",
"oneOf": [
{
"description": "Homeserver is Synapse",
"description": "Homeserver is Synapse, version 1.135.0 or newer",
"type": "string",
"const": "synapse"
},
{
"description": "Homeserver is Synapse, in read-only mode\n\n This is meant for testing rolling out Matrix Authentication Service with\n no risk of writing data to the homeserver.",
"description": "Homeserver is Synapse, version 1.135.0 or newer, in read-only mode\n\n This is meant for testing rolling out Matrix Authentication Service with\n no risk of writing data to the homeserver.",
"type": "string",
"const": "synapse_read_only"
},
{
"description": "Homeserver is Synapse, using the legacy API",
"type": "string",
"const": "synapse_legacy"
},
{
"description": "Homeserver is Synapse, with the modern API available (>= 1.135.0)",
"type": "string",
"const": "synapse_modern"
}
]
},
@@ -2165,6 +2180,14 @@
"description": "Whether the `login_hint` should be forwarded to the provider in the\n authorization request.\n\n Defaults to `false`.",
"type": "boolean",
"default": false
},
"on_backchannel_logout": {
"description": "What to do when receiving an OIDC Backchannel logout request.\n\n Defaults to `do_nothing`.",
"allOf": [
{
"$ref": "#/definitions/OnBackchannelLogout"
}
]
}
},
"required": [
@@ -2363,6 +2386,14 @@
"description": "The Jinja2 template to use for the localpart attribute\n\n If not provided, the default template is `{{ user.preferred_username }}`",
"type": "string",
"nullable": true
},
"on_conflict": {
"description": "How to handle conflicts on the claim, default value is `Fail`",
"allOf": [
{
"$ref": "#/definitions/OnConflict"
}
]
}
}
},
@@ -2391,6 +2422,21 @@
}
]
},
"OnConflict": {
"description": "How to handle an existing localpart claim",
"oneOf": [
{
"description": "Fails the sso login on conflict",
"type": "string",
"const": "fail"
},
{
"description": "Adds the oauth identity link, regardless of whether there is an existing\n link or not",
"type": "string",
"const": "add"
}
]
},
"DisplaynameImportPreference": {
"description": "What should be done for the displayname attribute",
"type": "object",
@@ -2440,6 +2486,26 @@
}
}
},
"OnBackchannelLogout": {
"description": "What to do when receiving an OIDC Backchannel logout request.",
"oneOf": [
{
"description": "Do nothing",
"type": "string",
"const": "do_nothing"
},
{
"description": "Only log out the MAS 'browser session' started by this OIDC session",
"type": "string",
"const": "logout_browser_only"
},
{
"description": "Log out all sessions started by this OIDC session, including MAS\n 'browser sessions' and client sessions",
"type": "string",
"const": "logout_all"
}
]
},
"BrandingConfig": {
"description": "Configuration section for tweaking the branding of the service",
"type": "object",
@@ -2538,6 +2604,10 @@
"description": "Whether to enable self-service password registration. Defaults to\n `false` if password authentication is enabled.\n\n This has no effect if password login is disabled.",
"type": "boolean"
},
"password_registration_email_required": {
"description": "Whether self-service password registrations require a valid email.\n Defaults to `true`.\n\n This has no effect if password registration is disabled.",
"type": "boolean"
},
"password_change_allowed": {
"description": "Whether users are allowed to change their passwords. Defaults to `true`.\n\n This has no effect if password login is disabled.",
"type": "boolean"

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.
@@ -72,6 +72,7 @@ Make sure your code adheres to our Rust and TypeScript code style by running:
- `cargo +nightly fmt` (with the nightly toolchain installed)
- `npm run format` in the `frontend` directory
- `make fmt` in the `policies` directory (if changed)
When updating SQL queries in the `crates/storage-pg/` crate, you may need to update the `sqlx` introspection data. To do this, make sure to install `cargo-sqlx` (`cargo install sqlx-cli`) and:
@@ -86,11 +87,18 @@ While you're developing and before submitting a patch, you'll want to test your
- Run `cargo clippy --workspace` to lint the Rust code.
- Run `npm run lint` in the `frontend` directory to lint the frontend code.
- Run `make fmt` and `make lint` in the `policies` directory to format and lint the included policy.
### Run the tests
- Run the tests to the backend by running `cargo test --workspace`. This requires a connection to a PostgreSQL database, set via the `DATABASE_URL` environment variable.
If you haven't already, install [Cargo-Nextest](https://nexte.st/docs/installation/pre-built-binaries/).
- Run the tests to the backend by running `cargo nextest run --workspace`. This requires a connection to a PostgreSQL database, set via the `DATABASE_URL` environment variable.
- Run the tests to the frontend by running `npm run test` in the `frontend` directory.
- To run the tests for the included policy, change to the `policies` directory and run one of:
- `make test` (needs Open Policy Agent installed)
- `make PODMAN=1 test` (runs inside a container; needs Podman installed)
- `make DOCKER=1 test` (runs inside a container; needs Docker installed)
## 8. Submit a pull request

View File

@@ -97,7 +97,7 @@ At this point, the releaser should check the changelog and ensure the "Set as pr
1. Wait for [CI to churn] and the [draft release to appear]. This takes about 30 minutes.
1. Double-check the changelog on the draft release.
1. Check the "Set as pre-release" checkbox, and publish the release.
1. Delete the N-2 release branch on [Localazy], meaning that once the 0.16 release cycle begins, the 0.14 release branch will be deleted.
1. Delete the N-2 release branch on [Localazy](https://localazy.com/console/branching), meaning that once the 0.16 release cycle begins, the 0.14 release branch will be deleted.
- Create new release candidates if needed:
1. Run the `translations-download` workflow on the release branch.
1. Wait for the [translation download PR] to be automatically merged.
@@ -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

@@ -23,6 +23,32 @@ $ mas-cli manage add-email <username> <email>
$ mas-cli manage verify-email <username> <email>
```
## `manage promote-admin`
Make a user admin.
```
$ mas-cli manage promote-admin <username>
```
**This doesn't make all the users sessions admin, but rather lets the user request admin access in administration tools.**
## `manage demote-admin`
Make a user non-admin.
```
$ mas-cli manage demote-admin <username>
```
## `manage list-admin-users`
List all users with admin privileges.
```
$ mas-cli manage list-admins
```
## `manage set-password`
Set a user password.
@@ -93,8 +119,11 @@ $ mas-cli manage lock-user <username> --deactivate
Unlock a user.
Options:
- `--reactivate`: Whether to reactivate the user.
```
$ mas-cli manage unlock-user <username>
$ mas-cli manage unlock-user <username> --reactivate
```
## `manage register-user`

View File

@@ -135,7 +135,9 @@ matrix:
# Shared secret used to authenticate the service to the homeserver
# This must be of high entropy, because leaking this secret would allow anyone to perform admin actions on the homeserver
secret: "SomeRandomSecret"
secret_file: /path/to/secret/file
# Alternatively, the shared secret can be passed inline.
# secret: "SomeRandomSecret"
# URL to which the homeserver is accessible from the service
endpoint: "http://localhost:8008"
@@ -170,7 +172,8 @@ clients:
# Confidential client
- client_id: 000000000000000000000FIRST
client_auth_method: client_secret_post
client_secret: secret
client_secret_file: secret
# OR client_secret: c1!3n753c237
# List of authorized redirect URIs
redirect_uris:
- http://localhost:1234/callback
@@ -194,35 +197,7 @@ secrets:
# Signing keys
keys:
# It needs at least an RSA key to work properly
- kid: "ahM2bien"
key: |
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAuf28zPUp574jDRdX6uN0d7niZCIUpACFo+Po/13FuIGsrpze
yMX6CYWVPalgXW9FCrhxL+4toJRy5npjkgsLFsknL5/zXbWKFgt69cMwsWJ9Ra57
bonSlI7SoCuHhtw7j+sAlHAlqTOCAVz6P039Y/AGvO6xbC7f+9XftWlbbDcjKFcb
pQilkN9qtkdEH7TLayMAFOsgNvBlwF9+oj9w5PIk3veRTdBXI4GlHjhhzqGZKiRp
oP9HnycHHveyT+C33vuhQso5a3wcUNuvDVOixSqR4kvSt4UVWNK/KmEQmlWU1/m9
ClIwrs8Q79q0xkGaSa0iuG60nvm7tZez9TFkxwIDAQABAoIBAHA5YkppQ7fJSm0D
wNDCHeyABNJWng23IuwZAOXVNxB1bjSOAv8yNgS4zaw/Hx5BnW8yi1lYZb+W0x2u
i5X7g91j0nkyEi5g88kJdFAGTsM5ok0BUwkHsEBjTUPIACanjGjya48lfBP0OGWK
LJU2Acbjda1aeUPFpPDXw/w6bieEthQwroq3DHCMnk6i9bsxgIOXeN04ij9XBmsH
KPCP2hAUnZSlx5febYfHK7/W95aJp22qa//eHS8cKQZCJ0+dQuZwLhlGosTFqLUm
qhPlt/b1EvPPY0cq5rtUc2W31L0YayVEHVOQx1fQIkH2VIUNbAS+bfVy+o6WCRk6
s1XDhsECgYEA30tykVTN5LncY4eQIww2mW8v1j1EG6ngVShN3GuBTuXXaEOB8Duc
yT7yJt1ZhmaJwMk4agmZ1/f/ZXBtfLREGVzVvuwqRZ+LHbqIyhi0wQJA0aezPote
uTQnFn+IveHGtpQNDYGL/UgkexuCxbc2HOZG51JpunCK0TdtVfO/9OUCgYEA1TuS
2WAXzNudRG3xd/4OgtkLD9AvfSvyjw2LkwqCMb3A5UEqw7vubk/xgnRvqrAgJRWo
jndgRrRnikHCavDHBO0GAO/kzrFRfw+e+r4jcLl0Yadke8ndCc7VTnx4wQCrMi5H
7HEeRwaZONoj5PAPyA5X+N/gT0NNDA7KoQT45DsCgYBt+QWa6A5jaNpPNpPZfwlg
9e60cAYcLcUri6cVOOk9h1tYoW7cdy+XueWfGIMf+1460Z90MfhP8ncZaY6yzUGA
0EUBO+Tx10q3wIfgKNzU9hwgZZyU4CUtx668mOEqy4iHoVDwZu4gNyiobPsyDzKa
dxtSkDc8OHNV6RtzKpJOtQKBgFoRGcwbnLH5KYqX7eDDPRnj15pMU2LJx2DJVeU8
ERY1kl7Dke6vWNzbg6WYzPoJ/unrJhFXNyFmXj213QsSvN3FyD1pFvp/R28mB/7d
hVa93vzImdb3wxe7d7n5NYBAag9+IP8sIJ/bl6i9619uTxwvgtUqqzKPuOGY9dnh
oce1AoGBAKZyZc/NVgqV2KgAnnYlcwNn7sRSkM8dcq0/gBMNuSZkfZSuEd4wwUzR
iFlYp23O2nHWggTkzimuBPtD7Kq4jBey3ZkyGye+sAdmnKkOjNILNbpIZlT6gK3z
fBaFmJGRJinKA+BJeH79WFpYN6SBZ/c3s5BusAbEU7kE5eInyazP
-----END RSA PRIVATE KEY-----
- key_file: keys/rsa_key
- kid: "iv1aShae"
key: |
-----BEGIN EC PRIVATE KEY-----
@@ -257,16 +232,24 @@ 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 in the list corresponds to one signing key used by MAS.
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
- PKCS#8 PEM or DER-encoded RSA or ECDSA private key, encrypted or not
- SEC1 PEM or DER-encoded ECDSA private key
A [JWK Key ID] is automatically derived from each key.
To override this default, set `kid` to a custom value.
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.
For PKCS#8 encoded keys, the `password` or `password_file` properties can be used to decrypt the key.
[JWK Key ID]: <https://datatracker.ietf.org/doc/html/rfc7517#section-4.5>
## `passwords`
Settings related to the local password database
@@ -313,6 +296,12 @@ account:
# This has no effect if password login is disabled.
password_registration_enabled: false
# Whether self-service registrations require a valid email
#
# Defaults to `true`
# This has no effect if password registration is disabled.
password_registration_email_required: true
# Whether users are allowed to change their passwords
#
# Defaults to `true`.
@@ -740,6 +729,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:
@@ -770,6 +766,12 @@ upstream_oauth2:
#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:
#action: suggest
@@ -795,6 +797,37 @@ upstream_oauth2:
#template: "@{{ user.preferred_username }}"
```
## `branding`
Configuration section for tweaking the branding of the service.
```yaml
branding:
# A human-readable name. Defaults to the server's address.
#service_name:
# Link to a privacy policy, displayed in the footer of web pages and
# emails. It is also advertised to clients through the `op_policy_uri`
# OIDC provider metadata.
#policy_uri:
# Link to a terms of service document, displayed in the footer of web
# pages and emails. It is also advertised to clients through the
# `op_tos_uri` OIDC provider metadata.
#
# This also adds a mandatory checkbox during registration. The value of
# this config item will be stored in the `user_terms` table to indicate
# which ToS document the user accepted. Note that currently changing this
# value will not force existing users to re-accept terms.
#tos_uri:
# Legal imprint, displayed in the footer in the footer of web pages and emails.
#imprint:
# Logo displayed in some web pages.
#logo_uri:
```
## `experimental`
Settings that may change or be removed in future versions.

View File

@@ -4,9 +4,8 @@ The [default policy](../topics/policy.md#authorization-requests) shipped with MA
- [`openid`](#openid)
- [`email`](#email)
- [`urn:matrix:org.matrix.msc2967.client:api:*`](#urnmatrixorgmatrixmsc2967clientapi)
- [`urn:matrix:org.matrix.msc2967.client:device:[device id]`](#urnmatrixorgmatrixmsc2967clientdevicedevice-id)
- [`urn:matrix:org.matrix.msc2967.client:guest`](#urnmatrixorgmatrixmsc2967clientguest)
- [`urn:matrix:client:api:*`](#urnmatrixclientapi)
- [`urn:matrix:client:device:[device id]`](#urnmatrixclientdevicedevice-id)
- [`urn:synapse:admin:*`](#urnsynapseadmin)
- [`urn:mas:admin`](#urnmasadmin)
- [`urn:mas:graphql:*`](#urnmasgraphql)
@@ -33,13 +32,13 @@ The default policy allows any client and any user to request this scope.
Those scopes are specific to the Matrix protocol and are part of [MSC2967].
### `urn:matrix:org.matrix.msc2967.client:api:*`
### `urn:matrix:client:api:*`
This scope grants access to the full Matrix client-server API.
The default policy allows any client and any user to request this scope.
### `urn:matrix:org.matrix.msc2967.client:device:[device id]`
### `urn:matrix:client:device:[device id]`
This scope sets the device ID of the session, where `[device id]` is the device ID of the session.
Currently, MAS only allows the following characters in the device ID: `a-z`, `A-Z`, `0-9` and `-`.
@@ -49,15 +48,6 @@ There can only be one device ID in the scope list of a session.
The default policy allows any client and any user to request this scope.
### `urn:matrix:org.matrix.msc2967.client:guest`
This scope grants access to a restricted set of endpoints that are available to guest users.
It is mutually exclusive with the `urn:matrix:org.matrix.msc2967.client:api:*` scope.
Note that MAS doesn't yet implement any special semantic around guest users, but this scope is reserved for future use.
The default policy allows any client and any user to request this scope.
## Synapse-specific scopes
MAS also supports one Synapse-specific scope, which aren't formally defined in any specification.
@@ -67,7 +57,7 @@ MAS also supports one Synapse-specific scope, which aren't formally defined in a
This scope grants access to the [Synapse admin API].
Because of how Synapse works for now, this scope by itself isn't sufficient to access the admin API.
A session wanting to access the admin API also needs to have the `urn:matrix:org.matrix.msc2967.client:api:*` scope.
A session wanting to access the admin API also needs to have the `urn:matrix:client:api:*` scope.
The default policy doesn't allow everyone to request this scope.
It allows:

View File

@@ -1,74 +1,46 @@
# Homeserver configuration
The `matrix-authentication-service` is designed to be run alongside a Matrix homeserver.
It currently only supports [Synapse](https://github.com/element-hq/synapse) through the experimental OAuth delegation feature.
It currently only supports [Synapse](https://github.com/element-hq/synapse) version 1.136.0 or later.
The authentication service needs to be able to call the Synapse admin API to provision users through a shared secret, and Synapse needs to be able to call the service to verify access tokens using the OAuth 2.0 token introspection endpoint.
## Provision a client for the Homeserver to use
In the [`clients`](../reference/configuration.md#clients) section of the configuration file, add a new client with the following properties:
- `client_id`: a unique identifier for the client. It must be a valid [ULID](https://github.com/ulid/spec), and it happens that `0000000000000000000SYNAPSE` is a valid ULID.
- `client_auth_method`: set to `client_secret_basic`. Other methods are possible, but this is the easiest to set up.
- `client_secret`: a shared secret used for the homeserver to authenticate
```yaml
clients:
- client_id: 0000000000000000000SYNAPSE
client_auth_method: client_secret_basic
client_secret: "SomeRandomSecret"
```
**Don't forget to sync the configuration file** with the database after adding the client, using the [`config sync`](../reference/cli/config.md#config-sync---prune---dry-run) command.
## Configure the connection to the homeserver
In the [`matrix`](../reference/configuration.md#matrix) section of the configuration file, add the following properties:
- `kind`: the type of homeserver to connect to, currently only `synapse` is supported
- `homeserver`: corresponds to the `server_name` in the Synapse configuration file
- `secret`: a shared secret the service will use to call the homeserver admin API
- `secret`: a shared secret the service will use to call the homeserver MAS API
- `endpoint`: the URL to which the homeserver is accessible from the service
```yaml
matrix:
homeserver: localhost:8008
secret: "AnotherRandomSecret"
kind: synapse
homeserver: example.com
endpoint: "http://localhost:8008"
secret: "AVeryRandomSecretPleaseUseSomethingSecure"
# Alternatively, using a file:
#secret_path: /path/to/secret.txt
```
## Configure the homeserver to delegate authentication to the service
Set up the delegated authentication feature in the Synapse configuration in the `experimental_features` section:
Set up the delegated authentication feature **in the Synapse configuration** in the `matrix_authentication_service` section:
```yaml
experimental_features:
msc3861:
enabled: true
# Synapse will call `{issuer}/.well-known/openid-configuration` to get the OIDC configuration
issuer: http://localhost:8080/
# Matches the `client_id` in the auth service config
client_id: 0000000000000000000SYNAPSE
# Matches the `client_auth_method` in the auth service config
client_auth_method: client_secret_basic
# Matches the `client_secret` in the auth service config
client_secret: "SomeRandomSecret"
# Matches the `matrix.secret` in the auth service config
admin_token: "AnotherRandomSecret"
# URL to advertise to clients where users can self-manage their account
# Defaults to the URL advertised by MAS, e.g. `https://{public_mas_domain}/account/`
#account_management_url: "http://localhost:8080/account/"
# URL which Synapse will use to introspect access tokens
# Defaults to the URL advertised by MAS, e.g. `https://{public_mas_domain}/oauth2/introspect`
# This is useful to override if Synapse has a way to call the auth service's
# introspection endpoint directly, skipping intermediate reverse proxies
#introspection_endpoint: "http://localhost:8080/oauth2/introspect"
matrix_authentication_service:
enabled: true
endpoint: http://localhost:8080/
secret: "AVeryRandomSecretPleaseUseSomethingSecure"
# Alternatively, using a file:
#secret_file: /path/to/secret.txt
```
The `endpoint` property should be set to the URL of the authentication service.
This can be an internal URL, to avoid unnecessary round-trips.
The `secret` property must match in both the Synapse configuration and the Matrix Authentication Service configuration.
## Set up the compatibility layer
The service exposes a compatibility layer to allow legacy clients to authenticate using the service.
@@ -81,3 +53,17 @@ The following Matrix Client-Server API endpoints need to be handled by the authe
- [`/_matrix/client/*/refresh`](https://spec.matrix.org/latest/client-server-api/#post_matrixclientv3refresh)
See the [reverse proxy configuration](./reverse-proxy.md) guide for more information.
## Migrating from the experimental MSC3861 feature
If you are migrating from the experimental MSC3861 feature in Synapse, you will need to migrate the `experimental_features.msc3861` section of the Synapse configuration to the `matrix_authentication_service` section.
To do so, you need to:
- Remove the `experimental_features.msc3861` section from the Synapse configuration
- Add the `matrix_authentication_service` section to the Synapse configuration with:
- `enabled: true`
- `endpoint` set to the URL of the authentication service
- `secret` set to the same secret as the `admin_token` that was set in the `msc3861` section
- Optionally, remove the client provisioned for Synapse in the `clients` section of the MAS configuration

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"
}
```
```

View File

@@ -0,0 +1,31 @@
# Get an access token
The [Matrix Authentication Service repository contains a simple shell script](https://github.com/element-hq/matrix-authentication-service/blob/main/misc/device-code-grant.sh) to interactively get an access token with arbitrary scopes.
It requires `sh`, `jq` and `curl` to be installed.
This can be run from anywhere, not necessarily from the host where MAS is running.
```sh
sh ./misc/device-code-grant.sh [synapse-url] <scope>...
```
This will prompt you to open a URL in your browser, finish the authentication flow, and print the access and refresh tokens.
This can be used to get access to the MAS admin API:
```sh
sh ./misc/device-code-grant.sh https://synapse.example.com/ urn:mas:admin
```
Or to the Synapse admin API:
```sh
sh ./misc/device-code-grant.sh https://synapse.example.com/ urn:matrix:org.matrix.msc2967.client:api:* urn:synapse:admin:*
```
Or even both at the same time:
```sh
sh ./misc/device-code-grant.sh https://synapse.example.com/ urn:matrix:org.matrix.msc2967.client:api:* urn:mas:admin urn:synapse:admin:*
```
Note that the token will only be valid for a short time (5 minutes by default) and needs to be revoked manually from the MAS user interface.

View File

@@ -46,7 +46,9 @@ If admin API is enabled, MAS will also serve the specification at `/api/spec.jso
## Authentication
All requests to the admin API are gated using access tokens obtained using OAuth 2.0 grants.
All requests to the admin API are gated either using access tokens obtained using OAuth 2.0 grants,
or using personal access tokens (which must currently be issued through the Admin API).
They must have the [`urn:mas:admin`](../reference/scopes.md#urnmasadmin) scope.
### User-interactive tools

View File

@@ -129,6 +129,33 @@ It may also be used in the future as a foundation for a new Application Service
This works by presenting the client credentials to get back an access token.
The simplest type of client credentials is a client ID and client secret pair, but MAS also supports client authentication with a JWT ([RFC 7523]), which is a robust way to authenticate clients without a shared secret.
## Personal sessions (personal access tokens)
Personal access tokens are a credential that can be issued to give access to a user,
with predefined scopes and a predefined expiry time.
Either before or after expiry, the owner of the token can regenerate it, which produces a new
access token with the same scopes but a new expiry time.
Personal access tokens are intended to fulfill two basic use cases:
1. an easy way to obtain a clean token for your own user, for use in automation and scripts;
2. a way to obtain a token for administrative access of another user, either for ad-hoc administrative operations or to set up a bot or similar service.
In the future, users will be able to create their own personal access tokens, but this is currently not implemented
so (1) is currently not supported.
For now, personal access tokens must be created, regenerated and revoked by administrators through the [Admin API], satisfying use case (2).
[Element Admin](https://github.com/element-hq/element-admin), available by default in Element Server Suite, can be used to do this interactively.
You can also use the online beta deployment at [admin-beta.element.dev](https://admin-beta.element.dev/). <!--- TODO stable deployment -->
### Validity
Personal sessions can be used so long as:
- the owner (creator) of the token is still an active and unlocked user (or static OAuth 2 client); and
- the actor (target user, or user being controlled by the token) has not been deactivated. Though the actor is allowed to be locked.
[MSC4108]: https://github.com/matrix-org/matrix-spec-proposals/pull/4108
[RFC 6749]: https://datatracker.ietf.org/doc/html/rfc6749
[RFC 7523]: https://datatracker.ietf.org/doc/html/rfc7523
@@ -140,3 +167,4 @@ The simplest type of client credentials is a client ID and client secret pair, b
[`urn:synapse:admin:*`]: ../reference/scopes.md#urnsynapseadmin
[`urn:mas:graphql:*`]: ../reference/scopes.md#urnmasgraphql
[`urn:mas:admin`]: ../reference/scopes.md#urnmasadmin
[Admin API]: ./admin-api.md

View File

@@ -24,11 +24,10 @@ As such, they usually can be bypassed through the admin API or the CLI if needed
### User attributes
The policy is evaluated in three different scenarios:
The policy is evaluated in the following different scenarios:
- [`register.rego`]: During user registration, either with password credentials or with an upstream OAuth 2.0 provider. This calls the [`email.rego`] and [`password.rego`] policies as well.
- [`register.rego`]: During user registration, either with password credentials or with an upstream OAuth 2.0 provider. This calls the [`email.rego`] policy as well.
- [`email.rego`]: When a user adds a new email address to their account.
- [`password.rego`]: When a user changes their password.
### Client registration
@@ -69,8 +68,7 @@ This is especially important as in the future it will make it possible to implem
To understand the authorization process and how sessions are created, refer to the [authorization and sessions](./authorization.md) section.
[`register.rego`]: https://github.com/element-hq/matrix-authentication-service/blob/main/policies/register.rego
[`email.rego`]: https://github.com/element-hq/matrix-authentication-service/blob/main/policies/email.rego
[`password.rego`]: https://github.com/element-hq/matrix-authentication-service/blob/main/policies/password.rego
[`client_registration.rego`]: https://github.com/element-hq/matrix-authentication-service/blob/main/policies/client_registration.rego
[`authorization_grant.rego`]: https://github.com/element-hq/matrix-authentication-service/blob/main/policies/authorization_grant.rego
[`register.rego`]: https://github.com/element-hq/matrix-authentication-service/blob/main/policies/register/register.rego
[`email.rego`]: https://github.com/element-hq/matrix-authentication-service/blob/main/policies/email/email.rego
[`client_registration.rego`]: https://github.com/element-hq/matrix-authentication-service/blob/main/policies/client_registration/client_registration.rego
[`authorization_grant.rego`]: https://github.com/element-hq/matrix-authentication-service/blob/main/policies/authorization_grant/authorization_grant.rego