Issue Description
We found a case where a valid OIDC-authenticated user could not load the Stalwart WebUI account page because /jmap/session returned 401, even though the same
bearer token worked for other authenticated endpoints.
Environment/context:
- Stalwart v0.16.2
- Stalwart WebUI via OIDC
- OIDC directory provider
- User could authenticate successfully through OIDC
- The issue affected one user only
- Other users using the same OIDC provider and WebUI client worked correctly
Observed with the same bearer token:
- GET /auth/userinfo returned 200
- GET /api/account returned 200
- GET /api/schema returned 200
- GET /jmap/session returned 401
The browser then displayed a Basic auth popup because /jmap/session returned:
WWW-Authenticate: Bearer realm=“Stalwart Server”, Basic realm=“Stalwart Server”
After investigation, the affected primary account id was 17. The ACL store contained stale ACL rows granting account 17 access to deleted account ids 39 and 40.
Those account ids no longer existed.
Removing only those stale ACL rows fixed the issue immediately. The same user and same OIDC flow could then load /jmap/session successfully.
Expected Behavior
A valid authenticated user should be able to load /jmap/session for their own account even if a stale ACL/share reference exists for a deleted secondary/shared
account.
Expected behavior would be one of:
- Account deletion removes all ACL/share rows referencing the deleted account.
- /jmap/session ignores missing secondary/shared account ids and logs a warning.
- Stalwart returns a data consistency/internal error if the stale ACL is considered fatal.
The request should not return 401 Unauthorized, because the primary user is already authenticated and other authenticated endpoints accept the same bearer token.
Relevant documentation:
- JMAP: Overview | Stalwart
- OIDC directory/auth configuration, if applicable to this issue.
Actual Behavior
The affected user authenticated successfully, but /jmap/session returned 401 Unauthorized.
Other authenticated endpoints worked with the same bearer token:
/auth/userinfo → 200
/api/account → 200
/api/schema → 200
/jmap/session → 401
This caused the Stalwart WebUI account page to fail and the browser to show a Basic auth popup.
The root cause appeared to be stale ACL rows referencing deleted account ids. Once those stale ACL rows were removed, /jmap/session returned 200.
Reproduction Steps
Approximate reproduction steps:
- Configure Stalwart v0.16.2 with an OIDC directory provider and WebUI OIDC login.
- Create a user account. In our case, the affected account id was 17.
- Create/share resources so that the user receives ACL access to other accounts.
- Delete the shared/secondary accounts without all ACL rows being removed.
- Authenticate as the primary user through OIDC.
- Call authenticated endpoints with the resulting bearer token:
- GET /auth/userinfo
- GET /api/account
- GET /api/schema
- GET /jmap/session
- Observe that /auth/userinfo, /api/account, and /api/schema return 200, while /jmap/session returns 401.
In our live system, the stale ACL rows were:
grant account: 17 → deleted owner account: 39
grant account: 17 → deleted owner account: 40
Removing only those stale ACL rows fixed the problem.
Relevant Log Output
Older debug logs indicated that /jmap/session was failing while trying to load a missing secondary account id:
accountId = 39
causedBy principals.rs:308
causedBy jmap/src/api/session.rs:63
HTTP behavior observed:
GET /auth/userinfo 200
GET /api/account 200
GET /api/schema 200
GET /jmap/session 401
WWW-Authenticate: Bearer realm=“Stalwart Server”, Basic realm=“Stalwart Server”
Stalwart Version
v0.16.x
Installation Method
Docker
Database Backend
RocksDB
Blob Storage
Filesystem
Search Engine
Meilisearch
Directory Backend
OIDC
Additional Context
This issue looked like an OIDC/authentication problem at first, but the token was valid. The failure was specific to /jmap/session, which appears to expand
secondary/shared account ids.
The likely hardening gaps are:
- Account deletion may leave stale ACL rows behind.
- /jmap/session fails the entire authenticated session when a secondary/shared account id no longer exists.
- The failure is returned as 401 Unauthorized, which misleads operators and browsers into treating it as an authentication problem.
I have reviewed the documentation and FAQ and confirm that my issue is NOT addressed there.
on
I have searched this support forum (open and closed topics) and confirm this is not a duplicate.
on
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