Sumeyye
I should clarify that I am using a Tiered Blazor project, not a microservice. I don't have a Gateway/Mobile project. Looks like that comes when you are doing a microservice project but I may be wrong.
I will send over the base project, Appreciate your support on this.
Thank you
Here is the Identity/Auth Server Log:
2025-08-18 20:32:42.304 -04:00 [DBG] The event OpenIddict.Server.OpenIddictServerEvents+ProcessSignInContext was successfully processed by OpenIddict.Server.AspNetCore.OpenIddictServerAspNetCoreHandlers+ResolveHostSignInProperties.
2025-08-18 20:32:42.305 -04:00 [DBG] The event OpenIddict.Server.OpenIddictServerEvents+ProcessSignInContext was successfully processed by OpenIddict.Server.OpenIddictServerHandlers+ValidateSignInDemand.
2025-08-18 20:32:42.305 -04:00 [DBG] The event OpenIddict.Server.OpenIddictServerEvents+ProcessSignInContext was successfully processed by OpenIddict.Server.OpenIddictServerHandlers+RedeemTokenEntry.
2025-08-18 20:32:42.305 -04:00 [DBG] The event OpenIddict.Server.OpenIddictServerEvents+ProcessSignInContext was successfully processed by OpenIddict.Server.OpenIddictServerHandlers+RestoreInternalClaims.
2025-08-18 20:32:42.306 -04:00 [DBG] The event OpenIddict.Server.OpenIddictServerEvents+ProcessSignInContext was successfully processed by OpenIddict.Server.OpenIddictServerHandlers+AttachHostProperties.
2025-08-18 20:32:42.306 -04:00 [DBG] The event OpenIddict.Server.OpenIddictServerEvents+ProcessSignInContext was successfully processed by OpenIddict.Server.OpenIddictServerHandlers+AttachDefaultScopes.
2025-08-18 20:32:42.306 -04:00 [DBG] The event OpenIddict.Server.OpenIddictServerEvents+ProcessSignInContext was successfully processed by OpenIddict.Server.OpenIddictServerHandlers+AttachDefaultPresenters.
2025-08-18 20:32:42.306 -04:00 [DBG] The event OpenIddict.Server.OpenIddictServerEvents+ProcessSignInContext was successfully processed by OpenIddict.Server.OpenIddictServerHandlers+InferResources.
2025-08-18 20:32:42.306 -04:00 [DBG] The event OpenIddict.Server.OpenIddictServerEvents+ProcessSignInContext was successfully processed by OpenIddict.Server.OpenIddictServerHandlers+EvaluateGeneratedTokens.
2025-08-18 20:32:42.306 -04:00 [DBG] The event OpenIddict.Server.OpenIddictServerEvents+ProcessSignInContext was successfully processed by OpenIddict.Server.OpenIddictServerHandlers+AttachAuthorization.
2025-08-18 20:32:42.309 -04:00 [DBG] The event OpenIddict.Server.OpenIddictServerEvents+ProcessSignInContext was successfully processed by OpenIddict.Server.OpenIddictServerHandlers+PrepareAuthorizationCodePrincipal.
2025-08-18 20:32:42.315 -04:00 [DBG] Creating identity session for session id: 66aa238b-b694-49ed-93e0-3a957abdb9a5, device: OAuth, user id: b0720c2d-b561-bf72-6f7c-3a1bcc7809ea, tenant id: , client id: New2_Mobile
2025-08-18 20:32:42.325 -04:00 [DBG] The event OpenIddict.Server.OpenIddictServerEvents+ProcessSignInContext was successfully processed by Volo.Abp.Account.Web.Pages.Account.OpenIddictCreateIdentitySession.
2025-08-18 20:32:42.325 -04:00 [DBG] The event OpenIddict.Server.OpenIddictServerEvents+ProcessSignInContext was successfully processed by OpenIddict.Server.OpenIddictServerHandlers+AttachCustomSignInParameters.
2025-08-18 20:32:42.326 -04:00 [DBG] The event OpenIddict.Server.OpenIddictServerEvents+GenerateTokenContext was successfully processed by OpenIddict.Server.OpenIddictServerHandlers+Protection+AttachSecurityCredentials.
2025-08-18 20:32:42.356 -04:00 [DBG] The event OpenIddict.Server.OpenIddictServerEvents+GenerateTokenContext was successfully processed by OpenIddict.Server.OpenIddictServerHandlers+Protection+CreateTokenEntry.
2025-08-18 20:32:42.360 -04:00 [DBG] The event OpenIddict.Server.OpenIddictServerEvents+GenerateTokenContext was successfully processed by OpenIddict.Server.OpenIddictServerHandlers+Protection+GenerateIdentityModelToken.
2025-08-18 20:32:42.400 -04:00 [DBG] The event OpenIddict.Server.OpenIddictServerEvents+GenerateTokenContext was successfully processed by OpenIddict.Server.OpenIddictServerHandlers+Protection+AttachTokenPayload.
2025-08-18 20:32:42.400 -04:00 [DBG] The event OpenIddict.Server.OpenIddictServerEvents+ProcessSignInContext was successfully processed by OpenIddict.Server.OpenIddictServerHandlers+GenerateAuthorizationCode.
2025-08-18 20:32:42.400 -04:00 [DBG] The event OpenIddict.Server.OpenIddictServerEvents+ProcessSignInContext was successfully processed by OpenIddict.Server.OpenIddictServerHandlers+BeautifyGeneratedTokens.
2025-08-18 20:32:42.400 -04:00 [DBG] The event OpenIddict.Server.OpenIddictServerEvents+ProcessSignInContext was successfully processed by OpenIddict.Server.OpenIddictServerHandlers+AttachSignInParameters.
2025-08-18 20:32:42.401 -04:00 [DBG] The event OpenIddict.Server.OpenIddictServerEvents+ApplyAuthorizationResponseContext was successfully processed by OpenIddict.Server.OpenIddictServerHandlers+Authentication+AttachRedirectUri.
2025-08-18 20:32:42.401 -04:00 [DBG] The event OpenIddict.Server.OpenIddictServerEvents+ApplyAuthorizationResponseContext was successfully processed by OpenIddict.Server.OpenIddictServerHandlers+Authentication+InferResponseMode.
2025-08-18 20:32:42.401 -04:00 [DBG] The event OpenIddict.Server.OpenIddictServerEvents+ApplyAuthorizationResponseContext was successfully processed by OpenIddict.Server.OpenIddictServerHandlers+Authentication+AttachResponseState.
2025-08-18 20:32:42.401 -04:00 [DBG] The event OpenIddict.Server.OpenIddictServerEvents+ApplyAuthorizationResponseContext was successfully processed by OpenIddict.Server.OpenIddictServerHandlers+Authentication+AttachIssuer.
2025-08-18 20:32:42.401 -04:00 [DBG] The event OpenIddict.Server.OpenIddictServerEvents+ApplyAuthorizationResponseContext was successfully processed by Volo.Abp.OpenIddict.Globalization.AttachCultureInfo.
2025-08-18 20:32:42.401 -04:00 [DBG] The event OpenIddict.Server.OpenIddictServerEvents+ApplyAuthorizationResponseContext was successfully processed by OpenIddict.Server.AspNetCore.OpenIddictServerAspNetCoreHandlers+AttachHttpResponseCode1[[OpenIddict.Server.OpenIddictServerEvents+ApplyAuthorizationResponseContext, OpenIddict.Server, Version=6.4.0.0, Culture=neutral, PublicKeyToken=35a561290d20de2f]]. 2025-08-18 20:32:42.401 -04:00 [DBG] The event OpenIddict.Server.OpenIddictServerEvents+ApplyAuthorizationResponseContext was successfully processed by OpenIddict.Server.AspNetCore.OpenIddictServerAspNetCoreHandlers+AttachCacheControlHeader
1[[OpenIddict.Server.OpenIddictServerEvents+ApplyAuthorizationResponseContext, OpenIddict.Server, Version=6.4.0.0, Culture=neutral, PublicKeyToken=35a561290d20de2f]].
2025-08-18 20:32:42.401 -04:00 [DBG] The event OpenIddict.Server.OpenIddictServerEvents+ApplyAuthorizationResponseContext was successfully processed by OpenIddict.Server.AspNetCore.OpenIddictServerAspNetCoreHandlers+Authentication+ProcessSelfRedirection.
2025-08-18 20:32:42.401 -04:00 [DBG] The event OpenIddict.Server.OpenIddictServerEvents+ApplyAuthorizationResponseContext was successfully processed by OpenIddict.Server.AspNetCore.OpenIddictServerAspNetCoreHandlers+Authentication+ProcessFormPostResponse.
2025-08-18 20:32:42.401 -04:00 [INF] The authorization response was successfully returned to 'exp://10.0.2.2:19000' using the query response mode: {
"code": "[redacted]",
"state": "4mGnTeKDTO",
"iss": "http://10.0.2.2:44322/",
"culture": "en",
"ui-culture": "en"
}.
2025-08-18 20:32:42.402 -04:00 [DBG] The event OpenIddict.Server.OpenIddictServerEvents+ApplyAuthorizationResponseContext was successfully processed by OpenIddict.Server.AspNetCore.OpenIddictServerAspNetCoreHandlers+Authentication+ProcessQueryResponse.
2025-08-18 20:32:42.402 -04:00 [DBG] The event OpenIddict.Server.OpenIddictServerEvents+ApplyAuthorizationResponseContext was marked as handled by OpenIddict.Server.AspNetCore.OpenIddictServerAspNetCoreHandlers+Authentication+ProcessQueryResponse.
2025-08-18 20:32:42.402 -04:00 [DBG] The event OpenIddict.Server.OpenIddictServerEvents+ProcessSignInContext was successfully processed by OpenIddict.Server.OpenIddictServerHandlers+Authentication+ApplyAuthorizationResponse1[[OpenIddict.Server.OpenIddictServerEvents+ProcessSignInContext, OpenIddict.Server, Version=6.4.0.0, Culture=neutral, PublicKeyToken=35a561290d20de2f]]. 2025-08-18 20:32:42.402 -04:00 [DBG] The event OpenIddict.Server.OpenIddictServerEvents+ProcessSignInContext was marked as handled by OpenIddict.Server.OpenIddictServerHandlers+Authentication+ApplyAuthorizationResponse
1[[OpenIddict.Server.OpenIddictServerEvents+ProcessSignInContext, OpenIddict.Server, Version=6.4.0.0, Culture=neutral, PublicKeyToken=35a561290d20de2f]].
2025-08-18 20:32:42.402 -04:00 [INF] Executed action Volo.Abp.OpenIddict.Controllers.AuthorizeController.HandleAsync (Volo.Abp.OpenIddict.AspNetCore) in 294.8017ms
2025-08-18 20:32:42.402 -04:00 [INF] Executed endpoint 'Volo.Abp.OpenIddict.Controllers.AuthorizeController.HandleAsync (Volo.Abp.OpenIddict.AspNetCore)'
2025-08-18 20:32:42.410 -04:00 [INF] Request finished HTTP/1.1 GET http://10.0.2.2:44322/connect/authorize?code_challenge=xq93uUcSpC3iTHaU0pF1JAgT8WqNySU2dDGPOS209qI&code_challenge_method=S256&redirect_uri=exp%3A%2F%2F10.0.2.2%3A19000&client_id=New2_Mobile&response_type=code&state=4mGnTeKDTO&scope=offline_access+New2 - 302 0 null 607.4527ms
Here is my Environment:
import { Environment } from '@new2/models';
const yourIP = '10.0.2.2'; // See the docs https://docs.abp.io/en/abp/latest/Getting-Started-React-Native?Tiered=No
const apiUrl = http://${yourIP}:44359
;
const issuerUrl = http://${yourIP}:44322
;
const dev = {
apiUrl,
appUrl: exp://${yourIP}:19000
,
oAuthConfig: {
issuer: issuerUrl,
clientId: 'New2_Mobile',
scope: 'offline_access New2',
},
localization: {
defaultResourceName: 'New2',
},
} as Environment;
The AI response outlines everything I have done at this moment. Would request further guidance.
I am working on adding a mobile app utilizing react-native to my project. To test this prior to fully integrating, I used ABP Studio to create a new tiered project to test with. I adjusted the following:
I was able to get the android emulator to load the project up, click login on the home page and redirect me to the Auth Server login. But it would fail on the return due to the 192.16X.X.X not matching the app url of the mobile device for whatever reason it was submitting as 10. instead of my specified 192. IP address.
So I adjusted the following.
After changing these, I was able to get a successful code response, but the redirect was still coming back as 192.16X.X.X and there for the login on the mobile app return to the home screen as if the user was not authenticated and present the login button vs other options for standard features included.
At this point, I believe I have followed everything in the tutorial on this topic, I have a successful authentication loop occurring from mobile to Auth back to mobile. I by no means am an react-native expert so I consider this a learning activity at this point. What could I potentially be missing? I've rebuilt this twice using a ABP Studio generated project. I'm sure this is something simple that I've missed.
Environment.ts update:
const yourIP = '10.0.2.2';
const apiUrl = http://${yourIP}:44359
;
const issuerUrl = http://${yourIP}:44322
;
const dev = {
apiUrl,
appUrl: exp://${yourIP}:19000
,
oAuthConfig: {
issuer: issuerUrl,
clientId: 'New2_Mobile',
scope: 'offline_access New2',
},
localization: {
defaultResourceName: 'New2',
},
} as Environment;
Here is the Auth server response to the clicking of the login button and the browser login event.
[20:32:42 INF] The authorization response was successfully returned to 'exp://10.0.2.2:19000' using the query response mode: {
"code": "[redacted]",
"state": "4mGnTeKDTO",
"iss": "http://10.0.2.2:44322/",
"culture": "en",
"ui-culture": "en"
}.
[20:32:42 DBG] The event OpenIddict.Server.OpenIddictServerEvents+ApplyAuthorizationResponseContext was successfully processed by OpenIddict.Server.AspNetCore.OpenIddictServerAspNetCoreHandlers+Authentication+ProcessQueryResponse.
[20:32:42 DBG] The event OpenIddict.Server.OpenIddictServerEvents+ApplyAuthorizationResponseContext was marked as handled by OpenIddict.Server.AspNetCore.OpenIddictServerAspNetCoreHandlers+Authentication+ProcessQueryResponse.
[20:32:42 DBG] The event OpenIddict.Server.OpenIddictServerEvents+ProcessSignInContext was successfully processed by OpenIddict.Server.OpenIddictServerHandlers+Authentication+ApplyAuthorizationResponse1[[OpenIddict.Server.OpenIddictServerEvents+ProcessSignInContext, OpenIddict.Server, Version=6.4.0.0, Culture=neutral, PublicKeyToken=35a561290d20de2f]]. [20:32:42 DBG] The event OpenIddict.Server.OpenIddictServerEvents+ProcessSignInContext was marked as handled by OpenIddict.Server.OpenIddictServerHandlers+Authentication+ApplyAuthorizationResponse
1[[OpenIddict.Server.OpenIddictServerEvents+ProcessSignInContext, OpenIddict.Server, Version=6.4.0.0, Culture=neutral, PublicKeyToken=35a561290d20de2f]].
[20:32:42 INF] Executed action Volo.Abp.OpenIddict.Controllers.AuthorizeController.HandleAsync (Volo.Abp.OpenIddict.AspNetCore) in 294.8017ms
[20:32:42 INF] Executed endpoint 'Volo.Abp.OpenIddict.Controllers.AuthorizeController.HandleAsync (Volo.Abp.OpenIddict.AspNetCore)'
[20:32:42 INF] Request finished HTTP/1.1 GET http://10.0.2.2:44322/connect/authorize?code_challenge=xq93uUcSpC3iTHaU0pF1JAgT8WqNySU2dDGPOS209qI&code_challenge_method=S256&redirect_uri=exp%3A%2F%2F10.0.2.2%3A19000&client_id=New2_Mobile&response_type=code&state=4mGnTeKDTO&scope=offline_access+New2 - 302 0 null 607.4527ms
My custom subdomain resolver excludes various subdomains such as uat, api, auth which are used for the various services as well as the uat base in this case is for the host.
I have previously added the following to AddAbpOpenIdConnect options
options.Events.OnRedirectToIdentityProvider = context =>
{
var httpContext = context.HttpContext;
var currentTenant = httpContext.RequestServices
.GetRequiredService<ICurrentTenant>();
if (currentTenant?.Name != null)
{
context.ProtocolMessage.SetParameter("tenant", currentTenant.Name);
}
else
{
// On host tenant access, ensure we don't leak the last tenant
context.ProtocolMessage.Parameters.Remove("tenant");
context.HttpContext.Response.Cookies.Delete("Abp.TenantId");
}
return Task.CompletedTask;
};
I am certainly missing something, and or if my approach is non-standard, please advise and I'll adjust. For Management of the URL and SSL certificates I was attempting to use just a base auth.uat.domain.io address without creating a new cert to support wildcard *.auth.uat.domain.io.
UI: Blazor
DB: EF Core
Tiered Project
**Objective: **
Deploy a Blazor App that resolves tenant based on subdomain in a UAT and a Production environment. Right now I just have the UAT environment which is reachable like uat.domain.io. If I visit the tenant it is tenant1.uat.domain.io I want the login page on authentication server to know that tenant1 is the Tenant.
Additional details.
Authentication server is hosted at auth.uat.domain.io
API Server is hosted on api.uat.domain.io
Blazor App Server is hosted on uat.domain.io with wildecards enabled
What I expect to Happen:
User visits tenant.uat.domain.io
Application validates Tenant on Blazor app and directs to Account/Login on Auth Server
Auth Server validates Tenant without using subdomain (limiting this to just point to auth.uat.domain.io)
If no Subdomain or tenant resolved assume host
If tenant resolved on blazor side from subdomain, then use that tenant for logging in as well via querystring or other methods of sharing.
What is happening:
When visiting the domain as uat.domain.io where the user has previously logged in (but logged out) The login page retains the previous tenant regardless of if visiting uat.domain.io or tenant2.uat.domain.io.
If I start an incognito window and visit tenant1.uat.domain.io the tenant resolves to the host tenant regardless of subdomain.
I setup a custom Querystring tenant resolver on auth to resolve tenant from the URL (its embedded in the returnurl) and get the authserver to resolve my tenant but then it reverts to host as final
** Log information** 2025-06-22 00:33:39.670 +00:00 [INF] The authorization request was successfully extracted: { "client_id": "BlazorServer", "redirect_uri": "https://mytenant.uat.domain.io/signin-oidc", "response_type": "code id_token", "scope": "openid profile roles email phone ", "response_mode": "form_post", "nonce": "638861492195962570.YTM1NDAwNjctOTg2Ny00Njc0LTkxNTAtY2UwNzY5ZDdhOWY3MGU4NWU4ZGEtZGYxYi00NTEwLWJmYjctYWJkZmQ5YjE5ZDIy", "tenant": "mytenant", "state": "Q", "x-client-SKU": "ID_NET9_0", "x-client-ver": "8.3.0.0" }. 2025-06-22 00:33:39.701 +00:00 [INF] AuthServer OIDC: ValidateAuthorizationRequest for tenant: (host) 2025-06-22 00:33:39.702 +00:00 [INF] The authorization request was successfully validated.
Blazor Module Code Snippet Configure<AbpTenantResolveOptions>(options => { options.TenantResolvers.Clear(); options.TenantResolvers.Insert(0, new SubdomainTenantResolveContributor()); options.TenantResolvers.Add(new QueryStringTenantResolveContributor()); options.TenantResolvers.Add(new HeaderTenantResolveContributor()); options.TenantResolvers.Add(new CookieTenantResolveContributor()); });
public class SubdomainTenantResolveContributor : ITenantResolveContributor { public string Name => "Subdomain";
private static readonly string[] NonTenantSubdomains = {
"localhost", "www", "auth", "api", "uat"
};
public Task ResolveAsync(ITenantResolveContext context)
{
var httpContextAccessor = context.ServiceProvider.GetService<IHttpContextAccessor>();
var logger = context.ServiceProvider.GetService<ILogger<SubdomainTenantResolveContributor>>();
var host = httpContextAccessor?.HttpContext?.Request?.Host.Host;
string resolvedTenant = null;
if (!string.IsNullOrWhiteSpace(host))
{
var parts = host.Split('.');
var subdomain = parts.FirstOrDefault()?.ToLowerInvariant();
// Exclude known non-tenant subdomains and azurewebsites
if (!string.IsNullOrWhiteSpace(subdomain)
&& !NonTenantSubdomains.Contains(subdomain)
&& !host.Contains("azurewebsites.net"))
{
resolvedTenant = subdomain;
context.TenantIdOrName = resolvedTenant;
}
logger?.LogInformation("SubdomainTenantResolveContributor - Host: {Host}, ResolvedTenant: {Tenant}", host, resolvedTenant ?? "(none)");
}
else
{
logger?.LogWarning("SubdomainTenantResolveContributor - No host available from HttpContext.");
}
return Task.CompletedTask;
}
}
Auth Server Module: Configure<AbpTenantResolveOptions>(options => { options.TenantResolvers.Clear(); options.TenantResolvers.Insert(0, new ReturnUrlQueryTenantResolveContributor()); options.TenantResolvers.Insert(1, new CookieTenantResolveContributor()); options.TenantResolvers.Add(new QueryStringTenantResolveContributor()); options.TenantResolvers.Add(new HeaderTenantResolveContributor());
});
public class ReturnUrlQueryTenantResolveContributor : ITenantResolveContributor { public string Name => "ReturnUrlQuery";
public async Task ResolveAsync(ITenantResolveContext context)
{
var serviceProvider = context.ServiceProvider;
var httpContextAccessor = serviceProvider.GetService(typeof(IHttpContextAccessor)) as IHttpContextAccessor;
var logger = serviceProvider.GetService(typeof(ILogger<ReturnUrlQueryTenantResolveContributor>)) as ILogger;
var request = httpContextAccessor?.HttpContext?.Request;
//var response = httpContextAccessor?.HttpContext?.Response;
if (request == null)
{
logger?.LogWarning("No HttpContext found.");
return;
}
var returnUrl = request.Query["ReturnUrl"].FirstOrDefault();
if (string.IsNullOrWhiteSpace(returnUrl))
{
logger?.LogDebug("ReturnUrl missing or empty.");
return;
}
try
{
var decodedUrl = Uri.UnescapeDataString(returnUrl);
var queryIndex = decodedUrl.IndexOf('?');
if (queryIndex >= 0)
{
var queryString = decodedUrl.Substring(queryIndex);
var parsedQuery = QueryHelpers.ParseQuery(queryString);
if (parsedQuery.TryGetValue("tenant", out StringValues tenantValues))
{
var tenant = tenantValues.FirstOrDefault();
if (!string.IsNullOrWhiteSpace(tenant))
{
context.TenantIdOrName = tenant;
context.Handled = true;
//if (response == null)
//{
// logger?.LogWarning("No HttpContext Response found.");
// return;
//}
//response.Cookies.Append("Abp.TenantId", tenant, new CookieOptions
//{
// HttpOnly = true,
// Secure = request.IsHttps,
// SameSite = SameSiteMode.Lax,
// Path = "/"
//});
logger?.LogInformation("Tenant resolved from ReturnUrl: {Tenant}", tenant);
}
}
}
}
catch (Exception ex)
{
logger?.LogError(ex, "Error parsing tenant from ReturnUrl.");
}
await Task.CompletedTask;
}
}