Skip to content

Permissions

Permissions are how Stalwart decides whether an authenticated account may do what it asks. A permission authorizes one kind of action: signing in, sending mail, calling a JMAP method, reading or changing a configuration object, or running a task. An account may perform an action only if its effective permissions contain the permission for that action.

An account rarely receives its permissions one by one. Most come from roles, which bundle permissions under a name. Permissions can also be set directly on accounts and groups, and in the Enterprise edition they are capped by tenants. This page describes how the server combines these sources into the effective permissions, and which permissions an administrator typically assigns by hand. The permission reference lists every permission with its description.

There are many permissions, but their names follow a fixed pattern. The permission that guards an action can therefore be derived from the action itself:

  • Configuration objects are guarded by sys<Object><Operation>. The operations are Get, Create, Update, Destroy and Query, and singletons have only Get and Update. Creating a Domain, for example, requires sysDomainCreate, and changing the OidcProvider singleton requires sysOidcProviderUpdate.
  • Each kind of task and action has its own permission, task<Variant> or action<Variant>, for example actionReloadSettings.
  • Protocol operations carry the protocol in the prefix: imap* for IMAP commands (imapAppend, imapFetch), pop3*, jmap* for JMAP methods (jmapEmailGet, jmapMailboxCreate), dav* for WebDAV, CalDAV and CardDAV requests, sieve* for ManageSieve, calendar* for calendar notifications and scheduling, and email* for sending and receiving mail (emailSend, emailReceive).
  • A small number of permissions stand alone, such as authenticate and impersonate, which are described below.

The effective permissions of an account are the set the server actually checks. It computes them in this order:

  1. The permissions of the account’s roles are combined. Roles can include other roles, and the permissions of those are included too.
  2. The account’s own permissions field is applied according to its mode.
  3. In the Enterprise edition, the result is restricted to the permissions of the account’s tenant.
  4. Every permission disabled at any of these levels is removed.

The second step depends on a decision made for each account: how its own permissions relate to those of its roles. The permissions field of an Account, and of a Tenant, records that decision as one of three modes:

  • Inherit leaves the decision to the roles, so the account has exactly the permissions its roles grant.
  • Merge keeps the permissions of the roles and adds the ones listed in enabledPermissions, for an account that needs a few extra rights.
  • Replace ignores the roles, and only enabledPermissions applies, for an account whose permissions must be listed explicitly.

In Merge and Replace mode, disabledPermissions lists permissions to remove. A disabled permission takes precedence over every source, including roles and the tenant. This precedence is what makes it possible to suspend an account without changing its roles.

The following value gives an account the permissions of its roles plus impersonate, but takes away emailSend:

{
"permissions": {
"@type": "Merge",
"enabledPermissions": {"impersonate": true},
"disabledPermissions": {"emailSend": true}
}
}

A single request can carry fewer permissions than its account. This happens in three cases, each of which can narrow the permissions but never extend them:

  • App passwords and API keys have their own mode, Inherit, Disable or Replace, which can remove permissions but never add any.
  • A token issued to an OAuth application other than a first-party client is limited to the permissions mapped to its scopes. These never include management (sys*), telemetry, SCIM or administration.
  • A token of an external identity provider that carries scopes is limited in the same way.

Changes to roles, permissions, group memberships or the tenant take effect without a new sign-in (Roles).

The server creates four roles on first start. They contain these permissions:

RolePermissions
Userauthenticate, authenticateWithAlias; every protocol permission (jmap*, imap*, pop3*, dav*, sieve*, calendar*, email*); the self-service objects sysAccountPassword*, sysAccountSettings*, sysApiKey*, sysAppPassword*, sysPublicKey*, sysMaskedEmail*, sysArchivedItem*, the sysOAuthGrant* permissions for listing and revoking connected applications, reading and deleting spam training samples; interactAi
GroupEvery protocol permission, the sysAccountSettings*, sysPublicKey*, sysMaskedEmail* and sysArchivedItem* permissions, and reading and deleting spam training samples
Tenant Administratorauthenticate, authenticateWithAlias, fetchAnyBlob, liveDeliveryTest, interactAi, and the management of domains, DKIM signatures, ACME providers, accounts, roles, OAuth clients, mailing lists, external reports, DNS servers and queued messages (sysDomain*, sysDkimSignature*, sysAcmeProvider*, sysAccount*, sysRole*, sysOAuthClient*, sysMailingList*, sysExternalReport*, sysDnsServer*, sysQueuedMessage*)
System AdministratorEvery permission except the protocol permissions

Neither administrator role contains the protocol permissions. An administrator account therefore also receives the User role, and the defaults provide it: roles: Admin applies System Administrator together with User, and a tenant administrator receives Tenant Administrator together with User. Tenant administrators exist only in deployments with tenants, an Enterprise feature.

Most permissions reach an account through its roles. A few are the exception, because administrators most often add them to, or remove them from, individual accounts, custom roles or credentials:

PermissionEffect
authenticateSign in with any credential. Disabling it suspends all sign-ins of the account.
authenticateWithAliasSign in with an alias address of the account as well as its primary address.
emailSend, emailReceiveSubmit mail through SMTP or JMAP; receive mail at the account’s addresses.
impersonateAccess any account’s data and act on its behalf, through master-user sign-in and through the accountId of JMAP requests. Superusers hold it.
unlimitedRequests, unlimitedUploadsBypass the request rate limits and the upload size and rate limits, for example for migration accounts.
fetchAnyBlobDownload any blob by id, even one not owned by the account.
liveDeliveryTestRun the delivery test in the WebUI troubleshooting tools.
liveTracing, liveMetricsView live event traces and metrics.
scimAccessUse the SCIM provisioning endpoint.
interactAiUse the AI features that send content to an AI model.

An account that can manage users could, without a further rule, create an account more powerful than itself, or take one over. The server prevents this with a rule that applies to every change to an account. Creating, changing or deleting an account requires the sysAccountCreate, sysAccountUpdate or sysAccountDestroy permission. In addition, the caller must hold every effective permission of the target account. An account can therefore grant only permissions it holds itself.

The rule applies everywhere accounts are changed: the management API, the WebUI, the CLI and SCIM provisioning. It has no exception for superusers.

A request that breaks the rule fails with the JMAP error forbidden, in notCreated, notUpdated or notDestroyed, or with HTTP status 403 on SCIM. The description names up to five of the missing permissions:

You are not authorized to grant permissions: impersonate, unlimitedRequests, unlimitedUploads, fetchAnyBlob, liveDeliveryTest and <N> more

The caller’s permissions are those of the credential it presented, which are not always those of its account. A password carries the permissions of its account, and so does an app password or API key in Inherit mode. In Disable mode the listed permissions are removed, and in Replace mode only the listed permissions that the account holds are kept.

The rule has these consequences in practice:

  • A help-desk role with sysAccountUpdate and the User permissions can reset the password of ordinary users, but not of administrators.
  • A credential restricted to account management, for example an API key in Replace mode with only sysAccount* permissions, cannot manage ordinary users, because users hold every protocol permission of the User role. Use a credential in Inherit or Disable mode on an account that holds the User permissions as well.
  • An account that manages administrators must hold the administrators’ permissions.
  • Tenant administrators can manage the accounts of their tenant, because their roles include the User permissions.

SCIM configuration describes what this means for provisioning credentials.

Permissions decide which kinds of actions an account may perform. They do not decide which mailboxes, calendars, address books or folders of other accounts it may reach. That is decided by access control lists, which the owner of each resource sets when sharing it, through IMAP ACL, JMAP sharing or WebDAV ACL (Sharing).

An account needs both kinds of authorization. Opening a mailbox that another account owns over IMAP requires the imapSelect permission, which is needed to open any mailbox, and an access control entry on that mailbox.