Open Closed

Shared User Accounts - sent email format #10659


User avatar
0
thanhvl1 created

Hi,

This question is about feature Shared User Accounts

I've used this feature but the email send to end users maybe not in the proper format and there is no url link, What am I missing ?

Markdown supported.
Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)

18 Answer(s)
  • User Avatar
    0
    AI-Bot created
    Support Team ABP Agent
    • The invitation email body is rendered correctly, but your application’s public URL (host/scheme) is not being included while generating the invitation link.
      That’s why you only see a relative URL like: [/Account/InviteUser?token=...] and many email clients won’t make it clickable / it won’t point to your site.

    • Fix: configure the application URL(s) so ABP can generate an absolute invite link (e.g. https://yourdomain.com/Account/InviteUser?...) in the email.

      In your *.HttpApi.Host (or Web project, depending on your UI), configure AppSelfUrl (and optionally RedirectAllowedUrls) in appsettings.json:

    {
        "App": {
          "SelfUrl": "https://yourdomain.com",
          "RedirectAllowedUrls": "https://yourdomain.com"
        }
      }
    

    If you are running behind a reverse proxy / load balancer, also make sure forwarded headers are correctly configured so the request scheme/host are detected as external (https, correct host). Otherwise ABP may still generate non-public URLs.

    • After setting App:SelfUrl properly, re-send the invitation: the email should contain a full absolute link and display as a clickable “Accept invitation” link.

      • https://abp.io/docs/latest/modules/account/shared-user-accounts
      • https://abp.io/docs/10.2/modules/account/shared-user-accounts

    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)
  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    Hi thanhvl1,

    The link is a relative path because Applications["MVC"].RootUrl isn't set when the invite email is generated. Two cases:

    Non-tiered solution (*.Web / *.Blazor.Server / *.Blazor.WebApp / *.HttpApi.HostWithIds) — the template already wires App:SelfUrl to Applications["MVC"].RootUrl. Just make sure App:SelfUrl in appsettings.json is a full URL with scheme + host, e.g. https://your-app.example.com.

    Tiered solution (separate *.HttpApi.Host + *.AuthServer) — the InviteUsers API runs in *.HttpApi.Host, but its ConfigureUrls doesn't register Applications["MVC"].RootUrl. Add this one line in *.HttpApi.Host/*HttpApiHostModule.cs:

    Configure<AppUrlOptions>(options =>
    {
        options.Applications["MVC"].RootUrl = configuration["AuthServer:Authority"];
        // ...existing Angular registrations
    });
    

    The Account/InviteUser page is served by the AuthServer in a tiered solution, which is why we point to AuthServer:Authority. After this, the email link becomes absolute like https://your-authserver.example.com/Account/InviteUser?token=... and clickable.

    We'll fix this in the project template in the next ABP version.

    Thanks!

    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
  • User Avatar
    0
    thanhvl1 created

    thanks for your quick support, I'm missing setting this options.Applications["MVC"].RootUrl = configuration["AuthServer:Authority"]; in Identity

    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    Great

    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
  • User Avatar
    0
    thanhvl1 created

    Hi, there is still 1 more thing related to this feature

    for example I'm in Host tenant when I choose switch tenant I will see this

    Then I change to "fti" tenant, this modal of switch tenant now no show Host tenant

    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    Hi thanhvl1,

    The Switch Tenant modal lists all tenant associations the current user has on the Host side. In Shared User Accounts mode, AbpUsers on the Host database uses three values for TenantId:

    • Guid.Empty — the user's global root record (filtered out)
    • NULL — Host association (rendered as "Host" in the modal)
    • <tenant guid> — a tenant the user has joined

    If the user has a row with TenantId IS NULL, the modal shows a "Host" entry that lets you switch back to Host from any tenant. The fact that "Host" doesn't appear in your screenshot suggests this user has no Host association — they were only invited into fti / tff.

    To help me confirm, could you share a few details:

    1. Is it the same user account signed in for both screenshots, or two different accounts? (The Host-side screenshot might be your Host admin, while the tenant-side one might be a different account that was only invited into fti / tff.)
    2. Which ABP version are you on (10.2 / 10.3 / 10.4)?
    3. Could you run this on the Host database for the email you're testing with, and paste the result?
    SELECT Id, UserName, Email, TenantId
    FROM AbpUsers
    WHERE Email = '<user email here>';
    

    Most likely outcome — if there's no row with TenantId IS NULL, a Host admin can invite that user to Host through the standard invitation flow (open the invite dialog while the current tenant is Host). After acceptance, the Host association is created and "Host" will appear in the Switch Tenant modal.

    Thanks!

    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    Hi thanhvl1,

    One more question — the Switch Tenant modal in your screenshots looks like it might not be our default one. Did you customize the modal, or are you using a community / third-party UI?

    If yes, could you share the relevant code (or at least which API it calls to load the tenant list)? That'll help us trace where the displayed list comes from.

    Thanks!

    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
  • User Avatar
    0
    thanhvl1 created

    In this admin app is a standard Angular host: it uses @volo/abp.ng.account and provideAccountPublicConfig() in app.config.ts, plus Lepton X (@volosoft/abp.ng.theme.lepton-x). We do not ship a custom “Switch tenant” dialog implementation in our admin src/ tree.

    I also have checked db and api

    But there this is weird because when I logged in it's come to next screen choose tenants, in this UI, I see the Host

    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    Hi thanhvl1,

    To narrow this down, could you check a few things after switching to fti?

    1. Decode the access token. Open DevTools (F12) → Network → pick any authenticated API request after the switch → copy the Authorization: Bearer <token> value → paste it at https://jwt.io. What does the tenant_id (or tenantid) claim show?

    2. Database setup. Are fti / tff configured as shared database or database-per-tenant?

    3. (If per-tenant) Run this on the fti tenant database (not Host):

    SELECT Id, Email, TenantId
    FROM AbpUsers
    WHERE Email = 'thanhvl1@aaa.com';
    

    Once we have these, we can pinpoint where the list is coming from.

    Thanks!

    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
  • User Avatar
    0
    thanhvl1 created

    I've used shared database

    After choosing tenant fti then get the token to decode and I get

    "tenantid": "3a1af4d8-364d-86dc-87c9-66b8c5f291f5" match this api

    {
      "items": [
        {
          "tenantId": "3a1aff20-3e15-936d-eed4-9ae0c7235e8e",
          "tenantName": "tff",
          "email": "thanhvl1@aaa.com"
        },
        {
          "tenantId": "3a1af4d8-364d-86dc-87c9-66b8c5f291f5",
          "tenantName": "fti",
          "email": "thanhvl1@aaa.com"
        }
      ]
    }
    
    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    Hi thanhvl1,

    We tried to reproduce this on our side with the same setup (Tiered Angular Pro, Shared User Accounts, shared database, the same 3 user rows in AbpUsers), but we couldn't reproduce the issue — switching to fti and calling GET /api/account/user-sharing with the new token returns [Host, tff] as expected, with Host included.

    To narrow this down, could you share a few more pieces of info?

    1. Authorization header from actual XHR requests after switching to fti. Open DevTools → Network → after the switch, pick 2–3 XHR requests (for example /api/abp/application-configuration and the modal's /api/account/user-sharing) → copy each request's full Authorization: Bearer ... value → decode each at https://jwt.io. We want to confirm whether every XHR is sending the same fti token you decoded earlier, or whether some are still carrying the old Host token.

    2. Backend debug log around the /api/account/user-sharing request. In your AuthServer's appsettings.json, lower the Serilog/logging level for Volo.Abp.MultiTenancy (or the root logger) to Debug, restart AuthServer, reproduce once, then share the log lines around the request. The single most useful line looks like:

    [DBG] Tenant resolved by 'CurrentUser' as '<value>'.
    

    That tells us exactly which tenant the server saw when handling the modal's request.

    1. Exact ABP version (e.g. 10.2.1, 10.3.2, 10.4.0) — we want to make sure we're comparing the same code.

    2. How are you switching to fti? Through the Switch Tenant modal (clicking fti in the actions menu), through the login page with a tenant selection, through a URL parameter, or some other flow?

    3. Have you customized any of these on the server side? UserSharingAppService, IdentityUserManager, IUserClaimsPrincipalFactory, or any tenant-resolution / authentication / HTTP interceptor pieces. Likewise on the Angular side — any custom interceptor or override of @volo/abp.commercial.ng.ui/config SwitchTenantService / RestService.

    4. Hard refresh test — after switching to fti, hit Ctrl+Shift+R (Cmd+Shift+R on Mac) to do a hard reload, then open the Switch Tenant modal again. Does Host show up now? This rules out browser/SPA caching as the cause.

    Thanks!

    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
  • User Avatar
    0
    thanhvl1 created

    checking 2-3 XHR the token Bear value is almost the same, it's from fti after switching tenant. The weird thing I've checked is that in localhost, I can still see Host as listed in the modal of switching tenant

    I've got this issue when deploying to AKS, so is that maybe caused by a behind proxy ?

    For more info, I use ABP version 10.3.0 And I got through the Switch Tenant modal in Angular admin I also try hard refresh test but still the same

    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
  • User Avatar
    0
    thanhvl1 created

    1 thing to note that is this api called from Admin Angular but it return 2 tenants test1 and test2 (I have leaved 2 tenants fti and tff above then created new tenants and joined to them)

    but when using token value to call from postman it return like what we expected.

    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    Hi thanhvl1,

    Great comparison — Angular vs Postman returning different responses with the same token strongly points to Angular sending something extra in the request that's changing the server's behavior.

    Could you share two things?

    1. The full Request Headers of the Angular call to /api/account/user-sharing from DevTools Network — please include all headers (not just Authorization), especially any Cookie, Origin, Referer, or __tenant-style headers. A screenshot of the fully expanded Request Headers section works.

    2. How are the Angular app and AuthServer exposed on AKS? Same domain (e.g. app.example.com and app.example.com/authserver) or different domains (e.g. app.example.com and authserver.example.com)? If they share a domain, the browser may be sending the AuthServer's session cookie automatically along with the Bearer token, which could change how the server authenticates the request.

    Once we see the headers and the deployment layout, we can pinpoint and fix it.

    Thanks!

    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
  • User Avatar
    0
    thanhvl1 created

    I exposed my app on AKS using the same domain admin angular: domain/admin authserver: domain/authserver

    After fill all the headers to the postman, now I know it caused by Cookie header

    With uncheck Cookie now it shows like we expected

    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    Hi thanhvl1,

    Excellent debugging — that nails it down to the Cookie header.

    To confirm exactly what's happening on the server side, could you share the full AuthServer Debug log for one reproduction of the /api/account/user-sharing call?

    To enable Debug-level logs, please follow this guide: https://abp.io/support/questions/8622/How-to-enable-Debug-logs-for-troubleshoot-problems

    Then restart AuthServer, sign in, switch to a tenant, open the Switch Tenant modal once, and attach the complete log (please don't trim it).

    Thanks!

    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
  • User Avatar
    0
    thanhvl1 created

    do you need me to reproduce this and send you my log for further document ?

    Because when I try to implement this middleware now it can bypass and the switch tenant now show as expected. But I don't know if it will cause other error

    public sealed class StripCookiesForBearerAccountApiMiddleware : IMiddleware
    {
        private const string AccountPublicApiPrefix = "/api/account";
    
        public async Task InvokeAsync(HttpContext context, RequestDelegate next)
        {
            var path = context.Request.Path;
            if (!path.StartsWithSegments(AccountPublicApiPrefix, StringComparison.OrdinalIgnoreCase))
            {
                await next(context);
                return;
            }
    
            var authHeader = context.Request.Headers.Authorization.ToString();
            if (string.IsNullOrEmpty(authHeader) ||
                !authHeader.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase))
            {
                await next(context);
                return;
            }
    
            context.Request.Headers.Remove("Cookie");
            await next(context);
        }
    }
    
    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    Is your problem solved? If not, you can continue sharing the logs. https://abp.io/support/questions/10659/Shared-User-Accounts---sent-email-format#answer-3a213270-a9ea-58ca-2111-9b161116c3a1

    Because when I try to implement this middleware now it can bypass and the switch tenant now show as expected. But I don't know if it will cause other error

    You can remove your middleware to troubleshoot the problem.

    Thanks

    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
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 September 28, 2026, 11:44
1
ABP Assistant
🔐 You need to be logged in to use the chatbot. Please log in first.