Activities of "JanneHarju"

Now I managed to get login to work but now token validation fails. It seems that it validates with old ClientId value and token contains updated clientId as it should. Here is error message what I received.

SecurityTokenInvalidAudienceException: IDX10214: Audience validation failed. Audiences: 'b7de466e-7846-45c4-bc91-099f3c89fdff'. Did not match: validationParameters.ValidAudience: '275a3f7d-b568-4865-92a5-6bf5df627e46' or validationParameters.ValidAudiences: 'null'.
Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler.ValidateTokenUsingHandlerAsync(string idToken, AuthenticationProperties properties, TokenValidationParameters validationParameters)
Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler.HandleRemoteAuthenticateAsync()

Show raw exception details
AuthenticationFailureException: An error was encountered while handling the remote login.
Microsoft.AspNetCore.Authentication.RemoteAuthenticationHandler<TOptions>.HandleRequestAsync()
Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
Volo.Abp.AspNetCore.Tracing.AbpCorrelationIdMiddleware.InvokeAsync(HttpContext context, RequestDelegate next)
Microsoft.AspNetCore.Builder.UseMiddlewareExtensions+InterfaceMiddlewareBinder+<>c__DisplayClass2_0+<<CreateMiddleware>b__0>d.MoveNext()
Microsoft.AspNetCore.Localization.RequestLocalizationMiddleware.Invoke(HttpContext context)
Microsoft.AspNetCore.RequestLocalization.AbpRequestLocalizationMiddleware.InvokeAsync(HttpContext context, RequestDelegate next)
Microsoft.AspNetCore.Builder.UseMiddlewareExtensions+InterfaceMiddlewareBinder+<>c__DisplayClass2_0+<<CreateMiddleware>b__0>d.MoveNext()
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)

And here is current solution what works this much.

authenticationBuilder.AddOpenIdConnect("AzureOpenId", "Azure AD", options =>
			{
				options.Authority = "https://login.microsoftonline.com/" + configuration["AzureAd:TenantId"] + "/v2.0/";
				options.ClientId = configuration["AzureAd:ClientId"];
				options.ResponseType = OpenIdConnectResponseType.CodeIdToken;
				options.SignInScheme = IdentityConstants.ExternalScheme;
				options.CallbackPath = "/signin-azuread-oidc";
				options.RequireHttpsMetadata = false;
				options.SaveTokens = true;
				options.GetClaimsFromUserInfoEndpoint = true;
				options.Scope.Add("email");
				options.ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "sub");
				EfCoreSaasTenantIdentityProviderSettingRepository saasTenantIdentityProviderSettingsService =
					context.Services.GetRequiredService<EfCoreSaasTenantIdentityProviderSettingRepository>();
				options.Events.OnTokenResponseReceived = async receivedContext =>
				{
					await Task.FromResult("");
				};
				options.Events.OnRedirectToIdentityProvider = async redirectContext =>
				{
					var azureAdSettings =
						await saasTenantIdentityProviderSettingsService.GetIdentityProviderSettings(IdentityProviderType.ENTRA_ID);
					var deserializedSettings = azureAdSettings?.Setting != null
						? JsonConvert.DeserializeObject<AzureEntraIdSetting>(azureAdSettings?.Setting)
						: null;

					if (azureAdSettings != null && deserializedSettings.IsEnabled)
					{
						redirectContext.ProtocolMessage.ClientId = deserializedSettings.ClientId;
						redirectContext.ProtocolMessage.ClientSecret = deserializedSettings.ClientSecret;
						redirectContext.ProtocolMessage.IssuerAddress =
							redirectContext.ProtocolMessage.IssuerAddress.Replace(configuration["AzureAd:TenantId"],
								deserializedSettings.AzureTenantId);

						redirectContext.Options.ClientId = deserializedSettings.ClientId;
						redirectContext.Options.ClientSecret = deserializedSettings.ClientSecret;
						redirectContext.Options.Authority = redirectContext.Options.Authority.Replace(configuration["AzureAd:TenantId"],
							deserializedSettings.AzureTenantId);
						redirectContext.Options.MetadataAddress = redirectContext.Options.MetadataAddress.Replace(
							configuration["AzureAd:TenantId"],
							deserializedSettings.AzureTenantId);
					}
				};
			});

Should I implement some other Event listener for token validation? I tried to implement OnTokenResponseReceived but exception occures before it goes there.

  1. I only get login to work when I set this setting to None. It doesn't feel right thing to do. But is there any other way? options.MinimumSameSitePolicy = Microsoft.AspNetCore.Http.SameSiteMode.None;

  2. Is there possibility to get login working without enabling self-registration when using Azure Entra Id?

After talking with my team enabling registration is not good for us. So is there possibility to get it working like making "registration" automatically if user is logged in through Azure Entra Id?

After I found correct place to enable self registration I managed to get login working with static appsettings.json settings . So now we need to get dynamic config working.

After login url looks like this. I removed some characters from those long values like state. If this helps anything. https://localhost:44369/Account/Register?isExternalLogin=True&externalLoginAuthSchema=AzureOpenId&returnUrl=%2Fconnect%2Fauthorize%3Fresponse_type%3Dcode%26client_id%3DSCM_App%26state%3DQmRYxUmlDVEhQ;%25252Fdashboard%26redirect_uri%3Dhttp%253A%252F%252Flocalhost%253A4200%252F%26scope%3Dopenid%2520offline_access%2520SCM%26code_challenge%3D4vcFgDJfIZgrYbPec%26code_challenge_method%3DS256%26nonce%3DQmRKTG9UYxUmlDVEhQ%26culture%3Dfi-FI%26ui-culture%3Dfi-FI%26returnUrl%3D%252Fdashboard

Forget to give you my ConfigureServices code. It is quite same as you suggested and what there was earlier.

context.Services.AddOptions()
.ConfigureOptions<AzureEntraIdTenantOptionsProvider>();
var authenticationBuilder = context.Services.AddAuthentication();
authenticationBuilder.AddOpenIdConnect("AzureOpenId", "Azure AD", options =>
{
    options.Authority = "https://login.microsoftonline.com/" + configuration["AzureAd:TenantId"] + "/v2.0/";
    options.ClientId = configuration["AzureAd:ClientId"];
    options.ResponseType = OpenIdConnectResponseType.CodeIdToken;
    options.CallbackPath = configuration["AzureAd:CallbackPath"];
    options.ClientSecret = configuration["AzureAd:ClientSecret"];
    options.RequireHttpsMetadata = false;
    options.SaveTokens = true;
    options.GetClaimsFromUserInfoEndpoint = true;
    options.Scope.Add("email");
    
    options.ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "sub");
});

And here is out provider. We assumed that currentTenant is set here so our global ef filter should work here and tenantId parameter is added to query automaticly.

public class AzureEntraIdTenantOptionsProvider : IConfigureOptions<OpenIdConnectOptions>, ITransientDependency
	{
		private readonly IServiceProvider _serviceProvider;


		public AzureEntraIdTenantOptionsProvider(IServiceProvider serviceProvider)
		{
			_serviceProvider = serviceProvider;
		}

		public void Configure(OpenIdConnectOptions options)
		{
			ISaasTenantIdentityProviderSettingsRepository saasTenantIdentityProviderSettingsService = _serviceProvider.GetRequiredService<ISaasTenantIdentityProviderSettingsRepository>();
			var azureAdSettings = saasTenantIdentityProviderSettingsService.GetIdentityProviderSettings(IdentityProviderType.ENTRA_ID).Result;
			var deserializedSettings = azureAdSettings?.Setting != null
				? JsonConvert.DeserializeObject<AzureEntraIdSetting>(azureAdSettings?.Setting)
				: null;

			if (azureAdSettings != null && deserializedSettings.IsEnabled)
			{
				options.ClientId = deserializedSettings.ClientId;
				options.ClientSecret = deserializedSettings.ClientSecret;
				options.Authority = $"https://login.microsoftonline.com/{deserializedSettings.AzureTenantId}/v2.0";
				options.ResponseType = OpenIdConnectResponseType.CodeIdToken;
				options.SaveTokens = true;
				options.GetClaimsFromUserInfoEndpoint = true;
				options.CallbackPath = "/signin-azure";
				options.RequireHttpsMetadata = false;
				options.Scope.Add("email");
				options.ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "sub");
			}
			else
			{
				// Or configure default behavior
				throw new UserFriendlyException("Azure Ad is not configured for you");
			}
		}
	}

Hello, I'm collegue of LW and started to implement this feature. Now I have several problems for which I need your help. First problem is about AzureEntraIdTenantOptionsProvider. I managed to implement it and when debuging I noticed that it goes to constructor of provider but never goes to Configure method so authserver is not even trying to get dynamic OpenIdConnectOptions from provider and uses what was in appsettings.json.

Other problem is when trying to use Azure AD button. I managed to configure Entra Id login settings to our appsetting.json from where AddOpenIdConnect is getting default settings. And it redirects to microsoft site and after awile it goes back to register page as seen below. Is this normal routine when using external identity provider? How can I get Register button enable if it is required to get external login to work.

And last notice is that I only get login to work this much when I se this setting to None. It doesn't feel right thing to do. But is there any other way? options.MinimumSameSitePolicy = Microsoft.AspNetCore.Http.SameSiteMode.None;

Collegue found that these were needed although we were not doing over module joins. [ReplaceDbContext(typeof(IForecastingDbContext))] and

modelBuilder.ConfigureForecasting();

So after all it was same problem as others have. I didn't just remember that our background process manager has own db context.

  • ABP Framework version: v8.2.1
  • UI Type: Angular
  • Database System: EF Core (SQL Server)
  • Tiered (for MVC) or Auth Server Separated (for Angular): separate
  • Exception message and full stack trace: The entity type 'ExtraPropertyDictionary' requires a primary key to be defined. If you intended to use a keyless entity type, call 'HasNoKey' in 'OnModelCreating'. For more information on keyless entity types, see https://go.microsoft.com/fwlink/?linkid=2141943. System.InvalidOperationException: The entity type 'ExtraPropertyDictionary' requires a primary key to be defined. If you intended to use a keyless entity type, call 'HasNoKey' in 'OnModelCreating'. For more information on keyless entity types, see https://go.microsoft.com/fwlink/?linkid=2141943. at Microsoft.EntityFrameworkCore.Infrastructure.ModelValidator.ValidateNonNullPrimaryKeys(IModel model, IDiagnosticsLogger1 logger) at Microsoft.EntityFrameworkCore.Infrastructure.ModelValidator.Validate(IModel model, IDiagnosticsLogger1 logger) at Microsoft.EntityFrameworkCore.Infrastructure.RelationalModelValidator.Validate(IModel model, IDiagnosticsLogger1 logger) at Microsoft.EntityFrameworkCore.SqlServer.Infrastructure.Internal.SqlServerModelValidator.Validate(IModel model, IDiagnosticsLogger1 logger) at Microsoft.EntityFrameworkCore.Infrastructure.ModelRuntimeInitializer.Initialize(IModel model, Boolean designTime, IDiagnosticsLogger1 validationLogger) at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.GetModel(DbContext context, ModelCreationDependencies modelCreationDependencies, Boolean designTime) at Microsoft.EntityFrameworkCore.Internal.DbContextServices.CreateModel(Boolean designTime) at Microsoft.EntityFrameworkCore.Internal.DbContextServices.get_Model() at Microsoft.EntityFrameworkCore.Infrastructure.EntityFrameworkServicesBuilder.<>c.<TryAddCoreServices>b__8_4(IServiceProvider p) at ResolveService(ILEmitResolverBuilderRuntimeContext, ServiceProviderEngineScope) at ResolveService(ILEmitResolverBuilderRuntimeContext, ServiceProviderEngineScope) at ResolveService(ILEmitResolverBuilderRuntimeContext, ServiceProviderEngineScope) at ResolveService(ILEmitResolverBuilderRuntimeContext, ServiceProviderEngineScope) at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType) at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider) at Microsoft.EntityFrameworkCore.DbContext.get_ChangeTracker() at Volo.Abp.EntityFrameworkCore.AbpDbContext1.Initialize(AbpEfCoreDbContextInitializationContext initializationContext) at Volo.Abp.Uow.EntityFrameworkCore.UnitOfWorkDbContextProvider1.CreateDbContextAsync(IUnitOfWork unitOfWork, String connectionStringName, String connectionString) at Volo.Abp.Uow.EntityFrameworkCore.UnitOfWorkDbContextProvider1.GetDbContextAsync() at Volo.Abp.Domain.Repositories.EntityFrameworkCore.EfCoreRepository2.GetDbSetAsync() 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.Dyn2025-01-16 13:12:43.260 +02:00 [INF] Loaded ABP modules:
  • Steps to reproduce the issue: I managed to find that this exception is thrown from these lines at our background process manager:
_mLOutputStorageService.ConnectToOutputStorage();
string currentTenantName = _currentTenant.Name!;
IList<BaselineDemandForecast> baselineDemandForecasts = await _mLOutputStorageService.DownloadForecastDataAsync(currentTenantName);
//remove all old forecasts from same run and insert new ones
var newRunIdFromDownloadedData = baselineDemandForecasts[0]?.RunId;
var query = await _baselineDemandForecastRepository.GetQueryableAsync();
var oldForecasts = query.Where(x => x.RunId == newRunIdFromDownloadedData);
await _baselineDemandForecastRepository.DeleteFromQueryAsync(oldForecasts);
foreach (var item in baselineDemandForecasts)
{
item.TenantId = _currentTenant.Id;
}
await _sqlBulkOperationsBaselineDemandForecastRepository.BulkInsert(baselineDemandForecasts);

and spesific line is: var query = await _baselineDemandForecastRepository.GetQueryableAsync();

Weird thing is that I haven't touched this part of code. I have some changes is in some Repositories. Here is original code from there. public EfCoreCalculatedSeasonalityProfileRepository(IDbContextProvider<ForecastingDbContext> dbContextProvider) and we changed to use interface like this: public EfCoreCalculatedSeasonalityProfileRepository(IDbContextProvider<IForecastingDbContext> dbContextProvider) but changes were into different repositories than what I'm using where probelm seems to be.

I found that in some other your customers have same kind of issues that they were missing module dependeces but I didn't found samekind of deficiencies in our code.

Here is definiton of that entity: public class BaselineDemandForecast : Entity<Guid>, IMultiTenant And here is builder configuration:

public class BaselineDemandForecastModelCreatingExtensions : IModuleEntityTypeConfiguration<BaselineDemandForecast>
{
    public bool IsApplicationDbContext { get; set; }
    public bool IsSqlite { get; set; }
    
    public void Configure(EntityTypeBuilder<BaselineDemandForecast> builder)
    {
        builder.ToTable(ForecastingDbProperties.DbTablePrefix + "BaselineDemandForecasts", ForecastingDbProperties.DbSchema);
        builder.ConfigureByConvention();
        builder.ConfigureByConventionSCM(IsSqlite);
        //here is ton of field definitions.
    }
}

Now I made test what is running this part of code. I only mock MLOutputStorageService to give me spesific list of items. And no exception.

Any idea what could be creating this issue?

I will continue with solution I have with configurations. I will continue to listen this thread if you decide something.

Showing 31 to 40 of 92 entries
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