Hi there. We have configured ABP’s built-in subdomain tenant resolver using AddDomainTenantResolver(...), and inbound tenant resolution works as expected. Requests to tenant subdomains correctly resolve CurrentTenant.
However, we noticed that Account module emails, like the password reset email sent when a tenant user uses “Forgot password”, do not use the tenant subdomain URL. The generated reset link points to the configured host/base URL, so the link does not work correctly for tenant users in our subdomain setup.
We found that setting the MVC application root URL to the tenant-aware template (replacing it's default value of configuration["App:SelfUrl"]) appears to solve it:
Configure<AppUrlOptions>(options =>
{
options.Applications["MVC"].RootUrl = "https://{0}.example.com";
});
Can you confirm whether configuring options.Applications["MVC"].RootUrl this way is the correct approach for tenant-aware Account email links? We could not find anything related to this in the documentation, so we want to make sure we are not doing anything we shouldn't that could cause unwanted side effects.
Thanks!
5 Answer(s)
-
0
- Yes: configuring
AppUrlOptionsis the correct/expected way to make Account module email links (forgot password / reset password / email confirmation, etc.) point to the correct UI host, including tenant-specific subdomains. - ABP’s Account emails build links via the App URL system (
AppUrlOptions+IAppUrlProvider). Ifoptions.Applications["MVC"].RootUrl(or your relevant UI key) is set to a non-tenant-aware host URL, the generated link will also be non-tenant-aware—exactly what you observed.
To make links tenant-aware for a subdomain setup, setting a template RootUrl is the right approach, e.g.:
Configure<AppUrlOptions>(options => { // Use the UI application's key that Account uses for link generation in your solution options.Applications["MVC"].RootUrl = "https://{0}.example.com"; });Notes / side effects (what to expect)
{0}is the placeholder ABP uses to inject the current tenant name when generating URLs (similar to how it’s used in the domain/subdomain tenant resolver).- This impacts only URLs generated through ABP’s URL system for that application key (including Account emails and other places that call
IAppUrlProvider), which is typically what you want in a subdomain-per-tenant setup. - If you also need to support host (no-tenant) URLs, ABP will generate host URLs when there is no current tenant (it won’t have a tenant name to substitute). In practice, many solutions handle host separately by using a non-templated RootUrl for host and a templated one for tenant scenarios; but the safe/official mechanism remains configuring
AppUrlOptions.
Sources
- https://abp.io/docs/latest/framework/architecture/multi-tenancy#domainsubdomain-tenant-resolver
- https://abp.io/support/questions/7608
- https://abp.io/docs/10.4/modules/account
- https://abp.io/docs/10.4/guides/ms-multi-tenant-domain-resolving
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) - Yes: configuring
-
0
Hi,
Yes, configuring
AppUrlOptionsis the correct and supported way to make Account email links (forgot password, email confirmation, change email, user invitation, etc.) tenant-aware. It's not a hack, and there are no hidden side effects. Your config is exactly right:Configure<AppUrlOptions>(options => { options.Applications["MVC"].RootUrl = "https://{0}.example.com"; });A few things worth knowing so you can rely on it with confidence:
Why the
"MVC"key is correct on Blazor Server. In a Blazor Server app, the Account pages that send these emails (login / forgot-password / register) are served by server-side MVC Razor Pages. They submit the request withAppName = "MVC", and the password reset / email confirmation URLs are registered underApplications["MVC"]by default. SoApplications["MVC"].RootUrlis exactly the value ABP uses to build those links.The
{0}placeholder. It's replaced with the current tenant's name. This is the same placeholder semantics used byAddDomainTenantResolver("{0}.example.com"), so as long as your subdomains map to the tenant name (the common case), the outbound email links line up perfectly with your inbound resolution. If your subdomains are based on the tenant id instead, usehttps://{{tenantId}}.example.com(there's also{{tenantName}}if you prefer to be explicit).No side effect for host (no tenant). When there is no current tenant, ABP removes the
{0}.part entirely, sohttps://{0}.example.combecomeshttps://example.com. Host-side links keep working.This single setting covers all Account emails (not just password reset), so you don't need to configure them one by one.
You're right that this isn't spelled out in the docs. The closest related reference is the subdomain resolver section, which confirms the
{0}= tenant name placeholder: https://abp.io/docs/latest/framework/architecture/multi-tenancy#domainsubdomain-tenant-resolverAnd a runnable sample of the subdomain setup: https://github.com/abpframework/abp-samples/tree/master/DomainTenantResolver
Thanks
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 clarification! Maybe this detail of setting
Applications["MVC"].RootUrlshould be in the documentation, since although not required for the subdomain tenant resolver to work, it's certainly something that should be done for a complete implementation.Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
Hi,
Good point, you're absolutely right. We checked the docs and there's actually no dedicated page for
AppUrlOptions/IAppUrlProviderat all — not just missing from the multi-tenancy section. It's a framework feature that deserves its own documentation.We're going to add a dedicated Application URLs page covering
AppUrlOptions(basic config,IAppUrlProvider, multi-tenant placeholders{0}/{{tenantId}}/{{tenantName}}, host fallback behavior,RedirectAllowedUrls), and cross-link it from the Domain/Subdomain Tenant Resolver section so it shows up exactly where you were looking for it.I'll follow up here with the PR link once it's opened.
Thanks
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
Hi,
Following up — the docs PR is open: https://github.com/abpframework/abp/pull/25505
It adds a dedicated Application URLs page covering
AppUrlOptions,IAppUrlProvider, multi-tenant placeholders, host fallback, andRedirectAllowedUrls, plus short cross-references from the multi-tenancy, Account, emailing and microservice domain-resolving pages so it's easy to find from where you were looking.Thanks
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)