Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Legacy Authentication

By default, registration is disabled. You must explicitly enable it and choose what conditions, if any, a prospective user must meet before an account is created.

Enabling registration

Set allow_registration = true to enable registration. On its own this is not enough; you must also configure at least one of the following:

  • A registration token (recommended)
  • Required email at registration, with an SMTP connection_uri set
  • The open-registration confirmation flag (not recommended)

Password registration also needs login_with_password left at its default of true. With it disabled, only identity providers can register new accounts.

Token-based registration

A registration token acts as a shared secret that prospective users must supply when creating an account. This is the recommended approach for private or invite-only servers.

Static token — set a single token directly in the config:

allow_registration = true
registration_token = "o&^uCtes4HPf0Vu@F20jQeeWE7"

File-based tokens — read tokens from a file, one per line or separated by whitespace. Useful for rotating tokens without restarting the server:

allow_registration = true
registration_token_file = "/etc/tuwunel/.reg_tokens"

Both options can be set at the same time; tokens from both are accepted.

Admin-issued tokens — generate short-lived or single-use tokens from the admin room without touching the config file:

CommandDescription
!admin token issueIssue a token with no restrictions.
!admin token issue --onceIssue a single-use token (shorthand for --max-uses 1).
!admin token issue --max-uses <N>Issue a token that expires after N uses.
!admin token issue --max-age <duration>Issue a token that expires after a duration (e.g. 30m, 7d).
!admin token revoke <token>Revoke a token immediately.
!admin token listList all active tokens.

Open registration

To allow anyone to register without a token, you must set an additional confirmation flag that acknowledges the abuse risk:

allow_registration = true
yes_i_am_very_very_sure_i_want_an_open_registration_server_prone_to_abuse = true

This is not recommended for public-facing servers. Consider token-based registration or SSO providers instead.

Email verification

Tuwunel can verify that a user controls an email address by emailing a single-use confirmation link through your own SMTP relay. No external identity server is involved; each verified address binds locally to one account. Email is the only supported medium (phone-number verification is not supported). Verified email is used for adding an address to an account, resetting a forgotten password, and optionally requiring email at registration.

Point Tuwunel at an SMTP relay and set the sender mailbox. The confirmation link is built from well_known.client, so that must also be set and reachable by your users in a browser:

[global.smtp]
connection_uri = "smtps://noreply%40example.com:password@mail.example.com:465"
sender = "Example <noreply@example.com>"

[global.well_known]
client = "https://matrix.example.com"
OptionDefaultDescription
connection_uri(unset)Connection URL for the outbound SMTP relay. Setting it enables the email subsystem; without it, no mail is sent. Use smtp:// for an unencrypted or STARTTLS connection and smtps:// for implicit TLS. Credentials and host go inline (smtps://user:pass@host:port). The userinfo is URL-encoded, so an @ in the username must be written as %40.
sender(unset)The mailbox verification messages are sent from. Accepts a bare address or a display-name form (Example <noreply@example.com>). Required whenever connection_uri is set.

The subsystem is disabled by default and stays inert until connection_uri is set. If a client asks to verify an email while it is disabled, the request is rejected with M_THREEPID_DENIED.

Requiring email at registration

These options gate registration on a verified email address. Both default to off, and both require the email verification subsystem above to be configured.

OptionDefaultDescription
require_email_for_registrationfalseRequire a verified email address to complete registration. When set, the registration flow does not finish until the user proves control of an email address.
require_email_for_token_registrationfalseRequire a verified email address when registering with a registration token. When set, token-based registration also demands a verified email address.

Guest registration

Guest accounts are anonymous sessions that some clients (e.g. Element) create automatically before a user logs in. Guest registration is separate from normal registration and is disabled by default.

OptionDefaultDescription
allow_guest_registrationfalseAllow guest account creation.
log_guest_registrationsfalseLog each guest registration to the admin room. May be noisy on public servers.
allow_guests_auto_join_roomsfalseAllow guest users to auto-join rooms listed in auto_join_rooms.

Login options

These options control which login methods are accepted regardless of how accounts were created.

OptionDefaultDescription
login_with_passwordtrueAccept username and password login. Set to false to enforce SSO-only login; password registration is then refused too, while identity providers can still register new accounts.
login_via_tokentrueAccept m.login.token login tokens. Disabling this can break SSO flows where the server issues a token to complete the login.
login_via_existing_sessiontrueAllow an authenticated session to mint a login token that a second client can use to log in. Requires interactive re-authentication. Disable if you want to prevent clients from spawning additional sessions this way.

Login rate limits

Password sign-in uses three token buckets. A refused attempt gets M_LIMIT_EXCEEDED, with a retry_after_ms unless a limit’s table is full.

  • Wrong passwords: each account and client address pair has its own budget. An attempt reserves a token before checking the password and returns it on success; wrong passwords and unknown accounts keep it. Once exhausted, that pair is refused until a token refills, including attempts with the correct password. Attempts from another address still have their own allowance. Concurrent attempts each reserve a token, so they cannot bypass the limit.
  • Client addresses: all password attempts from one address share a broader budget across accounts, charged before verification and kept on success too. This bounds password spraying and password-verification work.
  • Successful sign-ins: only a verified password consumes the account’s sign-in budget. Wrong guesses never consume it, but an account that has signed in too often is refused even with the correct password.

Public /login and the built-in OIDC login page share the first two budgets. Password re-entry for sensitive actions (UIAA) has separate failed-attempt and address budgets with the same settings, so public login attempts cannot exhaust its allowance. The successful-sign-in budget does not apply to UIAA. LDAP binds made by /login remain outside these limits; an account not found in LDAP that falls back to local password checking is limited.

IPv4 addresses have individual budgets. IPv4-mapped IPv6 addresses use their IPv4 identity, and other IPv6 addresses share budgets within each /64. Clients sharing a NAT address also share its address budget. By default the address comes from the socket peer. A loopback peer, such as a reverse proxy connecting over loopback or any client of the Unix socket, stands for every client behind it, so its attempts are not limited per address and keep only the failed-attempt and successful-sign-in limits. Behind a reverse proxy, configure http.ip_source, restrict backend access to trusted proxies, and have the proxy replace the selected forwarding header with a verified address; this also applies the address budget behind a local proxy or the Unix socket. Do not accept client-supplied forwarding headers unchanged. A proxy that connects from a non-loopback address, including a container on a bridge network, gives all its users one address and allowance unless it forwards the client address. Password login and password UIAA require the selected source even for loopback peers and peers listed in http.ip_source_trusted_subnets; they do not use those peers’ usual extraction bypass. A missing or invalid selected source refuses authentication. At startup and on reload, a warning says when a Unix socket or loopback listener has no per-address limit.

Each limit has its own config section, shown here with its defaults:

[global.rate_limiting.login.failed]
per_second = 0.17
burst_count = 3

[global.rate_limiting.login.account]
per_second = 0.003
burst_count = 5

[global.rate_limiting.login.address]
per_second = 1.0
burst_count = 20

The failed-attempt budget allows three wrong passwords per account/address pair, then about one attempt every six seconds. The address budget allows 20 attempts across accounts, then one per second. The account budget allows five successful sign-ins, then about one every five and a half minutes. Setting either burst_count or per_second to 0 disables that limit.

Separating addresses prevents guesses from one address from exhausting an account’s allowance at another address. It also means distributed guesses from different addresses have separate failed-attempt budgets. Users sharing an address or IPv6 /64 can still affect one another. Existing sessions and non-password login methods (m.login.token, SSO and JWT) are unaffected.

Each table holds at most 65536 entries in memory and resets on restart. Fully refilled buckets can be removed to make room; buckets still limiting are retained. Full failed-attempt and address tables admit untracked pairs and addresses until room frees up, while retaining limits for existing entries. A full successful-sign-in table refuses untracked accounts. Table exhaustion logs a warning.

Token and session lifetimes

OptionDefaultDescription
login_token_ttl120000Lifetime of m.login.token tokens in milliseconds (default: 2 minutes).
access_token_ttl604800Lifetime of access tokens in seconds for clients that support refresh tokens. After expiry the client is soft-logged-out until it refreshes (default: 7 days).
openid_token_ttl3600Lifetime of OpenID 1.0 tokens in seconds. These are used for Matrix account integrations such as Vector Integrations in Element, not for OIDC/OpenID Connect logins (default: 1 hour).

Emergency password

The emergency password lets you log in to the server bot account (@conduit:<server_name>) when normal access is unavailable — for example, if you have lost access to your admin room.

emergency_password = "F670$2CP@Hw8mG7RY1$%!#Ic7YA"

Remove this option and restart the server once you have regained access — all sessions for the bot account are logged out when it is unset. See the troubleshooting guide for other recovery methods.