How to properly manage user roles/permissions via an OIDC directory (group-based, dynamic)?

Your question

Environment:

Stalwart, edition: community
Identity Provider: Authentik (OIDC)
Directory type: OpenID Connect

What I’m trying to do:

I want user roles/permissions in Stalwart to be driven dynamically by group membership in my IdP (Authentik), so that when a user is added to a group like devops on the IdP side, they automatically get the corresponding Stalwart role/permissions — without manual per-user configuration in Stalwart after every login.

Current config:

Directory (OIDC):

Type: OpenID Connect
Provider
Issuer URL: https://sso.example.com/application/o/stalwart-webui/
Required Scopes: openid, email
Claims
Username Claim: email
Groups Claim: groups

Group principal devops (id 2):

Type: Group account
Roles & Permissions
Roles:
Type: Custom role
Roles: DevOps Engineer (id: b3)
Permissions:
Type: Inherited permissions

Role DevOps Engineer (b3) — custom role with sysAccountGet, sysDirectoryGet, sysDomainGet and ~150 other sys*/action* permissions enabled.

Account (user):

Type: User account
Groups & Roles
Groups: m, 2
Roles:
Type: User role
Permissions:
Type: Inherited permissions

Decoded access token payload confirms the group claim is present and correctly received:

json
{
“groups”: [“users”, “devops”],

}

What happens:

GET /api/account with this user’s bearer token returns only the baseline consumer permission set (jmap*, imap*, emailReceive, authenticate, etc.) — none of the sys*/action* permissions from the DevOps Engineer role assigned to the devops group. Cache invalidation and a fresh authorization_code login didn’t change the result.

Questions:

  1. What is the correct/supported way to have a user’s roles/permissions be granted dynamically through an OIDC directory — i.e. without manually calling update Account --roles […] after every login? Is defaultGroupRoleIds on the Authentication singleton meant to cover this, and if so, what’s missing in the config above to make it apply?
  2. If a user is a member of a group (memberOf) and that group has a role with permissions attached — why doesn’t this merge/inherit into the effective permissions returned for the user itself? Per the docs (/docs/auth/authorization/permissions/), effective permissions are computed by “starting from the enabled permissions of any assigned roles” — is this scoped strictly to Account.roles, or does it also walk through Account.memberOf → Group.roles? Current behavior suggests the former, but it’s not stated explicitly either way in the docs.
  3. What’s the recommended pattern for keeping group-based permissions in sync dynamically in an SSO context — i.e. when group membership can change on the IdP side at any time, and I want Stalwart-side effective permissions to reflect that without manual intervention on every login? Is there a supported hook/sync mechanism, or does this require external automation reading OIDC claims and calling the management API to update Account.roles directly on each login?

I understand that topics in this category are triaged by a bot first but a human reply will follow up. If I’d prefer a human-only reply, I’ll add the no-ai tag to my topic.

on

Taking your questions in order. Effective permissions are computed from the account’s own roles (or the configured default role ids) plus the account and tenant permission layers. They do not walk group membership, so a role attached to a group is not inherited by that group’s members. What group membership does give you is mail addressing and ACL or shared-folder access, not permissions. So what you are seeing is the intended behaviour rather than a bug, and the docs are ambiguous on exactly this point, which they should not be.

defaultGroupRoleIds will not help here either: it is the default role given to a group principal itself when it has no explicit role, not a way to propagate a group’s role down to its members.

The half that does work is the sync. Your groups claim already creates and attaches the group principals on every login, so membership is current. There is no claim-to-role hook today, so making roles follow group membership means external automation calling the management API to set roles on the account, or assigning the role per account once. Worth checking which you actually need first: if the goal is shared mailbox or calendar access rather than admin permissions, group membership already covers that and no automation is needed.