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