options.SaveTokens = true;
With SaveTokens = true, ASP.NET Core stores tokens (id_token/access_token/refresh_token if present) inside the authentication cookie (.AspNetCore.Cookies / Identity cookie). With Okta, these tokens can easily push the cookie over 8KB.
options.SaveTokens = false;
This alone typically drops the cookie size dramatically.
app.UseDynamicClaims() and:options.IsDynamicClaimsEnabled = true;
are about refreshing claims per-request; they are not meant to inflate the cookie. The cookie still initially contains the claims created at sign-in, but ABP can override them dynamically afterward. So the primary fix here is still SaveTokens = false.
SaveTokens=true. (There isn’t an ABP-specific “shrink cookie” switch that safely compresses/encrypts tokens into fewer bytes—tokens are already compact JWT strings and will bloat cookies if stored there.)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.
AddVirtualJson(...) is correct, but it only works if your JSON files are actually available in ABP Virtual File System at runtime.vi.json files are not embedded (or not added to VFS), so ABP can’t find them. Then ABP keeps using the module’s built-in en.json.Use this checklist (it applies to SaasResource, PaymentResource, AbpIdentityResource, AbpOpenIddictResource):
Place the override files in your *.Domain.Shared project (recommended), e.g.:
MyProject.Domain.Shared
/Localization
/AbpIdentity
vi.json
/AbpOpenIddict
vi.json
/Saas
vi.json
/Payment
vi.json
Then embed them in MyProject.Domain.Shared.csproj:
<ItemGroup>
<EmbeddedResource Include="Localization\**\*.json" />
<Content Remove="Localization\**\*.json" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="*" />
</ItemGroup>
(Without embedding, the files may not be available in production and ABP won’t load them.)
In your MyProjectDomainSharedModule:
using Volo.Abp.VirtualFileSystem;
Configure<AbpVirtualFileSystemOptions>(options =>
{
options.FileSets.AddEmbedded<MyProjectDomainSharedModule>();
});
Use the standard ABP JSON schema:
{
"culture": "vi",
"texts": {
"SomeKey": "Some Vietnamese value"
}
}
(culture / texts should be lowercase as above.)
In MyProjectDomainSharedModule:
Configure<AbpLocalizationOptions>(options =>
{
options.Resources.Get<SaasResource>()
.AddVirtualJson("/Localization/Saas");
options.Resources.Get<PaymentResource>()
.AddVirtualJson("/Localization/Payment");
options.Resources.Get<AbpIdentityResource>()
.AddVirtualJson("/Localization/AbpIdentity");
options.Resources.Get<AbpOpenIddictResource>()
.AddVirtualJson("/Localization/AbpOpenIddict");
});
Then restart the app (localization is cached).
viEven if you set default language to vi, if the current culture is still en, you’ll see English.
Make sure Vietnamese exists in AbpLocalizationOptions.Languages and default is vi (or user/tenant sets vi).
That typically means either:
AbpAccountResource vs AbpIdentityResource), ORAddVirtualJson approach won’t affect them.But in your specific snippet (Identity/OpenIddict/SaaS/Payment module UI texts), the usual fix is embedding + AddEmbedded<...>() as above.
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.
vi when there is no user/tenant preference yet).In your *.Domain.Shared (or the module where you configure localization), configure AbpLocalizationOptions:
using Volo.Abp.Localization;
Configure<AbpLocalizationOptions>(options =>
{
// Make sure Vietnamese is available in the language list
options.Languages.Add(new LanguageInfo(
"vi",
"vi",
"Tiếng Việt",
flagIcon: "vn"
));
// Make Vietnamese the default when nothing else is selected
options.DefaultLanguage = "vi";
});
This makes newly created tenants/users start with Vietnamese as the default culture, but it does not automatically translate everything unless Vietnamese resources exist.
ABP module texts come from their own localization resources (embedded JSON). To translate module strings to Vietnamese, you override/extend those resources by adding vi.json under your app and registering it via AddVirtualJson(...) for each module resource you want to override.
Example pattern (same idea as overriding AbpTimingResource in the official article):
using Volo.Abp.Localization;
using Volo.Abp.Timing.Localization;
Configure<AbpLocalizationOptions>(options =>
{
// Add your overrides for an ABP module resource:
options.Resources
.Get<AbpTimingResource>()
.AddVirtualJson("/Localization/AbpTiming"); // contains vi.json
});
Then create:
YourProject.Domain.Shared/Localization/AbpTiming/vi.jsonwith contents like:
{
"culture": "vi",
"texts": {
"DisplayName:Abp.Timing.Timezone": "Múi giờ",
"Description:Abp.Timing.Timezone": "Múi giờ của ứng dụng"
}
}
Repeat this for other module resources you need (Identity, SettingManagement, FeatureManagement, etc.) by adding corresponding folders and vi.json files and registering them with .AddVirtualJson(...).
Keep using Language Management + your custom DynamicResourceLocalizer override (host context) so TenantId = null translations are visible to tenants. That ensures newly created tenants also see the translations without copying rows per tenant.
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.
TenantUserSharingStrategy.Shared, the credential verification/login happens on the Host side (global identity). That’s why /connect/token resolves the tenant as Host and why your custom tenant header is not used there. In other words: the password grant is intentionally host-scoped in Shared User Accounts.userA must exist in the Host database in a way that the Host-side user lookup can find. In your case, the Host DB row you see for userA has TenantId = <DevTenantId>, so when the token endpoint runs in the Host context (TenantId = null), it won’t match that user and you get “No user found … → invalid_grant”.Fix (what to do)
/connect/token).Answers to your specific questions
userA log in?/connect/token authenticates on Host, but the Host-side lookup can’t find userA (your Host DB record is not a Host record; it’s stored with a tenant id).TenantId = NULL?TenantId = null means Host-owned data. For shared-account login being Host-side, there must be a Host-side user identity to authenticate against. Seeing only a TenantId = Dev record in the Host database explains the behavior you observe./connect/token. The Shared User Accounts design is: authenticate globally first, then choose/switch the active tenant (tenant selection in UI; switch-tenant flow for programmatic usage)./connect/token is Host-side for shared identity, so a tenant header is not the mechanism to select tenant at that stage.Links (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.
DisplayName:Abp.Identity.*, IdentitySettings*, etc.) come from module localization JSON files (embedded en.json, etc.). When a text exists in those JSON resources, ABP can keep returning that value (English) unless your dynamic (DB) localization is configured to override it for the current tenant.LanguageText is a multi-tenant entity and the localization lookup/caching runs under the current tenant. So the query is filtered by TenantId = CurrentTenantId, and the Host records are not considered.To make Host translations apply to all tenants (including newly created ones), replace the dynamic resource localizer so it reads localization texts under the Host context:
using Microsoft.Extensions.Caching.Distributed;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Localization;
using Volo.Abp.MultiTenancy;
[Dependency(ReplaceServices = true)]
[ExposeServices(typeof(DynamicResourceLocalizer), typeof(IDynamicResourceLocalizer))]
public class MyDynamicResourceLocalizer : DynamicResourceLocalizer
{
private readonly ICurrentTenant _currentTenant;
public MyDynamicResourceLocalizer(
IServiceScopeFactory serviceScopeFactory,
IDistributedCache<LanguageTextCacheItem> cache,
ICurrentTenant currentTenant)
: base(serviceScopeFactory, cache)
{
_currentTenant = currentTenant;
}
public override LocalizedString GetOrNull(LocalizationResourceBase resource, string cultureName, string name)
{
using (_currentTenant.Change(null))
{
return base.GetOrNull(resource, cultureName, name);
}
}
protected override LanguageTextCacheItem GetCacheItem(LocalizationResourceBase resource, string cultureName)
{
using (_currentTenant.Change(null))
{
return base.GetCacheItem(resource, cultureName);
}
}
protected override Task<LanguageTextCacheItem> GetCacheItemAsync(LocalizationResourceBase resource, string cultureName)
{
using (_currentTenant.Change(null))
{
return base.GetCacheItemAsync(resource, cultureName);
}
}
}
And register it (e.g., in your Domain module):
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddSingleton<IDynamicResourceLocalizer, MyDynamicResourceLocalizer>();
}
With this change:
TenantId = null.Links (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.
/tenant1 in AuthServer
RouteTenantResolveContributor) by adding the special route parameter name {__tenant} to your routes.
[Route("{__tenant}/[controller]")]
public class MyController : Controller
{
}
or for Razor Pages:
@page "{__tenant?}/Account/Login"
{__tenant} to all routes (controllers/pages) as shown in the referenced article.PathBase and a custom route contributor derived from RouteTenantResolveContributor.Fix tenant context once a user enters via tenant-specific endpoint
Mapping tenants to different external authentication providers / enabling-disabling per tenant
ICurrentTenant (tenant resolved before hitting /Account/Login via {__tenant} route).Different OpenID Connect configurations per tenant (ClientId/Authority/Secret)
Example / sample
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.
options.ProductToken in the Blazorise registration. If you don’t, Blazorise may display a “license expired / free version” footer/banner.What you should do in an ABP Blazor solution
Generate / obtain the Blazorise Product Token from Blazorise:
Configure it in both places when you use a server + WASM (or Blazor WebApp with interactive/WASM) style solution:
YourApp.Blazor → *BlazorModule.cs → ConfigureBlazorise()YourApp.Blazor.Client → *BlazorClientModule.cs → ConfigureBlazorise()If you only put it into a server-side secrets file, the WASM/client side may not see it and the banner can appear after navigation (server prerender looks OK, then client becomes interactive and the footer/banner appears). ABP support confirmed this exact symptom and fix.
Two working approaches:
wwwroot/appsettings.json so the client can load it.What happens if your ABP license expires?
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.
The root cause is that the downloaded Account.Pro Angular libraries are being compiled as separate Angular library projects, and with Angular’s newer builder + "moduleResolution": "bundler", TypeScript can fail to resolve workspace-external dependencies (like @abp/ng.core) consistently when you reference module source via tsconfig.paths (e.g., pointing to ../modules/.../projects/.../src/public-api.ts). This frequently manifests as TS2307 (module not found) or related Angular compiler/type-check issues in modular development scenarios.
The officially working approach (and the one that avoids this entire class of resolution problems) is to not compile these module projects through tsconfig.paths pointing to their source. Instead, use one of these two approaches:
file:) instead of paths../modules/Volo.Abp.Account.Pro/angular/projects/...) so they produce their dist outputs.package.json using file: (or a local tarball), rather than tsconfig.json paths into src/public-api.ts.paths entries that point into ../modules/.../projects/.../src/....This ensures there is one consistent dependency graph resolved from your main app’s node_modules.
node_modulesIf you must develop the module source “in place” inside the same repo, use a symlink strategy so the module library projects resolve the same physical @abp/* packages as the main app:
paths mappings (mapping @abp/ng.core manually is a common way to end up with inconsistent resolution).../modules/.../angular/projects/... resolve dependencies from the main app’s angular/node_modules by symlinking (so they don’t behave like isolated workspaces with their own resolution roots).About peer dependencies: Account.Pro Angular source projects expect the ABP Angular packages (like @abp/ng.core) to be available from the consuming app’s node_modules (same versions as your solution). When the module projects compile “isolated” and can’t see that node_modules consistently, you hit TS2307. Using Option A or B above fixes that by making dependency resolution consistent.
The "types": [] inside tsconfig.lib.json is not the core issue here; the problem is primarily the module resolution graph and the way the new builder handles paths + library compilation boundaries.
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.
This error happens because your module’s Angular library project (e.g. modules/examplemodule/angular/...) ends up compiling against a different physical copy of Angular packages than the main app (App/angular/...). So TypeScript sees two different Routes types:
.../modules/examplemodule/angular/node_modules/@angular/router/....../angular/node_modules/@angular/router/...
and they are incompatible even if versions look identical.Definitive fix (recommended approach): ensure module UI projects use the main app’s node_modules via symlinks (single dependency graph).
tsconfig paths (as ABP modular UI does), but do not allow the module project to have its own independent node_modules resolution.App/angular/node_modules into each module’s angular/projects/... (or the module’s angular workspace) so everything resolves to one place.symlink-config.ps1 should include at least these packages to be shared from the main app to the module libs:
@angular/*rxjstslib@abp/* / @volo/* (if used inside the module UI lib)This is exactly aligned with the behavior you observed: manually symlinking fixes it because it forces a single Angular dependency instance.
Stable alternative (also works, but slower for dev): build & consume the module UI as a package instead of paths
file: dependency from the main Angular app, avoiding tsconfig.paths pointing to library sources. This also prevents duplicate node_modules graphs.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.
In ABP 8.2.x, Scriban is used through ABP Text Templating (Scriban) integration. ABP already enables Scriban’s “safe runtime” boundaries (restricted globals, restricted .NET member access via MemberFilter, no TemplateLoader by default, and execution limits like LoopLimit, RecursiveLimit, LimitToString, etc.). However, the CVE you described is specifically about array.insert_at bypassing those limits, so tightening LoopLimit/LimitToString alone is not a sufficient mitigation for that specific issue.
The practical mitigation in ABP without upgrading .NET / Scriban is therefore to ensure untrusted template authors cannot execute Scriban templates (i.e., don’t allow end users/tenants to edit arbitrary Scriban templates in production), and keep Scriban templates developer-owned and embedded/controlled (virtual file system, deployed with code). In other words: treat Scriban templates as trusted code/config, not user input.
If you must allow users to edit templates (e.g., Text Template Management scenarios), then within ABP 8.2.x there is no verified, ABP-provided switch documented to disable only array.insert_at or to hard-cap its index to prevent the allocation behavior in Scriban 5.9.0. In that case, the only fully effective remediation is upgrading Scriban to a fixed version (which you noted is blocked by your runtime constraint). So the ABP-side mitigation is to avoid exposing Scriban editing to untrusted parties until you can move to a fixed Scriban line.
Recommended ABP usage pattern (safe-by-design):
Dictionary<string, object> / ScriptObject as the model so the template surface area stays minimal and controlled (ABP recommends this pattern).TemplateLoader unless you absolutely need include behavior.Sources (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.