Activities of "maliming"

Hi,

Quick context: in ABP 8.2.3, the @abp/uppy npm wrapper declares "uppy": "^3.0.0", and npm resolves that to the latest 3.x — which is 3.27.3. The wrapper has no JS code of its own; it just copies node_modules/uppy/dist/* to wwwroot/libs/uppy/ via abp.resourcemapping.js. So you can change the resolved uppy version without touching ABP server-side (NuGet) packages.

Two important signals before we pick a fix:

  1. Your report shows uppy@3.27.3 (Transitive). In most SCA tools, (Transitive) means uppy is brought in through another package (here, @abp/uppy). The finding can either be in uppy's own code or in one of uppy's own sub-dependencies, and scanners often display the top-level package as the "vulnerable" one.
  2. The public databases we can check do not flag uppy@3.27.3 itself:
    • Snyk: https://security.snyk.io/package/npm/uppy/3.27.3 — "No direct vulnerabilities have been found for this package."
    • GitHub Advisory Database / NVD: no advisory matching uppy + CWE-843.

This strongly suggests the actual vulnerable package is a sub-dependency of uppy, not uppy itself. To pinpoint it, please share:

  • Output of npm ls uppy (full chain, so we can confirm whether it comes through @abp/uppy or something else)
  • The exact advisory ID from your scanner (CVE / GHSA / SNYK-ID), and ideally the "vulnerable package" field — that one is the package you actually need to bump, not necessarily uppy

While you collect those, here are the upgrade paths in order of safety:

Option 1 — Bump only the @abp/* npm packages to ~8.3.x (recommended). Keep ABP NuGet at 8.2.3. @abp/uppy@~8.3.x declares "uppy": "^3.27.0", so you stay on the 3.x line and just get the latest 3.27 patch. This is the smallest change and may already pull a fresh enough sub-dependency to clear the finding.

# In your client project, change @abp/* packages to ~8.3.x in package.json, then:
rm -rf node_modules package-lock.json
npm install
npm ls uppy

Option 2 — npm overrides to pin the actual vulnerable package. Once you know which sub-dependency the scanner is flagging, override that one directly (not necessarily uppy). Example shape:

{
  "overrides": {
    "<the-actual-vulnerable-package>": "<fixed-version>"
  }
}

If the scanner really is flagging uppy itself, pin uppy to the latest 3.x patch and stay on the 3.x major.

Don't blindly jump to uppy@4.x or 5.x via overrides. Uppy 4.x went ESM-only and 5.x changed bundle/plugin internals further. ABP's MVC pages call Uppy.Dashboard, Uppy.XHRUpload, uppy.use(), etc. via the global bundle, and although ABP itself moved to uppy 4 in v9.0 and uppy 5 in v10.0, that came with corresponding npm-pack updates and library-refresh runs (abp install-libs). Overriding the major across a wrong @abp/uppy version risks runtime errors in upload UI (file-management, cms-kit-admin, identity user import, account profile picture, etc.).

For reference, this is how ABP itself has moved uppy:

| @abp/uppy version | uppy range | | --- | --- | | 8.0.x – 8.2.x | ^3.0.0 | | 8.3.x | ^3.27.0 | | 9.x | ^4.4.1 | | 10.x | ^5.1.2 |

Also note: there is no ABP configuration switch that mitigates an npm-level vulnerability. It is purely a dependency-version question. If your client app does not actually use any Uppy-based upload UI at runtime, removing the package that pulls it in is also an option, but again npm ls uppy is the first step to know what to remove.

Thanks

Great

Hi,

The symptom you described (landing page clean, dashboard/other pages show the footer, then landing also shows after) means the Server has the token but the WASM doesn't.

You added the token to appsettings.secrets.json in the .Blazor project. That file only exists on the server file system:

  • Server prerender of the landing page: configuration["BlazoriseProductToken"] returns the real token → no footer.
  • WASM client (when a page goes interactive, or you navigate to Dashboard / admin pages): the same lookup returns null because the browser cannot read your server's secrets file → Blazorise treats it as unlicensed → footer.

Fix in the .Blazor.Client project — pick one:

Option 1: hard-code in the WASM module (simpler)

In MethodInsight.Blazor.Client/MethodInsightBlazorClientModule.cs:

private void ConfigureBlazorise(ServiceConfigurationContext context)
{
    context.Services
        .AddBlazorise(options =>
        {
            options.ProductToken = "your-product-token-here";
        })
        .AddBootstrap5Providers()
        .AddFontAwesomeIcons();
}

Option 2: add to the WASM project's wwwroot appsettings

Create/edit MethodInsight.Blazor.Client/wwwroot/appsettings.json:

{
  "BlazoriseProductToken": "your-product-token-here"
}

Blazor WASM loads this file via HttpClient at startup into IConfiguration, so your existing configuration["BlazoriseProductToken"] lookup will work without code changes.

Note: the WASM token has to live in the client-side bundle / static assets either way — Blazorise verifies the license inside the browser. Both options expose the token equally; Option 1 just has less ceremony.

After the change, clean bin/ and obj/ in .Blazor.Client, rebuild, hard-reload the browser.

Thanks

hi

Have you changed the license key to Product Token in both the server and wasm projects?

Please share your Product Token to liming.ma@volosoft.com

Thanks.

hi

We’ll look into this issue. Thanks for your feedback.

Hi,

That's the second layer of the Switch Tenant flow. Your log line is the giveaway:

[ERR] Invalid RedirectUrl: https://localhost:44337/Account/Challenge, Use AppUrlProvider to configure it!

After SwitchTenantLogin.OnPostAsync signs the user into the new tenant, it calls RedirectSafelyAsync(ReturnUrl, ...), which only allows return URLs whose origin is in AppUrlOptions.RedirectAllowedUrls. Your Blazor host https://localhost:44337 isn't in that list on the AuthServer side, so the redirect falls back to ~/ — the AuthServer home page, which is what you're seeing.

The template wires the list from App:RedirectAllowedUrls in appsettings.json:

// TestApp.AuthServer/<AuthServerModule>.cs
Configure<AppUrlOptions>(options =>
{
    options.Applications["MVC"].RootUrl = configuration["App:SelfUrl"];
    options.RedirectAllowedUrls.AddRange(
        configuration["App:RedirectAllowedUrls"]?.Split(',') ?? Array.Empty<string>());
});

Fix

In your AuthServer project's appsettings.json, add your Blazor host URL to App:RedirectAllowedUrls:

{
  "App": {
    "SelfUrl": "https://localhost:44335",
    "RedirectAllowedUrls": "https://localhost:44337,...your existing entries..."
  }
}

Then restart the AuthServer. After the switch completes, the AuthServer will redirect back to https://localhost:44337/Account/Challenge and re-establish the Blazor session under the new tenant.

While you're there, make sure the same Blazor URL is also in App:CorsOrigins (usually already added by the template). If you have other UI hosts pointing at this AuthServer, add their origins too — the check uses StartsWith, so a single entry like https://localhost:44337 covers any path under that origin.

Thanks

: )

I will update the faq text.

Thanks.

hi

You should use the Product Token instead of License key

Thanks

Hi,

Two separate issues — let me address each.


Issue 1: Switch Tenant returns 405

The SwitchTenant modal in the Blazor Server / WebApp project posts to a relative path /Account/SwitchTenantLogin, which means the form is submitted to the Blazor host itself (port 44337 in your case). But the SwitchTenantLogin Razor Page is only registered on the AuthServer (the Volo.Abp.Account.Pro.Public.Web module), so the Blazor host has no handler and returns 405.

The Blazor SwitchTenantModal already supports an absolute URL — it just needs AbpAccountSwitchTenantOptions.LoginUrl to be configured. The default app template doesn't wire this up (it does wire AbpAccountLinkUserOptions.LoginUrl right above, which is why Link Account works but Switch Tenant doesn't).

Add this in your *BlazorModule.cs (or *BlazorServerModule.cs) ConfigureServices, next to the existing AbpAccountLinkUserOptions block:

using Volo.Abp.Account.SwitchTenant;

Configure<AbpAccountSwitchTenantOptions>(options =>
{
    options.LoginUrl = configuration["AuthServer:Authority"];
});

Make sure your OIDC config has options.SaveTokens = true (the default template already has it), otherwise the access_token can't be attached to the form action.

We'll fix the template to include this by default.


Issue 2: Seeding default users to every new tenant under Shared Accounts

The old approach (IDataSeedContributor seeds an admin/support/ops user into every new tenant) doesn't translate to Shared mode, and not just mechanically — it's incompatible with the design.

Under Shared mode, an email/username pair identifies one person for the whole system. That person can belong to many tenants, but two different people can't share an email. In AbpUsers they show up as a host root row (TenantId = null) plus one tenant-shadow row per tenant they belong to — all those rows are the same identity. There's no such thing as "tenant A's support user" and "tenant B's support user" as two separate accounts; there is one support@yourcompany.com person, and tenants either have an association with that person or they don't.

That's the reason SaaS removed the auto-create-admin behavior. TenantAppService.CreateAsync now publishes InviteUserToTenantRequestedEto { DirectlyAddToTenant = false }, which emails the admin and waits for them to opt in. Joining a tenant is the user's choice, not the system's. The invitation record is the audit trail of that choice.

So the right pattern in Shared mode is:

  1. Create the support@yourcompany.com / ops@yourcompany.com users once in the host (a host-only IDataSeedContributor that calls IdentityUserManager.CreateAsync(...) with TenantId = null is fine, or let them self-register). This produces the single host root per identity that the model expects.
  2. Each tenant gets these users via the normal invitation flow — either you (the host admin) invite them from the SaaS host page after creating the tenant, or your operations workflow does it. The user accepts the invitation, and the tenant-shadow record gets created.

If you bulk-create tenants and find clicking Invite for each one tedious, the realistic answer is to script the host-side action — call SaaS's InviteUserAsync (or publish InviteUserToTenantRequestedEto) right after your tenant-creation script for each default email. The user still opts in via the email; you've just automated the host-side invitation send, not the user's consent.

I don't recommend writing a TenantCreatedEto handler that programmatically auto-accepts invitations on behalf of these users. The primitives to do it exist (UserInvitationManager.CreateAsync + UserSharingManager.AcceptInviteAsync is what UserSharingManager.AddPendingUserToTenantAsync uses internally for the DirectlyAddToTenant = true self-registration path), but applying them to a fixed default-user list means you're forging consent for every new tenant — which defeats the user-sovereignty guarantee the invitation flow was added to provide, and leaves no audit story when one of those users later changes role or leaves.

I verified Issue 1 end-to-end on a fresh tiered Blazor Server template (ABP 10.3.0, Shared mode): the 405 disappears after wiring AbpAccountSwitchTenantOptions.LoginUrl.

Thanks

ok, I will check it. Thanks.

Showing 481 to 490 of 12924 entries
Boost Your Development
ABP Live Training
Packages
See Trainings
Mastering ABP Framework Book
The Official Guide
Mastering
ABP Framework
Learn More
Mastering ABP Framework Book
Made with ❤️ on ABP v10.8.0-preview. Updated on November 02, 2026, 06:56
1
ABP Assistant
🔐 You need to be logged in to use the chatbot. Please log in first.