Stalwart w/ external IdP, configured with requireAudience or requireScopes, can cause the webui to reject logins

Issue Description

Upfront: I’m unsure if this counts as a feature request or bug report. I filed it here because it involves a protocol (RFC 8707) that is implemented in stalwart’s internal IdP, but is not extended to external IdPs, which results in unexpected auth failures under intuitive configurations.

tl;dr: when trying to use multiple OAuth registrations, at an external OIDC, with requireAudience set, the OIDC directory can mint a valid token for the WebUI, but Stalwart rejects it because the token does not contain the required API audience.

Stalwart’s external OIDC directory supports requireAudience and requireScopes, which reject access tokens unless their aud claim and required scopes match the configured values. The Stalwart WebUI is an OAuth client of the same identity provider, and Stalwart validates its access tokens using that external OIDC directory. However, the WebUI has no runtime way to request the audience/resource required by Stalwart, nor any way to discover which value the server requires.
The problem occurs when:

  • Accounts are authenticated via an external OIDC directory.
  • requireAudience and/or requireScopes is configured on that directory.
  • Those accounts sign in to the Stalwart WebUI.
  • The WebUI’s token either has an audience different from requireAudience or lacks one or more required scopes. This occurs when you try to use different OAuth client registrations for the WebUI and jmap client.

In that case, WebUI login fails, while JMAP and other clients that request the correct audience and scopes continue to function.

For example, when no resource parameter is included in the authorization request, PocketID uses the OAuth client ID as the default aud value. If the WebUI’s client ID is stalwart-webui and Stalwart is configured with requireAudience=https://jmap.example.com, then PocketID will mint a token for the webUI with aud=stalwart-webui which will be rejected by stalwart.
A straightforward fix is to allow the WebUI to discover and request the resource and scopes that Stalwart already requires. The server already has this information in the external OIDC directory configuration. So its existing discovery endpoint could add optional fields resource (RFC 8707) and required scopes. The WebUI could then consume those fields and the token minted by the IdP would be accepted by stalwart.

Stalwart already implements RFC 8707, but only for its internal authorization server. The extension to the endpoint would allow deployments to use separate OAuth client registrations for the WebUI, webmail, mobile clients, and other applications while still issuing tokens for the same Stalwart API. It would also preserve the existing behavior when no audience or scopes are configured: the new fields would simply be omitted from discovery, and existing clients would be unaffected.

Expected Behavior

When an external OIDC directory is configured with requireAudience and/or requireScopes, the Stalwart WebUI should be able to complete login using that directory.
The WebUI should discover the required resource and scopes from Stalwart, include them in its OAuth authorization and token requests, and receive an access token that satisfies the directory’s configured requirements. Stalwart should then accept the token and complete the login.

Actual Behavior

When the WebUI and JMAP use separate OAuth client registrations, the WebUI cannot request the API resource required by Stalwart. The identity provider therefore issues a token whose audience does not match requireAudience, and WebUI login fails. There is currently no runtime WebUI configuration or discovery response that provides the required resource.

Reproduction Steps

Configure an external OIDC provider with:

  • An API/resource identifier, for example https://mail.example.com.
  • A permission/scope, for example mail.read.
  • Two separate OAuth client registrations:
    • one for the Stalwart WebUI
    • one for a JMAP or other API client.

Grant both clients access to the API resource and scope.

Configure Stalwart’s external OIDC directory with:

requireAudience=https://mail.example.com
requireScopes=mail.read

Configure the non-WebUI client to request:

resource=https://mail.example.com
scope=openid mail.read

Verify that it receives an access token whose aud contains https://mail.example.com and whose scopes include mail.read. Requests using that token should succeed.

Sign in to the Stalwart WebUI.

Inspect the WebUI’s authorization request. It does not include the configured API resource, because the WebUI has no runtime setting or discovery field from which to obtain it.

The identity provider issues an access token using its default behavior. I use PocketID, so the token audience is the WebUI’s client ID rather than the API resource.

Stalwart rejects the token because its audience does not match requireAudience, and WebUI login fails

Stalwart Version

v0.16.x

Installation Method

Binary (Linux)

Database Backend

RocksDB

Blob Storage

RocksDB

Search Engine

Internal

Directory Backend

Internal

Additional Context

I have forks of stalwart and the webui at GitHub - Sorontooo/stalwart: All-in-one Mail & Collaboration server. Secure, scalable and fluent in every protocol (IMAP, JMAP, SMTP, CalDAV, CardDAV, WebDAV). · GitHub and GitHub - Sorontooo/webui: Stalwart WebUI · GitHub that implement the fixes. I disclose that LLMs helped me diagnose the issue and implement the fixes.

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

Thanks for the detailed writeup and the reproduction steps. I checked the current OIDC directory docs and the requireAudience/requireScopes reference, and they describe the directory-side validation but do not document any mechanism for the WebUI to discover or request a specific resource/scope set from the OIDC provider at login time. There’s no discovery extension or WebUI configuration option for this in the docs I have access to.

This looks like a genuine gap rather than something already solved by an existing setting, so it’s best handled as a bug/feature report for the team to review (including your proposed discovery-endpoint extension and forks).

This isn’t covered in the current docs. A community member or staff member will follow up.

This is an automated reply from the Stalwart Help Bot. Other community members may follow up if this answer is incomplete or wrong.

Please see draft-ietf-mailmaint-oauth-public-05 - OAuth Profile for Open Public Clients and draft-ietf-mailmaint-pacc-03 - Automatic Configuration of Email, Calendar, and Contact Server Settings.
Tthe requireScopes and requireAudice settings will be deprecated in order to full comply with PACC and OAuth Public.
Is PocketID compatible with the requirement established in draft-ietf-mailmaint-oauth-public?

I believe it is mostly compatible but not completely. It supports public clients and Authorization Code + PKCE, but it does not provide the mandatory Dynamic Client Registration endpoint. it has a feature called CIMD, but I think that’s a different thing. It also does not natively expose the standardized mail/calendar scopes required by PACC.

I found this issue (🚀 Feature: Dynamic Client Registration · Issue #1517 · pocket-id/pocket-id · GitHub) that implies CIMD deprecates DCR, so they’re probably(?) unlikely to implement it. In my estimation (I am neither a pocketID developer, nor am I thoroughly versed in RFC specs), either Stalwart would need to implement CIMD, or PocketID would have to revisit implementing DCR.

Please check Stalwart v0.16.19, it now allows you to configure the OAuth client id of the WebUI. You should set requireAudience to null and remove all requiredScopes so you don’t have issues with PocketID. The next WebUI release will use resource indicators, which Stalwart already validates.

Regarding DCR, PACC requires it so if PocketID removes it, you won’t be able to authenticate using Apple Mail, Thunderbird and other mail clients once PACC is published.

I’d suggest you open an issue in the PocketID repository so they take a look at these two drafts, they are probably not aware of them. This is not an issue at the moment since OAuth support is non-existent in mail clients, but Apple will soon add PACC support to their clients.