Single sign-on for Matrix clients
With MATRIX_EXTERNAL_LOGIN_METHOD = oidc, users who want a full Matrix client such as Element sign in to
the homeserver through the same identity provider (IdP) they use for Waldur. They land in the Matrix
account Waldur provisioned for them, with the project rooms Waldur manages, and Waldur hands out no
password or token. Waldur's own chat drawer is unaffected: it keeps using short-lived web sessions.
This page covers Tuwunel, the homeserver the Helm chart and docker-compose ship.
How the accounts line up
Three settings must produce the same name, or the user's SSO login is refused instead of reaching the account Waldur provisioned:
- Waldur's identity provider turns an IdP claim into the Waldur username:
user_claim(defaultsub) is stored inuser_field, which must beusername(with any other field, new users get a random username). MATRIX_USER_ID_FORMAT = usernamemakes the Waldur username the Matrix localpart. Waldur lowercases it and replaces characters a localpart may not hold.- The homeserver's identity provider turns the same claim into the localpart (
userid_claims). Tuwunel 1.9.3 reads onlysub,preferred_username,username,nickname, the local part ofemail, andlogin(GitHub). Other claims, such as eduTEAMS'voperson_id, cannot be used.
The claim must already be a valid Matrix localpart: lowercase letters after folding, digits and
. _ - / +. Tuwunel uses a valid claim as it is (lowercased) and refuses anything else, so a username
with a space, @, : or a non-ASCII letter can never reach the same account over SSO. Waldur escapes
= as =3d, as it is the escape character for non-ASCII letters, so a username with = does not reach
the same account either:
| IdP subject | Waldur provisions | Tuwunel SSO signs in to |
|---|---|---|
alice |
@alice |
@alice |
Alice.Smith |
@alice.smith |
@alice.smith |
alice+lab |
@alice+lab |
@alice+lab |
alice smith, alice@example.org, jüri |
@alice_smith, @alice_example.org, @j=c3=bcri |
refused |
a=b |
@a=3db |
@a=b, a different account |
Every refused row is also a takeover risk. Tuwunel takes a claim as the localpart as it is, and trusted
signs in to any account so named, so @alice_smith is the account of whichever IdP subject's claim reads
alice_smith, not of the user alice smith. With MATRIX_EXTERNAL_LOGIN_METHOD = oidc Waldur therefore
refuses to provision a user whose username does not become their Matrix ID unchanged (apart from
lowercasing), and their chat answers "Chat is unavailable right now". Accounts provisioned before
switching to oidc are not refused, so their chat keeps working; the sso_id_collisions check of the
Diagnostics action under Administration → Configuration → Matrix chat lists them. Rename or
relink those users. waldur link_matrix_account warns when it links such an ID. The IdP should also
refuse claims that are not valid localparts, so that no such user exists in the first place.
Waldur refuses two more kinds of user under oidc, and the same check lists their existing accounts:
- Users whose username another user's differs from only in case. Tuwunel lowercases the claim, so the
subjects
Aliceandaliceboth sign in to@alice. A non-ASCII username that lowercases to ASCII counts too: the Kelvin sign (U+212A) becomesk, so its holder would reach@kate. Deactivated users count, since deactivating them in Waldur does not remove them from the IdP. Rename or remove one of the users. - Users who do not sign in to Waldur through the homeserver's IdP. A local, SAML or other-IdP user
bobholds@bob, and any subject of the homeserver's IdP whose claim readsbobwould sign in to that account. Waldur provisions only users whose registration method isMATRIX_SSO_REGISTRATION_METHOD(see Waldur configuration), and none while it is blank.
Accounts also fail to line up when a user's Matrix ID no longer follows from their username, because
Waldur keeps the ID it derived when it first provisioned them. That covers users renamed afterwards,
including to the claim by OIDC_MATCHMAKING_BY_EMAIL, and users provisioned while MATRIX_USER_ID_FORMAT
was uuid or email_local. After a database reset, waldur link_matrix_account --all looks those users
up under the ID derived now and misses them, and their next chat creates a new, empty account. Link each
of them by hand before they next open chat: waldur link_matrix_account <username> <their old matrix id>.
Waldur provisions a user's Matrix account when they open its chat or are added to a project room. Tuwunel
also remembers the account an IdP identity first signed in to, so a stray account created by an earlier
test login keeps winning. Waldur also refuses to provision a user whose Matrix ID such a stray account
holds, and their chat answers "Chat is unavailable right now". If the account is theirs, link it
deliberately with waldur link_matrix_account <username> <matrix id>. Deactivating it on the homeserver
does not free the ID, and SSO reaches no other account for them; see
Existing Matrix accounts.
Choose a claim users cannot set themselves. Keycloak's sub is a UUID: it becomes both the Waldur
username and the Matrix ID, which reads poorly but cannot be chosen. preferred_username reads better,
but is safe only if users cannot pick or change their username at the IdP, through self-registration or an
"edit username" setting. See trusted below for why.
Homeserver configuration
Register a client for the homeserver at the IdP with the redirect URI
https://<homeserver>/_matrix/client/unstable/login/sso/callback/<client_id>, then add to tuwunel.toml:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | |
What each choice does:
trusted = truesigns the user in to any existing local account whose name matches the claim, not only the ones Waldur provisioned. Without it, Tuwunel refuses accounts it did not create through SSO, which includes every account Waldur provisioned. Set it only for an IdP the operator controls, with a claim users cannot choose. Names also match by accident: a Waldur user who signs in locally or through another IdP asbobholds@bob, and an IdP user whose claim readsbobsigns in to that account; the same goes foralice smith, who holds@alice_smith. Waldur therefore gives Matrix accounts underoidconly to users who sign in to Waldur through this IdP and whose username is their Matrix ID unchanged (see How the accounts line up), but accounts created on the homeserver by other means stay exposed.forbidden_usernameskeeps SSO out of the accounts that matter most. Waldur's bot holds the highest power level in every room it manages, so an IdP user whose claim readswaldur-botwould otherwise take it over. The same goes for homeserver admins. Use the bot's localpart (MATRIX_APPSERVICE_SENDER_LOCALPART),waldur-bootstrap(a name reserved for the bootstrap admin that automatic registration creates) and any other admin's username, anchored as shown. When the Helm chart or docker-compose configures single sign-on, it forbids the bot andwaldur-bootstrapfor you. Tuwunel creates the bot when the appservice is registered, and a forbidden name can still be created that way or through the shared-secret registration API; SSO cannot sign in to it.registration = false: SSO creates no accounts, it only signs in to existing ones. A user Waldur has not provisioned yet is refused until it has.unique_id_fallbacks = falserefuses a claim that cannot become the localpart instead of inventing a random ID.userid_claimsmust name the claim Waldur's identity provider uses asuser_claim, and be one of those Tuwunel reads (above). Name exactly one: Tuwunel tries the listed claims in its own order and moves on to the next when one is not a valid localpart or is forbidden, and withtrustedthe next one can name someone else's account.brandnames the IdP software (keycloak); Tuwunel applies provider-specific workarounds by it.nameis the label on the login button.login_with_password = falseremoves the password form from clients. An admin created with a password then cannot sign in to a client either. The first registration still works: creating the bootstrap admin returns a session, and the same run makes the bot a homeserver admin, which locking deactivated users depends on (see Making the bot a homeserver admin). Later runs that change the registration, such as a token rotation, cannot sign in as the bootstrap admin and needMATRIX_ADMIN_TOKEN, a homeserver admin's access token, instead; see Token rotation. It is also untested with the drawer's encryption reset: the drawer answers the homeserver's interactive authentication with a temporary password that Waldur sets through the admin API, and the homeserver may refuse password authentication altogether once it is off. Reset encryption for a test user from the drawer with this setting before enabling it for everyone.
Tuwunel's SSO cookie is Secure, so the homeserver must be served over HTTPS; plain HTTP only works on
localhost, which browsers treat as secure.
Waldur configuration
- Set
MATRIX_EXTERNAL_LOGIN_METHODtooidc. The external client dialog then shows the room and the homeserver and tells users to sign in with single sign-on; it shows no password and no Matrix ID. - Configure Waldur's identity provider against the same IdP, with
user_claimmatching the homeserver'suserid_claims. - Set
MATRIX_SSO_REGISTRATION_METHODto the registration method Waldur records for that identity provider's users, which is its name in Waldur (provider, such askeycloak;eduteamsfor eduTEAMS), orOIDC_REGISTRATION_METHODfor users who sign in with OIDC bearer tokens. Only those users get a Matrix account. While it is blank, no user does, and thesso_id_collisionsdiagnostic fails.
Checking it
After a user has opened Waldur's chat once:
- Sign in to Element with the homeserver URL and choose the SSO button.
- Element shows the user's Waldur Matrix ID and their project rooms. Messages show as encrypted and unreadable until the Element session is verified (see Limits).
- The user's device list on the homeserver shows Waldur's
WALDUR_WEB_*devices and the Element device, and no second account exists for them.
Limits
- Chat is end-to-end encrypted. Waldur's drawer and bot share message keys only with devices that their owner's encryption identity has signed, and the drawer does not decrypt messages from any other device. Until Element's session is verified, Element cannot read the drawer's or the bot's messages, and the drawer cannot read Element's. The drawer cannot verify other devices, so verifying takes the user's recovery key, which Waldur's external client dialog shows them (see Showing the recovery key). The user guide's "Chat encryption" page (under end users) tells users what the key unlocks and what is encrypted.
- Element may offer to reset the encryption identity instead. Whether the homeserver lets it depends on
how Element signed in. Tuwunel (since 1.6.0, so 1.9.x included) runs its own OAuth server whenever an
identity provider and
well_known.clientare configured, and Element versions with next-generation authentication (MSC2965) sign in through it. For such a session Tuwunel allows the reset once the user signs in at the IdP again (MSC4312). A session that signed in through the older SSO redirect (m.login.sso) has to answer with the account's password, which SSO users do not know (Waldur registers every account with a random one), so it cannot reset. (Tuwunel offers single sign-on for that prompt only to accounts it registered itself at an SSO login with a single identity provider; the accounts Waldur provisions are not among them.) Either way, the recovery key Waldur shows is how to open the user's history in Element; tell users not to reset elsewhere unless every key is lost. A reset replaces the identity whose recovery key Waldur holds and deletes the user's key backup. Element then shows a new recovery key, and the drawer asks for it once on its next session (see Locked identities); until the user enters it, chat in Waldur stays locked. - Disabling a user at the IdP stops new SSO logins only. An Element session that is already signed in stays valid until it is signed out; deactivate the user in Waldur to end it.
- Deactivating or deleting a user in Waldur signs out every device, Element included, and locks their Matrix account, which refuses new SSO logins too. Locking needs the bot to be a homeserver admin (see Making the bot a homeserver admin). Until it is, the account stays unlocked and the user can still sign in over SSO, to an account without Waldur's project rooms, so disable them at the IdP as well. See Automatic member management.