Open Closed

How to Authenticate Between Two ABP Web Applications Using OpenID and SSO #10245


User avatar
0
williamT.B8 created

I have two ABP web solutions.

Solution 1 already has an OpenID application configured. In Solution 2, I want to use the same OpenID application (client ID and client secret) to connect to Solution 1 and authenticate using the currently logged-in user’s identity.

In Solution 2, users may log in using SSO, so there is no password available to pass to the OpenID access_token API. The username (email address) is available, but not the password.

Additionally, the user may not already exist in Solution 1.

What is the recommended approach to handle this scenario?

Should users be automatically provisioned in Solution 1?

Is there a specific OpenID/OpenIddict flow recommended when only the user’s email is available?

How should authentication be handled when user credentials are not available due to SSO?


16 Answer(s)
  • User Avatar
    0
    AI-Bot created
    Support Team ABP Agent
    1. Solution
    • Use Centralized Authentication (one Auth Server) and OIDC sign-in, not password-based token requests:

      • Treat Solution 1 as the single OpenIddict Authorization Server (AuthServer).
      • Register each frontend/back‑end of Solution 2 as OpenIddict client applications on Solution 1.
      • In Solution 2, authenticate users via standard OpenID Connect browser flow (Authorization Code, with PKCE for SPAs if any). Never call the token endpoint with username/password when users come from SSO.
    • Automatic user provisioning on first external login (recommended):

      • ABP’s Account module supports external/third‑party logins and can create a local user automatically on first login when external provider returns required claims (e.g., email). This allows Solution 2 users to appear in Solution 1’s identity store without knowing their password.
      • Ensure your OIDC configuration requests the email scope and maps sub -> NameIdentifier so ABP can provision users.
      • If you must restrict auto‑provisioning, handle the external login callback to apply custom rules or block creation.
    • Don’t reuse the same confidential client credentials across different sites arbitrarily:

      • Create a dedicated client for each app of Solution 2 in Solution 1’s OpenIddict (distinct client_id, secret if confidential, redirect URIs).
      • Register exact redirect URIs and post-logout redirect URIs used by Solution 2.
      • Grant the correct flows: for MVC server-side apps use authorization_code (+ refresh_token); for SPAs use authorization_code with PKCE; avoid resource owner password flow for SSO scenarios.
    • When only email is available (no password):

      • Use OIDC Authorization Code flow. The user authenticates at Solution 1 (AuthServer) using whatever SSO/external IdP it trusts (Azure AD, Google, etc.). Your Solution 2 does not and should not need the user’s password.
      • Ensure Solution 1 returns email and profile claims. In ABP, add options.Scope.Add("email") (and profile) in your OpenIdConnect configuration so the Account module can create/link the user on first login.
    • Practical steps

      1. In Solution 1 (AuthServer):
        • Define API scopes/resources needed by Solution 2.
        • Seed OpenIddict client applications for Solution 2 with:
          • client_id and client_secret (if confidential),
          • allowed grant types: authorization_code (+ refresh_token), optionally PKCE,
          • redirectUris/postLogoutRedirectUris matching Solution 2’s public URLs,
          • scopes: openid, profile, email, offline_access (+ your API scopes).
      2. In Solution 2 (MVC):
        • Add OpenID Connect authentication pointing to Solution 1’s authority:
    services.AddAuthentication()
             .AddCookie()
             .AddOpenIdConnect("oidc", "AuthServer", options =>
             {
                 options.Authority = configuration["AuthServer:Authority"];
                 options.RequireHttpsMetadata = true;
                 options.ClientId = configuration["AuthServer:ClientId"];
                 options.ClientSecret = configuration["AuthServer:ClientSecret"];
                 options.ResponseType = "code";
                 options.UsePkce = true;
                 options.SaveTokens = true;
    
                 options.Scope.Clear();
                 options.Scope.Add("openid");
                 options.Scope.Add("profile");
                 options.Scope.Add("email");
                 options.Scope.Add("offline_access");
                 options.Scope.Add("MySolution2Api"); // your API scope(s)
    
                 // Important for ABP external login handling:
                 options.ClaimActions.MapJsonKey(System.Security.Claims.ClaimTypes.NameIdentifier, "sub");
                 options.GetClaimsFromUserInfoEndpoint = true; // or false if you rely on id_token only
             });
    
     - Ensure cookies are configured and the app uses the OIDC challenge for sign-in.
    
    1. Enable ABP external login auto‑provisioning behavior:
      • With email scope present, ABP’s Account module can create the user locally on first login. If you’ve customized login, keep the mapping for sub → NameIdentifier and ensure email is present.
    2. If you run behind reverse proxies/ingress:
      • Register HTTPS redirect URIs that exactly match the browser-facing URLs.
      • Enable forwarded headers so ASP.NET Core and OIDC handlers generate correct https URLs.
    • Summary answers to your questions
      • Recommended approach: Centralized authentication via Solution 1 as AuthServer; Solution 2 signs in via OIDC Authorization Code flow. No password needed.
      • Auto-provision users in Solution 1? Yes, recommended. ABP supports creating the user on first external login if required claims are provided.
      • Specific flow when only email is available? Authorization Code flow (with PKCE for SPA). Request email scope so ABP can provision/link the user.
      • Handling authentication without credentials due to SSO: Never use ROPC or call token endpoint with username/password. Always use browser-based OIDC flow against the central AuthServer; rely on claims and ABP’s external login user provisioning.
    1. Sources
    • Centralized authentication and external IdPs with ABP (validated):
      • https://documentation.openiddict.com/
      • https://github.com/abpframework/abp
    • Community guides showing ABP OIDC external login, scopes and mapping:
      • https://learn.microsoft.com/en-us/aspnet/core/security/authentication/social/?view=aspnetcore-8.0

    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
    maliming created
    Support Team Fullstack Developer

    hi

    Solution 1 already has an OpenID application configured.

    In Solution 2, I want to use the same OpenID application (client ID and client secret) to connect to Solution 1 and authenticate using the currently logged-in user’s identity. In Solution 2, users may log in using SSO, so there is no password available to pass to the OpenID access_token API. The username (email address) is available, but not the password.

    Do you mean you have integrated OpenIddict in Solution 1 and want to add it to Solution 2 as well?

    Typically, you only need one authserver project.

    All of your users exist and are managed in solution 1, your solution 2 can use solution 1 to signin.

    If you have changed these two solution codes. Please share the module code for them.

    liming.ma@volosoft.com

    Thanks.

  • User Avatar
    0
    williamT.B8 created

    Hi,

    in solution 2 I want similar to /connect/token where the user get access to solution 1 APIs without exposing solution 1 to the client. Will use Refit to communicate from solution 2 to solution 1 from the backend. However, in the future I'd like to add SSO and /connect/token requires password which is a blocker.

    Additionally, how do I make sure the user managed in solution 1? I tried the following code but it still force me to register user in solution 2 after successful login on this OIDC

    // in ConfigureExternalProviders 
    context.Services
        .AddAuthentication()
        .AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, "Test", options =>
        {
            options.Authority = context.Configuration["Test:Authority"];
            options.RequireHttpsMetadata = true;
            options.ClientId = context.Configuration["Test:ClientId"];
            options.ClientSecret = context.Configuration["Test:ClientSecret"];
            options.ResponseType = OpenIdConnectResponseType.Code;
            options.UsePkce = true;
            options.SaveTokens = true;
        
            //options.Scope.Add("openid");
            options.Scope.Add("profile");
            options.Scope.Add("email");
            //options.Scope.Add("offline_access");
            options.Scope.Add("Test");
        
            options.CallbackPath = "/signin-oidc"; // have tried without this. 
        
            // Important for ABP external login handling:
            options.GetClaimsFromUserInfoEndpoint = true; // or false if you rely on id_token only
            options.ClaimActions.MapJsonKey(System.Security.Claims.ClaimTypes.NameIdentifier, "sub");
        })
    

    Note: I also have created the OpenId application in solution 1 to use on the code block above. the application setting is in the screenshot below

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    Not recommended to be an authserver in both solutions. Do these two solutions share the same user database?

    Thanks.

  • User Avatar
    0
    williamT.B8 created

    After further consideration, you're right it should have different user database.

    However, user in solution 2 should also exists in solution 1 but if I create new user in solution 1 it doesn't have to exists in solution 2. My main concern is how do I call solution 1 API from solution 2 where the API use currentUser.email for example, so it recognize the email of the user.

    Regards,

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    1. Two solutions have independent databases.
    2. Solution 1 is the main auth server.
    3. Solution 2 is also an auth server, but it adds an external login provider that targets Solution 1.

    Web app 2 -> login -> redirect to solution 2 login page -> click login by solution 1 -> redirect to solution 1 login page -> password login solution 1 -> redirect to solution 2:

    1. If the same user email exists in solution 2 -> redirect to web app 2. 1.1 Web app 2 has a token issued by solution 2
    2. if the same user email doesn't exist in solution 2 -> register a new user in solution 2 2.1 Web app 2 has a token issued by solution 2

    Web app 1 -> login -> redirect to solution 1 login page -> password login solution 1 -> redirect to web app 1:

    Web app 1 has a token issued by solution 1

    Thanks.

  • User Avatar
    0
    williamT.B8 created

    Hi,

    if i follow this step :

    1. in web app 2, login solution 1
    2. password login solution 1
    3. redirect to solution 2.
    • what if i want to implement SSO ?
    • how do I communicate to solution 1 from solution 2 ? I currently follow the step above with the code block I posted at the start, but I still cannot communicate with solution 1 API. If im correct its mainly because there is no access_token?
  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    The above steps have already logged into two applications. Why do you need them to communicate with each other?

    Thanks.

  • User Avatar
    0
    williamT.B8 created

    Hi,

    yes but I can't call solution 1 API from solution 2. There is a feature from solution 1 that I need on solution 2 and prefer not to create duplicate code.

    Is there another way to achieve it?

    Regards,

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    You can define a new OAuth2 Application/Client in solution 1, then use it to get a token from solution 1 in solution 2 and call the API.

    You can use client_credentials or password to get a token.

    Thanks.

  • User Avatar
    0
    williamT.B8 created

    is there any abp guide to use the client_credentials for login?

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    You can create a new Application in the ABP OpenIDDict module page.

    And then use it to get an access token

    
    using IdentityModel.Client;
    using System;
    using System.Net.Http;
    using System.Threading.Tasks;
    
    public class Program
    {
        public static async Task Main(string[] args)
        {
            // 1. Create an HttpClient instance
            var client = new HttpClient();
    
            // Optional: Set a base address if all requests go to the same IdentityServer
            // client.BaseAddress = new Uri("https://yoursolution1.com"); 
    
            // 2. Discover the token endpoint (recommended)
            // This dynamically finds the endpoint address from the discovery document
            var disco = await client.GetDiscoveryDocumentAsync("https://yoursolution1.com");
            if (disco.IsError)
            {
                Console.WriteLine(disco.Error);
                return;
            }
    
            // 3. Create the client credentials token request
            var request = new ClientCredentialsTokenRequest
            {
                Address = disco.TokenEndpoint, // Use the discovered token endpoint
                ClientId = "m2m", // Your client ID
                ClientSecret = "secret", // Your client secret
                Scope = "api" // The scope(s) you need access to
            };
    
            // 4. Send the request and await the response
            var tokenResponse = await client.RequestClientCredentialsTokenAsync(request);
    
            // 5. Check for errors and process the token
            if (tokenResponse.IsError)
            {
                Console.WriteLine(tokenResponse.Error);
                // Handle error, e.g., throw an exception or return
                return;
            }
    
            Console.WriteLine("Token retrieved successfully:");
            Console.WriteLine(tokenResponse.AccessToken);
        }
    }
    
    
  • User Avatar
    0
    williamT.B8 created

    Hi,

    Thank you,

    but if i Use Client Credentials token, what CurrentUser going to be?

    Regards,

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    There is no user concept in the Client Credentials flow. If you want to use a user, you can use the password flow.

    Thanks.

  • User Avatar
    0
    williamT.B8 created

    hmmm ok,

    but to use password, how can i get currentUser.password ?

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    You can't get the current user's password. Do you have to use a different user account?

    Client Credentials also works.

    Thanks.

Learn More, Pay Less
33% OFF
All Trainings!
Get Your Deal
Mastering ABP Framework Book
The Official Guide
Mastering
ABP Framework
Learn More
Mastering ABP Framework Book
Made with ❤️ on ABP v10.2.0-preview. Updated on January 09, 2026, 07:22
1
ABP Assistant
🔐 You need to be logged in to use the chatbot. Please log in first.