"Account does not have a password" error when using the webui

Issue Description

I use a directory and added a second domain to my Stalwart.
Weird enough, on my domain tab it doesn’t allow me choose the directory to read from.
However, when authenticating from my e-mail client, it works normally and I can send and receive emails.
But when connecting to the /admin/login endpoint, I get this:

2026-05-30T11:33:54Z ERROR Authentication error (auth.error) listenerId = "https", localPort = 443, remoteIp = 10.11.11.111, remotePort = 52036, details = Authentication error (auth.error) { details = "Account does not have a password. If you are using an external directory, make sure to set the password attribute.", causedBy = "crates/common/src/auth/oauth/token.rs:59" }, causedBy = "crates/http/src/auth/oauth/token.rs:127"

What can be the problem?

Stalwart Version

v0.16.x

Installation Method

Docker

Database Backend

FoundationDB

Blob Storage

S3-compatible

Search Engine

Internal

Directory Backend

LDAP

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

Let me look into this error to give you an accurate answer.

The error is directly caused by the interaction between bind authentication and the WebUI’s OAuth token flow. Here’s what’s happening and how to fix it:


Root cause: Your LDAP directory is configured with bindAuthentication: true (which is the default). In this mode, Stalwart authenticates users by binding as them directly – it never reads a password hash from LDAP. However, there is a key requirement: the attrSecretChanged attribute must be properly mapped so Stalwart can track password changes and generate OAuth tokens for the WebUI login. If that attribute is missing or not returned by your LDAP server, the OAuth token path cannot find a “password” value and throws this error.

Things to check/fix in your LDAP Directory object:

  1. attrSecretChanged – This attribute (default ["pwdChangeTime"]) must be present and returned by your LDAP server for entries. If your LDAP schema uses a different attribute name for password change timestamps, update attrSecretChanged to match. For example:

    {
      "@type": "Ldap",
      "bindAuthentication": true,
      "attrSecretChanged": ["pwdLastSet"]
    }
    

    (Use whatever attribute your LDAP server actually populates for password change tracking.)

  2. Alternatively, if bindAuthentication is false (service-account hash comparison mode), ensure attrSecret points to the correct attribute that stores the password hash (default ["userPassword"]), and that your LDAP server actually returns that attribute to the service account.

Why does IMAP/SMTP work but not the WebUI? Email clients authenticate via SASL mechanisms (PLAIN, LOGIN, etc.) which go through a different code path. The WebUI login uses OAuth token issuance, which is where Stalwart needs the password hash or password-change marker to issue a token – and that’s the step that’s failing.

You can configure these settings in the WebUI under Settings > Authentication > Directories, or via the stalwart-cli.

Relevant docs: LDAP Directory – specifically the “Authentication methods” and “Object attributes” sections.

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

It is not this. I have removed the attrSecretChanged and it still worked for one mailbox, but not for the other.

Any tips here @stalwart ? This is the only missing thing for me - I wonder why some users can login and others, from another ldap tree, can’t.

The “Account does not have a password” error fires when the account is found but the directory returns no usable password for it, which for an LDAP-backed user means the directory being consulted is not the one holding that user. That lines up with your symptom: one tree’s users authenticate, the other tree’s users do not.

A couple of things to check. Choosing a different directory per domain is an Enterprise feature; in the community edition every domain resolves to the single default directory, so if the failing users live in a second LDAP that is not the default, the WebUI auth will not find their password even though IMAP/SMTP may resolve them differently. Also, there was a real bug in per-domain external directory resolution that was fixed in 0.16.7, so if you are on Enterprise and below that, upgrade first and retest.

To narrow it down: what exact 0.16.x version are you on, Enterprise or community, and is each domain meant to use its own LDAP or should one default LDAP cover both trees? Confirm the failing users’ bind returns a userPassword attribute.

Thanks for replying.

I’ll check the version, but just to let you know: it’s the same ldap for all domains, and there are no separate trees per domain.

What I do have is different account types which spans on different trees, but all within the base tree.

Yes, the userPassword attribute is there. As I said, the user authenticates normally via imap/smtp. It’s just the web interface that complains.