This documentation is out of date!

This documentation site is for the versions of matrix-authentication-service maintained by the Matrix.org Foundation (github.com/matrix-org/matrix-authentication-service), available under the Apache 2.0 licence.

Since version 0.12.0, matrix-authentication-service is now maintained by Element under a new licence (github.com/element-hq/matrix-authentication-service).

If you are interested in the documentation for a later version of matrix-authentication-service, please refer to https://element-hq.github.io/matrix-authentication-service/.

Policy engine

A set of actions are controlled by a generic policy engine. A decision of the policy engine is deterministically made based on three components:

  • The policy itself
  • A static configuration
  • The action to be performed

The policy is a Open Policy Agent (OPA) policy compiled into WebAssembly. Matrix Authentication Service ships with a default policy which should be sufficient for most deployments. It can be replaced with a custom policy if needed, which can be useful to implement custom authorization logic without recompiling the service.

Actions

The policy engine mainly restricts three operations:

  • User attributes, which includes user registration, user profile updates, and user password changes.
  • Client registration, when an OAuth 2.0 dynamic client registration is requested.
  • Authorization requests, when a client requests an access token.

Policies are only evaluated in user-facing contexts, and not in administrative contexts. 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:

  • 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.
  • email.rego: When a user adds a new email address to their account.
  • password.rego: When a user changes their password.

Client registration

The policy (client_registration.rego) is evaluated when a client sends their metadata through the OAuth 2.0 dynamic client registration API. By default, it enforces a set of strict rules to make sure clients provide enough information about themselves, with coherent URLs. This is useful in production environments, but can be relaxed in development environments.

Authorization requests

The policy (authorization_grant.rego) is evaluated when a client requests an access token. This only covers OAuth 2.0 sessions, not compatibility sessions. It is evaluated for the authorization code grant, the client credentials grant and the device authorization grant.

This is probably the most interesting policy, as it defines which scope can be granted to which user and which client.

On evaluation, three main entities are available:

  • details about the grant, such as the type of grant and the requested scopes
  • the client making the request
  • the user with their attributes (only for the authorization code grant and the device authorization grant)

The policy evaluation cannot modify the grant, only allow or deny it. Therefore the client must know in advance which scope they want to request.

This is an important concept to understand: what access a token has is stored in the session itself, therefore access to privileged scopes is only based on policy evaluation, not on user attributes.

If we take the Synapse admin API access as an example, the fact that an access token has admin API access doesn't depend on attributes on the user directly. Instead, it is during the creation of the session that:

  • the client asks for the corresponding scope (e.g. urn:synapse:admin:*)
  • the policy engine decides whether to grant it or not

The default policy shipped with the service does gate access to this scope based on a user attributes (can_request_admin), but this is not a requirement.

It does make reasoning about admin access more complicated compared to a simple boolean flag on the user like what Synapse does, but it also allows for more complex authorization logic. This is especially important as in the future it will make it possible to implement a more granular role-based access control system to fit more complex use cases.

To understand the authorization process and how sessions are created, refer to the authorization and sessions section.