AbpOpenIddictWildcardDomainOptions the same way: WildcardDomainsFormat must contain only the domain/root format, not callback paths.... + "signin-oidc"... + "signout-callback-oidc"Use this configuration instead:
using Volo.Abp.OpenIddict.WildcardDomains;
if (!hostingEnvironment.IsDevelopment() &&
!string.IsNullOrWhiteSpace(configuration["App:OpenIddictWildcardDomainsFormat"]))
{
PreConfigure<AbpOpenIddictWildcardDomainOptions>(options =>
{
options.EnableWildcardDomainSupport = true;
options.WildcardDomainsFormat.Add(configuration["App:OpenIddictWildcardDomainsFormat"]!);
});
}
And set the value without a trailing slash:
"App": {
"OpenIddictWildcardDomainsFormat": "https://{0}.<app-domain>"
}
Also (common after moving to AKS/ingress): ensure your apps read the correct external scheme/host; otherwise OpenIddict may generate/validate redirect URIs against the wrong scheme/host. In AKS, configure forwarded headers / ingress so the app sees https and the real public host.
Sources:
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.
signin-oidc / signout-callback-oidc variants into WildcardDomainsFormat. WildcardDomainsFormat expects site root URL formats, not callback endpoints."App": {
"OpenIddictWildcardDomainsFormat": "https://{0}.<app-domain>"
}
using Volo.Abp.OpenIddict.WildcardDomains;
if (!hostingEnvironment.IsDevelopment() &&
!string.IsNullOrWhiteSpace(configuration["App:OpenIddictWildcardDomainsFormat"]))
{
PreConfigure<AbpOpenIddictWildcardDomainOptions>(options =>
{
options.EnableWildcardDomainSupport = true;
options.WildcardDomainsFormat.Add(configuration["App:OpenIddictWildcardDomainsFormat"]!);
});
}
https and the public host (otherwise you can end up with mismatched redirect/callback URLs causing 404/redirect issues in tenant subdomains).Links:
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.
UI Options (Blazorise / MudBlazor) are available for Blazor solutions, but ABP Studio v3.0.3 currently shows the “UI Options” step only for the “Modern” solution template.
When you create a solution with the Classic template (as in your screenshot), ABP Studio doesn’t display that UI Options screen for Blazor; it proceeds without that selection. This is a Studio wizard capability difference (not an ABP Framework 10.4.0 limitation).
If you want to pick the Blazor component library explicitly, you can:
Sources:
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.
abp global tool is running from ~/.dotnet/tools/abp and is using the .NET runtime located at ~/.dotnet (see “.NET location: /home/xx/.dotnet”).~/.dotnet location you only have .NET 8 and .NET 9 runtimes, so the tool fails when it looks for Microsoft.NETCore.App 10.0.0./usr/share/dotnet, which is not the runtime location your tool is picking up./usr/share/dotnet (system install) instead of ~/.dotnet:which dotnet
dotnet --info
which dotnet points to ~/.dotnet/dotnet, fix your PATH so /usr/share/dotnet is first (example for bash):export DOTNET_ROOT=/usr/share/dotnet
export PATH=/usr/share/dotnet:$PATH
hash -r
dotnet you’ll run it with:dotnet tool uninstall -g Volo.Abp.Studio.Cli
dotnet tool install -g Volo.Abp.Studio.Cli
# or:
# dotnet tool update -g Volo.Abp.Studio.Cli
abp -h
~/.dotnetIf you intentionally want to use the per-user dotnet (~/.dotnet), then you must install the .NET 10 runtime into that same location so ~/.dotnet/shared/Microsoft.NETCore.App/10.x exists. (Right now it doesn’t, according to your error output.)
The ABP CLI is a .NET global tool and it runs on the runtime selected by the dotnet resolution / DOTNET_ROOT / PATH. In your case the tool host resolves to ~/.dotnet, which doesn’t contain .NET 10.
Links (validated):
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.
azure_ad_token is not a grant type supported by ABP’s Auth Server (OpenIddict) out of the box. When /connect/token returns unsupported_grant_type, it means the authorization server doesn’t have that grant enabled/implemented.AddOpenIdConnect (or AddMicrosoftIdentityWebApp).This is why it “works on web”: the web flow is usually going through the interactive external login pipeline, not a custom /connect/token exchange with grant_type=azure_ad_token.
If your Flutter app already gets an Azure AD token and you want to exchange it at https://authserver.../connect/token, then you must do both:
grant_type=azure_ad_token and validates the incoming Azure AD token).XXX_MobileApp) in your AuthServer’s data seed (client permissions). Otherwise you’ll get either unsupported_grant_type or unauthorized_client.In ABP/OpenIddict, allowed grant types are configured per client during seeding (e.g., adding OpenIddictConstants.GrantTypes.AuthorizationCode, RefreshToken, etc.). Custom grants must also be included there, and the client may need to be re-created/re-seeded if it already exists.
authorization_code (and the external login UI), which ABP supports by default.grant_type=azure_ad_token, but:
XXX_MobileApp) does not have permission for that grant (client-side missing in OpenIddict application configuration).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.
In ABP Studio v3.x, the AI Agent is still a probabilistic tool (LLM-based). For “framework-shaped” tasks (like extending Setting Management UI with contributors/components), it can drift into non-existing types/namespaces (e.g., inventing SettingManagementViewComponent) and then spiral while trying to self-fix—burning credits. This is an expected failure mode for agentic coding when the task requires exact ABP API usage and project-specific conventions.
To improve success rate and reduce wasted credits, use the agent the way it was designed to be most deterministic:
SettingManagementPageOptions is configured in your Web module) before letting it generate code.For cost control:
If you believe this is a product-quality issue with ABP Studio AI Agent v3.0.2 (e.g., consistent failure even with Analyze + small scoped tasks), please contact us so the team can review logs/session behavior: https://abp.io/contact
Less obvious references (verified):
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.
ABP doesn’t require you to “replace an application service” to integrate SAML. Treat SAML as another ASP.NET Core authentication handler (like any social/OIDC provider), then let ABP’s Account login page flow (external login) create/link the ABP user and sign them in.
The wiring point is in your host web module where authentication is configured (e.g., *.Web for MVC/Razor UI or *.HttpApi.Host / separate AuthServer host in tiered setups): you register the SAML scheme via AddAuthentication().AddXxx(...) and ensure its SignInScheme is IdentityConstants.ExternalScheme so ABP’s external-login pipeline can read it.
Once that’s done, ABP will handle:
To support multiple login types:
IdentityConstants.ExternalScheme).About “customizing Volo.Abp.Identity” with Team license / no commercial source:
Volo.Abp.Identity and reference it alongside the NuGet package; that will create assembly conflicts (duplicate types/assemblies).Volo.Abp.* assembly.(Links validated: https://abp.io/community/articles/4603b9cf , https://abp.io/docs/latest/solution-templates/layered-web-application/authentication , https://abp.io/contact)
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.
Configure<AbpMultiTenancyOptions>(o => o.IsEnabled = false) only disables ABP’s multi-tenancy behavior at runtime (tenant resolution, multi-tenancy checks/filters, etc.). It does not automatically uninstall modules, and it does not remove:
If your goal is “B2C, and the customer must not be able to turn it into SaaS later”, the recommendation is to remove the SaaS module completely from the solution:
.csproj files.DependsOn(...) entries from your module classes (Web/HttpApi/EntityFrameworkCore/etc.).DbContext (builder.ConfigureSaas();) if it exists.Also note: if the client has host admin + direct DB access, they can always change data in any table (including permissions/features/settings). The only robust way to prevent SaaS capabilities from being enabled is not shipping the SaaS module/code at all (steps above). Disabling multi-tenancy via IsEnabled=false doesn’t provide that guarantee.
(Links checked)
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.
ABP’s resource-based authorization does not support “filter operators/conditions configured from UI” (e.g., Order.UserId == CurrentUser.Id or Vendor.UserId == CurrentUser.Id) as part of the built-in permission management UI.
For your legacy rules (ownership / “self” access) you should implement them with code-enforced policies, typically in one of these ABP-native ways:
Tenant isolation (already built-in)
IMultiTenant (or otherwise have TenantId) so ABP automatically isolates data per tenant.Ownership / “self” access (recommended: data filter + app service checks)
Order.CreatorId or Order.CustomerUserId, Vendor.OwnerUserId).AuthorizationService.CheckAsync(resource, permissionName) only if you are using per-record grants, ORCurrentUser.Id) for “self-service” rules.Where(...) based on CurrentUser.Id in repositories/app services). ABP’s built-in “data filters” are designed around known filter concepts (like multi-tenancy/soft-delete), not an end-user-configurable query builder for arbitrary entities.If you truly need a UI like your screenshot (a rule builder)
If your goal is “Customer can edit only their own orders” and “Vendor can access only their own vendor profile”, the clean ABP approach is:
Orders.Edit, Vendors.ViewSelf)entity.UserId == CurrentUser.Id (and tenant is already isolated)Sources (verified):
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.
This is a known timing/regression issue in LeptonX 5.3.x (ABP 10.3.x): the side-menu JS initializer (initSideMenu) can run when #lpx-sidebar exists but before the real menu items are rendered (or after Blazor later replaces them, e.g., on app configuration changes / impersonation). In that case, LeptonX binds zero click handlers, so parent items don’t expand. Your DevTools observation matches this exactly: menuItems is empty until you manually call createMenuItems() / re-init.
Your TelerikRootComponent placement is not the root cause. The issue is that LeptonX side menu binding is done once on first render, and if the DOM changes later, handlers can be lost. (So moving Telerik “above Routes” is not required just for this.)
Add a small script that re-runs only the side-menu initializer once the sidebar items appear (or re-appear) after Blazor updates the DOM.
wwwroot/lpx-sidebar-rebind-polyfill.js (Server UI project that serves _Host.cshtml / static files):(function () {
'use strict';
const DONE_ATTR = 'data-lpx-polyfill-rebound';
function tryRebind() {
const sidebar = document.querySelector('#lpx-sidebar');
if (!sidebar) return false;
// Wait until real items exist
if (!sidebar.querySelector('.outer-menu-item > .lpx-menu-item')) return false;
// Prevent endless re-binding loops
if (sidebar.hasAttribute(DONE_ATTR)) return true;
sidebar.setAttribute(DONE_ATTR, '');
const initFn =
window.leptonx &&
window.leptonx.init &&
window.leptonx.init.initializers &&
typeof window.leptonx.init.initializers.get === 'function' &&
window.leptonx.init.initializers.get('initSideMenu');
if (typeof initFn === 'function') {
initFn(); // binds expand/collapse handlers
return true;
}
return false;
}
function start() {
if (tryRebind()) return;
const obs = new MutationObserver(() => {
if (tryRebind()) obs.disconnect();
});
obs.observe(document.body, { childList: true, subtree: true });
// safety stop
setTimeout(() => obs.disconnect(), 30000);
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', start);
} else {
start();
}
})();
_Host.cshtml:<abp-script-bundle name="...LeptonX...Global" />
<script src="~/lpx-sidebar-rebind-polyfill.js"></script>
This ensures that when the menu DOM is finally present (or re-rendered), initSideMenu runs against the final nodes and the parent items expand reliably.
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.