Environment Details
- ABP Studio Version: 2.2.6
- UI Framework: Blazor Server
- Architecture: Tiered
- Identity Server: OpenIddict
- Database: SQL Server (Separate Tenant Schema)
- Distributed Event Bus: RabbitMQ
- Template: app
- Created ABP Studio Version: 1.0.2
- Current ABP Studio Version: 2.2.6
- Tiered: Yes
- Multi-Tenancy: Yes
- UI Framework: blazor-server
- Theme: leptonx
- Theme Style: system
- Theme Menu Placement: side
- Database Provider: ef
- Database Management System: sqlserver
- Separate Tenant Schema: Yes
- Create Initial Migration: Yes
- Run Db Migrator: Yes
- Mobile Framework: maui
- Public Website: Yes
- Social Login: Yes
- Include Tests: Yes
- Kubernetes Configuration: No
- Distributed Event Bus: rabbitmq
- Use Local References: No
- Optional Modules:
- GDPR
- FileManagement
- TextTemplateManagement
- LanguageManagement
- AuditLogging
- Chat
- OpenIddictAdmin
- Selected Languages: English, English (United Kingdom), 简体中文, Español, العربية, हिन्दी, Português (Brasil), Français, Русский, Deutsch (Deuthschland), Türkçe, Italiano, Čeština, Magyar, Română (România), Svenska, Suomi, Slovenčina, Íslenska, 繁體中文
- Default Language: English
- Create Command: abp new NewApp -t app --tiered --ui-framework blazor-server --mobile maui --database-provider ef --database-management-system sqlserver --theme leptonx --separate-tenant-schema --public-website --without-cms-kit --dont-run-bundling -chat -file-management
Ticket Description
Subject: Password change for Tenant User via Host Admin UI does not persist or sync with AuthServer
Description: When changing a Tenant's user password through the Host Admin UI, the system returns a success notification, but the authentication process still requires the old password.
Steps to Reproduce (as shown in attached images)
Logged in as Host Admin, navigated to the Tenant's user management, and updated the password to
Password_B. A success toast message was displayed.

Attempted to log in using the new
Password_B. The system returned an "Invalid username or password" error.

Attempted to log in using the old
Password_A. The login was successful, proving the update was not effectively persisted in the authentication layer.

Expected Behavior
The old password should be invalidated immediately, and the new password should be required for all subsequent login attempts.
7 Answer(s)
-
0
- In a tiered + separate AuthServer solution, the login password is validated by the AuthServer’s Identity database, not by the Blazor (UI) or HttpApi.Host database.
- With Separate Tenant Schema, it’s possible to end up changing the password in a different database/schema than the one the AuthServer is actually using for that tenant (or changing it under the wrong tenant context). The UI can still show “Saved successfully” because the SaaS operation succeeded, but the AuthServer still has the old hash, so
Password_Akeeps working.
Fix (recommended): ensure the password is set in the AuthServer’s Identity DB under the target tenant context
- In your Host Admin UI, when you “Set password” for a tenant user, call an endpoint that runs in the AuthServer (or a shared application contract implemented in AuthServer), not only in the UI/host side.
- In that endpoint, wrap the operation with the correct tenant:
using (CurrentTenant.Change(targetTenantId)) { // set password for the tenant's admin/user via IdentityUserManager/UserAppService // (this ensures it updates the tenant's identity store that AuthServer uses) }- If you are using a SaaS tenant password operation (like “Set password” on tenant), replace/override the relevant SaaS app service and ensure it validates/sets the password in the correct context. ABP support confirms SaaS and Identity are separate concerns and customization is required in such scenarios; example replacement is shown in the verified ticket below.
Verification steps
- After applying the fix, directly check the AuthServer database for the tenant’s
AbpUsers.PasswordHash(in the tenant schema) and confirm it changes when you set the password from Host. - Then login should immediately require
Password_B.
—
Sources (verified)- https://abp.io/support/questions/9002
- https://abp.io/docs/latest/modules/saas
This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
Hi,
I am requesting a review from a human support agent, as the AI-generated response suggests a manual fix/workaround for what appears to be a fundamental bug in the standard ABP Studio template.
To clarify:
I have no customizations: This is a clean, unmodified application generated directly via ABP Studio (version 1.0.2).
Standard Feature Failure: The "Set Password" functionality for Tenant Users via the Host UI is a built-in feature of the SaaS/Identity modules.
Best regards.
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
Hi,
The "Set Password" from the Tenant management page works through a distributed event internally — the UI shows success as soon as the event is published, but the actual password change happens asynchronously in a background handler. So the success toast doesn't necessarily mean the password was actually changed.
Could you check the logs of your HttpApi.Host and AuthServer after attempting the password change? Look for any of these messages:
User password changed: admin— means it actually workedUser password change failed: admin— password validation errorAn error occurred while handling UserPasswordChangeRequestedEto— exception during processing- If none of these appear, the event was never processed at all
You can share the relevant logs(Logs.txt) to liming.ma@volosoft.com if that's easier.
Thanks
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
Hi @maliming,
Thanks for the clarification regarding the distributed event background process. I investigated the application logs as you suggested and found the root cause of the issue.
Findings
There is a password complexity validation enforcing in the background when trying to change the password. This validation is enforcing the use of non-alphanumeric characters. However, I realized several inconsistencies in how the standard ABP platform handles this:
1. Missing UI Feedback
The front-end does not display the result of this validation. It simply shows a success toast because the event was published, misleading the user.
2. Configuration Ignored
As shown in the bellow attached image, the current tenant configuration does not require non-alphanumeric characters (it only requires a minimum of 6 characters). The system should accept a simple password based on these settings.

3. Inconsistent Validation (Creation vs. Update)
When creating a brand new tenant, the system does not enforce a complex password for the new admin. It creates the user without any restrictions. The strict validation only occurs when the Host Admin tries to change a Tenant Admin password later.

Tests Performed
To validate this behavior, I ran the following tests:
Test 1 (Failed): Using the password
CafeForte456(no special characters). The log shows a failure, and the password is not changed.
Test 2 (Success): Using the password
CafeForte@456(with a special character). The password updates successfully.
It seems to be a bug in the business rules enforcing a condition that is not required in the Tenant settings.
Looking forward to your feedback.
Best regards.
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
Hi,
Thank you so much for the detailed investigation, this is very helpful. You're absolutely right — I've confirmed this is a bug in our Pro
UserPasswordChangeRequestedEventHandler.The root cause is that this handler does not call
await IdentityOptions.SetAsync();before validating the password.SetAsync()is what loads the tenant-specific identity settings (password policy, lockout, etc.) into theIdentityOptionsinstance. Without it, the handler falls back to ASP.NET Core Identity's default policy, which requires digit, uppercase, lowercase and non-alphanumeric characters — exactly what you observed. Other places likeIdentityUserAppService.UpdatePasswordAsyncdo callSetAsync(), so only this distributed event handler is affected.We'll fix it in the next version by adding the
SetAsync()call at the beginning ofHandleEventAsync.Temporary workaround
You can replace the buggy handler in your
*.Domainproject by doing two things:1. Add a replacement handler class in your
*.Domainproject:using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Options; using Volo.Abp.DependencyInjection; using Volo.Abp.EventBus.Distributed; using Volo.Abp.Identity; using Volo.Abp.Users; namespace MyCompanyName.MyProjectName.Identity; public class MyUserPasswordChangeRequestedEventHandler : IDistributedEventHandler<UserPasswordChangeRequestedEto>, ITransientDependency { public ILogger<MyUserPasswordChangeRequestedEventHandler> Logger { get; set; } protected IIdentityUserRepository UserRepository { get; } protected IdentityUserManager IdentityUserManager { get; } protected IOptions<IdentityOptions> IdentityOptions { get; } public MyUserPasswordChangeRequestedEventHandler( IIdentityUserRepository userRepository, IdentityUserManager identityUserManager, IOptions<IdentityOptions> identityOptions) { Logger = NullLogger<MyUserPasswordChangeRequestedEventHandler>.Instance; UserRepository = userRepository; IdentityUserManager = identityUserManager; IdentityOptions = identityOptions; } public async Task HandleEventAsync(UserPasswordChangeRequestedEto eventData) { try { await IdentityOptions.SetAsync(); if (!eventData.Password.IsNullOrEmpty()) { var user = await UserRepository.FindByTenantIdAndUserNameAsync(eventData.UserName, eventData.TenantId); if (user != null) { var errors = await ValidatePasswordAsync(user, eventData.Password); if (errors.Any()) { Logger.LogError("User password change failed: {userName}, reason: {reason}", eventData.UserName, string.Join(";", errors.Select(e => e.Code))); } else { (await IdentityUserManager.RemovePasswordAsync(user)).CheckErrors(); (await IdentityUserManager.AddPasswordAsync(user, eventData.Password)).CheckErrors(); Logger.LogInformation("User password changed: {userName}", eventData.UserName); } } } } catch (Exception e) { Logger.LogError("An error occurred while handling UserPasswordChangeRequestedEto: {message}", e.Message); Logger.LogException(e); } } private async Task<List<IdentityError>> ValidatePasswordAsync(IdentityUser user, string password) { var errors = new List<IdentityError>(); foreach (var v in IdentityUserManager.PasswordValidators) { var result = await v.ValidateAsync(IdentityUserManager, user, password); if (!result.Succeeded && result.Errors.Any()) { errors.AddRange(result.Errors); } } return errors; } }2. Unsubscribe the original handler in your
*.Domainmodule'sConfigureServices:public override void ConfigureServices(ServiceConfigurationContext context) { Configure<AbpDistributedEventBusOptions>(options => { options.Handlers.Remove<UserPasswordChangeRequestedEventHandler>(); }); // ... your other configurations }The
Removecall runs afterAbpEventBusModulehas populated the handlers list, so only your new handler will be subscribed toUserPasswordChangeRequestedEto. After this, theSet Passwordaction from the Tenant management page will respect your tenant's password policy and actually change the password.Regarding your other two points:
- Missing UI feedback: you're right, it's a limitation of the fire-and-forget distributed event pattern used by
Set Password. The UI can't tell whether the background handler succeeded. We'll review this separately. - Inconsistent validation on tenant creation: the initial admin user is created through the data seeder which doesn't run
PasswordValidators, which is why a simple password is accepted at creation time. We'll revisit this to make the behavior more consistent.
Thanks again for the great bug report! Your ticket has been refunded. 👍
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) - Missing UI feedback: you're right, it's a limitation of the fire-and-forget distributed event pattern used by
-
0
Hi @maliming,
Thank you for the clarification on this issue — I really appreciate your assistance.
We’ve decided not to change anything in the code for now and will wait for the bug to be fixed in a future release. In the meantime, we are implementing an internal procedure to address the password‑complexity requirement, even though this setting is disabled in the tenant configuration. Your well‑documented workaround may still be helpful for others who choose to apply it in their environments.
Have a great day!
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
Hi,
Thanks for the update, glad to hear you have an internal procedure in place for now. The fix is already merged and will ship in the next release, so you can drop the workaround once you upgrade.
Thanks
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
