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)
-
0
- 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
- 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).
- In Solution 2 (MVC):
- Add OpenID Connect authentication pointing to Solution 1’s authority:
- In Solution 1 (AuthServer):
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.- 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.
- 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.
- 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.
-
0
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.
-
0
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

-
0
hi
Not recommended to be an authserver in both solutions. Do these two solutions share the same user database?
Thanks.
-
0
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.emailfor example, so it recognize the email of the user.Regards,
-
0
hi
- Two solutions have independent databases.
- Solution 1 is the main auth server.
- 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:- 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
- 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.
-
0
Hi,
if i follow this step :
- in web app 2, login solution 1
- password login solution 1
- 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?
-
0
hi
The above steps have already logged into two applications. Why do you need them to communicate with each other?
Thanks.
-
0
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,
-
0
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_credentialsorpasswordto get a token.Thanks.
-
0
is there any abp guide to use the
client_credentialsfor login? -
0
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); } } -
0
Hi,
Thank you,
but if i Use Client Credentials token, what
CurrentUsergoing to be?Regards,
-
0
hi
There is no user concept in the
Client Credentialsflow. If you want to use a user, you can use thepasswordflow.Thanks.
-
0
hmmm ok,
but to use password, how can i get currentUser.password ?
-
0
hi
You can't get the current user's password. Do you have to use a different user account?
Client Credentialsalso works.Thanks.