Skip to main content
Version 0.5Draft

Matrix homeserver (Synapse and MAS)

Matrix clients such as Element sign in to the Matrix network via your homeserver, not directly via LuxID. The homeserver (or its authentication service) acts as the OIDC client; LuxID acts as the OIDC provider. Users authenticating via LuxID receive a Matrix account on your homeserver.

There are two ways a Matrix deployment can talk to an upstream OIDC provider like LuxID:

  • Synapse built-in OIDC - configured directly in homeserver.yaml under oidc_providers. This is the original mechanism and still works, but it is now considered the legacy path.
  • Matrix Authentication Service (MAS) - the next-generation, standalone authentication component for Matrix. MAS handles all authentication for the homeserver and brokers to upstream providers under upstream_oauth2. This is the recommended path for new deployments and the direction the Matrix project is moving towards.

Pick the tab that matches your deployment. From LuxID's perspective both are just registered OIDC clients holding a Client ID and Client Secret and presenting a registered Redirect URI.

The Synapse homeserver acts as the OIDC client directly. Users authenticating via LuxID receive a Matrix account on your homeserver.

Configure homeserver.yaml

Add or extend the oidc_providers list in your homeserver.yaml:

homeserver.yaml
oidc_providers:
- idp_id: luxid
idp_name: "Sign in with LuxID"
discover: true
issuer: "https://login.luxid.lu"
client_id: "<your Client ID from your LuxID registration>"
client_secret: "<your Client Secret from your LuxID registration>"
scopes: ["openid", "profile", "email"]
user_mapping_provider:
config:
localpart_template: "{{ user.sub }}"
display_name_template: "{{ user.given_name }} {{ user.family_name }}"
email_template: "{{ user.email }}"

With discover: true, Synapse retrieves all endpoint URLs from https://login.luxid.lu/.well-known/openid-configuration. You do not need to specify authorization_endpoint, token_endpoint, or userinfo_endpoint separately.

After editing homeserver.yaml, the Synapse redirect URI will be https://<your-homeserver>/_synapse/client/oidc/callback. Register this URI with LuxID as an allowed Redirect URI before restarting Synapse.

Restart Synapse and test

Restart Synapse:

systemctl restart matrix-synapse

Open the Element (or any Matrix client) login screen pointing at your homeserver. A "Sign in with LuxID" button should appear alongside the standard username/password form. Click it to complete the test.

Synapse production checklist

  • Replace the login-uat.luxid.lu issuer with login.luxid.lu (or remove it and rely on discover: true with the production issuer).
  • Register the production Synapse callback URL with LuxID.
  • Rotate the Client Secret from UAT.
  • Confirm discover: true resolves to the production discovery document.
  • Review your Matrix server's allow_guest_access and registration_shared_secret settings - adding an OIDC provider does not automatically disable local password registration.

Matrix-specific considerations

These apply regardless of whether you use Synapse built-in OIDC or MAS, because both provision Matrix IDs the same way.

Localpart and MXID: The localpart template controls the local part of the user's Matrix ID (@localpart:your.server). Using {{ user.sub }} (the LuxID sub claim) is safe and stable because sub is permanent and unique per user per application. Do not use {{ user.email }} as the localpart - email addresses can change, but Matrix IDs are permanent once created.

User de-duplication on re-login: The homeserver maps OIDC subjects to Matrix accounts on first login. On subsequent logins it recognises the sub claim and re-uses the existing Matrix account rather than creating a new one. This works correctly as long as the provider identifier (idp_id in Synapse, the provider id in MAS) and the sub value remain stable. Do not change the provider identifier after accounts have been provisioned.

Irreversibility of localparts: Matrix IDs cannot be renamed or reassigned. If you change the localpart template, existing users' Matrix IDs are not updated. Plan your localpart strategy carefully before provisioning real users.

Using a pre-computed localpart claim

If sub is not the localpart you want - for example, you need a deterministic, human-meaningful Matrix localpart computed on LuxID's side - LuxID can release a custom, partner-specific claim for this purpose. Custom claims are declared in your Application's Claim Template and reviewed by LuxID like any other claim; once released, you reference the claim name in your localpart template (Synapse localpart_template or MAS claims_imports.localpart.template), for example "{{ user.your_custom_localpart_claim }}". Request a custom claim via LuxID - it is not part of the standard OIDC claim set. See Configure LuxID - available claims for the standard set.

Registering and coexisting callbacks

LuxID validates the redirect_uri against an allowlist of registered URIs (exact match) - the URI is sent by your client at authorization time, not fixed on LuxID's side. A practical consequence: you can register more than one callback at the same time. This is what makes a zero-downtime migration from Synapse built-in OIDC to MAS possible:

  1. Keep the existing Synapse callback (https://<your-homeserver>/_synapse/client/oidc/callback) registered.
  2. Add the new MAS callback (https://<your-mas-host>/upstream/callback/<provider-id>) alongside it.
  3. Both remain active in parallel. As long as the redirect_uri sent is in the allowlist, either path works - cut over to MAS at your own pace.
  4. Once MAS is validated in production, ask LuxID to remove the old Synapse callback.

To add or remove redirect URIs, contact LuxID. For the full rules on exact-match validation, HTTPS, and ports, see Redirect URIs and domains.

Updated 2026-07-03