Skip to content

Request authentication

Every client that connects to Stalwart must prove which account it acts for before it can read or change any data. This applies to every kind of client: a mail application, a calendar client, the WebUI and a script that calls the management API. The proof is a credential, and the way a client presents it depends on the protocol it speaks. This page describes the credentials the server accepts, how each protocol carries them and what the server does when authentication fails.

Authentication answers only the question of who the client is. The account model behind it is described in Accounts. The separate question of what an authenticated account may do is answered by Authorization.

The server accepts five kinds of credential, which fall into two families. Passwords and app passwords are presented together with an account name. API keys and access tokens are bearer credentials: whoever holds one is treated as its owner, and no account name accompanies it. The table compares them:

CredentialPresented asAccepted on
PasswordAccount name and passwordEvery protocol
App passwordAccount name and a password of the form app_...Every protocol
API keyBearer token of the form API_...HTTP; OAUTHBEARER and XOAUTH2 on the mail protocols
OAuth access tokenBearer tokenHTTP; OAUTHBEARER and XOAUTH2 on the mail protocols
Access token of an external identity providerBearer tokenHTTP; OAUTHBEARER and XOAUTH2 on the mail protocols

Where the account lives decides who checks the password. In most cases the server verifies passwords and app passwords itself. The exception is an LDAP directory in bind mode, which verifies the passwords of its own accounts. For an account of an LDAP or SQL directory in comparison mode, the directory returns a hash and the server compares the password with it.

Access tokens of an external provider are accepted only for domains served by an OpenID Connect directory. SCIM provisioning requests need no special treatment, because they authenticate like any other HTTP request.

Two permissions apply to sign-ins. The first is authenticate, which every credential requires, so disabling it suspends all sign-ins of an account at once (Managing accounts). The second is authenticateWithAlias, which lets a user sign in with an alias address of the account as well as with its primary address. The default User role includes it.

The mail protocols (IMAP, POP3, SMTP and ManageSieve) carry credentials in SASL mechanisms. SASL is the authentication framework these protocols share, and each mechanism defines one way of encoding a credential. Two groups of mechanisms matter here:

  • PLAIN, and on SMTP also LOGIN, transmit the account name together with a password or app password.
  • OAUTHBEARER (RFC 7628) and XOAUTH2 transmit a bearer token.

HTTP services use the Authorization header instead. Its Basic scheme carries passwords and app passwords, and its Bearer scheme carries tokens and API keys.

Which mechanisms a client sees depends on whether the connection is encrypted. By default the server offers no mechanism on a cleartext connection, so that no password crosses the network unprotected. The table shows what each protocol offers in each case:

ProtocolWith TLSWithout TLS, defaultWithout TLS, plain-text authentication allowed
IMAPPLAIN, OAUTHBEARER, XOAUTH2, LOGIN commandNonePLAIN, LOGIN command
POP3PLAIN, OAUTHBEARER, XOAUTH2, USER/PASSNonePLAIN, USER/PASS
ManageSievePLAIN, OAUTHBEARER, XOAUTH2NonePLAIN
SMTPPLAIN, LOGIN, OAUTHBEARER, XOAUTH2 on ports other than 25NoneThe password mechanisms returned by saslMechanisms

For IMAP, POP3 and ManageSieve, the decision to allow passwords without TLS is made with allowPlainTextAuth on the Imap singleton. On a new installation it is disabled, and while it is disabled no mechanism at all is offered on a cleartext connection.

SMTP makes the same decision through an expression. The mechanisms it offers are those returned by the saslMechanisms expression of MtaStageAuth. The default expression offers the four mechanisms on TLS connections to ports other than 25, and no authentication otherwise (SMTP authentication).

Bearer tokens require TLS on the mail protocols

Section titled “Bearer tokens require TLS on the mail protocols”

Bearer credentials follow a stricter rule than passwords. On IMAP, POP3, SMTP and ManageSieve, OAUTHBEARER and XOAUTH2 are neither offered nor accepted on a connection without TLS. The rule covers every bearer credential these mechanisms carry, API keys included. Neither allowPlainTextAuth nor the SMTP expression relaxes it.

A proxy that terminates TLS must tell the server that the client’s connection was encrypted. The connection counts as TLS only when the proxy sends a PROXY protocol version 2 header that carries the SSL TLV with the PP2_CLIENT_SSL flag. A version 1 header, or a version 2 header without the TLV, counts as cleartext.

The check is skipped in two special modes. The first is bootstrap mode, which runs the setup wizard on a new installation. The second is recovery mode, the maintenance mode for repairing a configuration.

A token used with these mechanisms must also carry the mail scope, the OAuth grant of access to mail. A token without it fails with insufficient_scope. API keys have no scopes, so they pass this check.

When a bearer mechanism fails, the server tells the client why before it rejects the attempt. It first sends a JSON error document that describes the failure, in the RFC 7628 format for OAUTHBEARER and in the XOAUTH2 format for XOAUTH2. It then sends the protocol’s failure reply (Mail, calendar and contacts clients).

An account with two-factor authentication needs a one-time code in addition to its password. Only the sign-in form of the OAuth server has a field for that code. Once two-factor authentication is enabled, a password alone therefore no longer works on IMAP, POP3, SMTP, ManageSieve or HTTP Basic, and applications must sign in through OAuth or use an app password. Two-factor authentication is available for accounts of the internal directory only.

The settings that apply to every sign-in are kept on one object, the Authentication singleton (found in the WebUI under Settings › Authentication › General). It decides:

  • Which directory verifies passwords by default (directoryId). The internal directory is used when the field is empty.
  • The password policy.
  • The default limits on app passwords and API keys.
  • The default roles assigned to users, groups, tenant administrators and administrators (Roles).

In the Enterprise edition, a domain can name its own directory, which then takes precedence over the default (Directories).

When accounts are owned by an external system, the server learns about them in one of two ways: through the directory, or through SCIM. Provisioning models compares the two.

The server answers a failed attempt in a way that gives an attacker as little information as possible. The reply comes after a random delay of up to half a second, so that response times do not reveal whether an account exists. The reply also does not say which part of the credential was wrong.

Failed attempts are counted per client IP address and per account name. An address that exceeds the configured rate is banned by the automatic ban mechanism. IMAP, POP3, ManageSieve and SMTP add a second limit within each session, and close the session after a number of failures in it.

Each failure is recorded as an event (Events):

  • A failed attempt produces auth.failed, logged at the debug level.
  • A correct password without the required one-time code produces auth.mfa-required, at the trace level.
  • A ban produces security.authentication-ban.