Open Closed

Multi Solutions - Single Sign On Experience #9811


User avatar
0
luciana created

Hi,

We have need to define multiple different ABP based solutions and yet still use the same openiddict auth server for a single sign on experience and central management of users, roles and permissions. The auth server has been configured and the client applications including the other client api's (ie. the host api's of the various modules) have been registered. The redirect works and a valid token is issued, however the authentication and authorization fails in the host api. We are able to get this working, if we manually create the tenant, the user and the session record in the database that is used by the host api. Can we programmatically create the tenant if it doesn't exist, create the user if it doesn't exist, and the session context for that user so that ICurrentUser and ICurrentTenant works? Alternatively is there a different approach we can take to take to implement this?

ABP Version - 9.2.0


7 Answer(s)
  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    however the authentication and authorization fails in the host api.

    Do you have any error logs? Why do you think creating a tenant will fix it?

    https://abp.io/support/questions/8622/How-to-enable-Debug-logs-for-troubleshoot-problems

    Thanks.

  • User Avatar
    0
    luciana created

    [maliming] said: hi

    however the authentication and authorization fails in the host api.

    Do you have any error logs? Why do you think creating a tenant will fix it?

    https://abp.io/support/questions/8622/How-to-enable-Debug-logs-for-troubleshoot-problems

    Thanks.

    Hi,

    Here is an example of the error: Volo.Abp.Domain.Entities.EntityNotFoundException: There is no such an entity. Entity type: Volo.Abp.Identity.IdentityUser, id: 3a1b19ed-1b99-0633-bfaf-f2bbd8fa0af3 at Volo.Abp.Identity.IdentityUserManager.GetByIdAsync(Guid id) at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo) at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue1.ProceedAsync() at Volo.Abp.Uow.UnitOfWorkInterceptor.InterceptAsync(IAbpMethodInvocation invocation) at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func3 proceed) at Volo.Abp.Identity.IdentityDynamicClaimsPrincipalContributorCache.<>c__DisplayClass23_0.<<GetAsync>b__0>d.MoveNext() --- End of stack trace from previous location --- at Volo.Abp.Caching.DistributedCache2.GetOrAddAsync(TCacheKey key, Func1 factory, Func1 optionsFactory, Nullable1 hideErrors, Boolean considerUow, CancellationToken token) at Volo.Abp.Identity.IdentityDynamicClaimsPrincipalContributorCache.GetAsync(Guid userId, Nullable1 tenantId) at Volo.Abp.Identity.IdentityDynamicClaimsPrincipalContributor.ContributeAsync(AbpClaimsPrincipalContributorContext context)

    If we then manually create the user, then it works on host but then fails on tenant untill we manually create the tenant. The different ABP solutions use completely separate databases.

  • User Avatar
    0
    AI-Bot created
    Support Team ABP Agent

    To achieve seamless single sign-on (SSO) across multiple ABP-based solutions using a shared OpenIddict auth server, you must ensure that tenants and users are synchronized across all client applications. ABP does not provide built-in automatic tenant/user provisioning out-of-the-box for this scenario, but you can implement the following approach:

    1. Programmatic Tenant and User Creation:

      • Implement logic in your client applications (host APIs) to detect when an authenticated user or tenant does not exist in the local database.
      • When a user logs in via OpenIddict and is authenticated, check if the corresponding tenant and user exist in your application's database.
      • If not, programmatically create the tenant and user using the appropriate ABP services (ITenantAppService, IIdentityUserAppService).
      • This can be done in a custom authentication event handler or middleware that runs after token validation.

      Example (simplified):

    public class CustomOpenIddictEvents : OpenIddictServerEvents.Authentication
       {
           public override async Task HandleAsync(AuthenticationContext context)
           {
               var tenantService = context.HttpContext.RequestServices.GetRequiredService<ITenantAppService>();
               var userService = context.HttpContext.RequestServices.GetRequiredService<IIdentityUserAppService>();
               var tenantName = /* extract from claims or token */;
               var userName = /* extract from claims or token */;
    
               // Check and create tenant if needed
               var tenant = await tenantService.FindByNameAsync(tenantName);
               if (tenant == null)
               {
                   await tenantService.CreateAsync(new TenantCreateDto { Name = tenantName });
               }
    
               // Check and create user if needed
               var user = await userService.FindByUserNameAsync(userName);
               if (user == null)
               {
                   await userService.CreateAsync(new IdentityUserCreateDto { UserName = userName, ... });
               }
           }
       }
    
    1. Session Context for ICurrentUser and ICurrentTenant:

      • Ensure that after provisioning, the correct tenant and user context is set for the current request.
      • ABP resolves ICurrentUser and ICurrentTenant based on the claims in the access token and the tenant resolution strategy (domain, header, etc.).
      • If your token contains the correct tenantid and user claims, and your tenant/user exists in the database, ABP will resolve the context automatically.
    2. Alternative Approach: Centralized User/Tenant Store:

      • Instead of duplicating tenants and users in each solution, consider using a shared database for user and tenant management across all ABP solutions.
      • Configure all client applications to use the same connection string for the identity and tenant tables.
      • This ensures that user and tenant data is always in sync, and SSO works seamlessly.
    3. Best Practice:

      • The recommended approach is to use a shared identity/tenant store if possible.
      • If you must keep separate databases, implement the programmatic provisioning logic as described above.

    No official ABP documentation provides a ready-made solution for automatic cross-solution tenant/user provisioning, but the above approach aligns with ABP's extensibility model and common practices.

    This approach aligns with common ABP conventions, but specific official documentation for this exact scenario is not available.


    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.

  • User Avatar
    0
    luciana created

    Does the tenant and the user absolutely need to exist? The example does not compile. Is there either more docs or other support tickets or examples that we can refer to?

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    Volo.Abp.Domain.Entities.EntityNotFoundException: There is no such an entity. Entity type: Volo.Abp.Identity.IdentityUser, id: 3a1b19ed-1b99-0633-bfaf-f2bbd8fa0af3
    at Volo.Abp.Identity.IdentityUserManager.GetByIdAsync(Guid id)
    

    Why does this user not exist?

    Is your application using the same database as the auth server(openiddit)?

    Thanks.

  • User Avatar
    0
    luciana created

    [maliming] said: hi

    Volo.Abp.Domain.Entities.EntityNotFoundException: There is no such an entity. Entity type: Volo.Abp.Identity.IdentityUser, id: 3a1b19ed-1b99-0633-bfaf-f2bbd8fa0af3 
    at Volo.Abp.Identity.IdentityUserManager.GetByIdAsync(Guid id) 
    

    Why does this user not exist?

    Is your application using the same database as the auth server(openiddit)?

    Thanks.

    Hi, No separate databases.

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    Your host api depends on the Identity module.

    They should use the Identity database.

    {
      "ConnectionStrings": {
        "Default": "Server=localhost;",
        "AbpIdentity": "Server=localhost;"
      }
    }
    

    You can also remove the Identity module from your host api

    Thanks.

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.0.0-preview. Updated on September 01, 2025, 08:37