أنشطة "anurag.tyagi"

okay I upgraded to @volosoft/abp.ng.theme.lepton-x": "3.1.4" and the frontend works wonderfully!

Issue was that by doingabp update I got the wrong version for @volosoft/abp.ng.theme.lepton-x and then I created a new project with 8.1.4 and I saw that the @volosoft/abp.ng.theme.lepton-x version there was 3.1.4.

thanks for the help!

hi, thanks a lot for your response and support Unfortunately when I moved up the lepton-x version to ~3.1.0 I now get a new couple of errors:

Thanks

public class MyappHttpApiHostModule : AbpModule
{
    public override void PreConfigureServices(ServiceConfigurationContext context)
    {
        var hostingEnvironment = context.Services.GetHostingEnvironment();
        var configuration = context.Services.GetConfiguration();

        PreConfigure<OpenIddictBuilder>(builder =>
        {
            builder.AddValidation(options =>
            {
                options.AddAudiences("Myapp");
                options.UseLocalServer();
                options.UseAspNetCore();
            });
        });
        
        PreConfigure<AbpOpenIddictWildcardDomainOptions>(options =>
        {
            options.EnableWildcardDomainSupport = true;
            options.WildcardDomainsFormat.Add("https://{0}.mybackend.com/");
            options.WildcardDomainsFormat.Add("https://{0}.mybackend.com/signin-oidc");
            options.WildcardDomainsFormat.Add("https://{0}.mybackend.com/signout-callback-oidc");
            options.WildcardDomainsFormat.Add("https://{0}.mybackend.com/authentication/login-callback");
            options.WildcardDomainsFormat.Add("https://{0}.myfrontend.com/");
        });

#if DEBUG
        PreConfigure<OpenIddictServerBuilder>(options => { options.UseAspNetCore().DisableTransportSecurityRequirement(); });
#endif
        
        if (!hostingEnvironment.IsDevelopment())
        {
            PreConfigure<AbpOpenIddictAspNetCoreOptions>(options =>
            {
                options.AddDevelopmentEncryptionAndSigningCertificate = false;
            });

            PreConfigure<OpenIddictServerBuilder>(builder =>
            {
                builder.AddSigningCertificate(GetSigningCertificate(hostingEnvironment, configuration));
                builder.AddEncryptionCertificate(GetSigningCertificate(hostingEnvironment, configuration));
            });
        }
        
        PreConfigure<IdentityBuilder>(identityBuilder=>{identityBuilder.AddSignInManager<MyAbpSignInManager>();});
    }

    public override void ConfigureServices(ServiceConfigurationContext context)
    {
        var configuration = context.Services.GetConfiguration();
        var hostingEnvironment = context.Services.GetHostingEnvironment();

        if (!Convert.ToBoolean(configuration["App:DisablePII"]))
        {
            Microsoft.IdentityModel.Logging.IdentityModelEventSource.ShowPII = true;
        }

        Configure<AbpTenantResolveOptions>(options =>
        {
            options.AddDomainTenantResolver(configuration["App:Domain"]!);
        });
        
        if (!Convert.ToBoolean(configuration["AuthServer:RequireHttpsMetadata"]))
        {
            Configure<OpenIddictServerAspNetCoreOptions>(options =>
            {
                options.DisableTransportSecurityRequirement = true;
            });
        }
        
        Configure<AbpTenantResolveOptions>(options =>
        {
            options.AddDomainTenantResolver(configuration["App:TenantResolverDomain"]!);
        });
        
        
        context.Services.AddHangfire(config =>
        {
            config.UseStorage(new MySqlStorage(configuration.GetConnectionString("Default"), new MySqlStorageOptions
            {
            }));
        });

        ConfigureAuthentication(context);
        ConfigureUrls(configuration);
        ConfigureBundles();
        ConfigureConventionalControllers();
        ConfigureImpersonation(context, configuration);
        ConfigureSwagger(context, configuration);
        ConfigureVirtualFileSystem(context);
        ConfigureCors(context, configuration);
        ConfigureExternalProviders(context);
        ConfigureHealthChecks(context);
        ConfigureTheme();
        
        context.Services.AddSignalR(hubOptions =>
        {
            hubOptions.MaximumParallelInvocationsPerClient = 5;
        });
    }

    private void ConfigureTheme()
    {
        Configure<LeptonXThemeOptions>(options =>
        {
            options.DefaultStyle = LeptonXStyleNames.System;
        });
    }

    private void ConfigureAuthentication(ServiceConfigurationContext context)
    {
        context.Services.ForwardIdentityAuthenticationForBearer(OpenIddictValidationAspNetCoreDefaults.AuthenticationScheme);
    }

    private void ConfigureHealthChecks(ServiceConfigurationContext context)
    {
        context.Services.AddMyappHealthChecks();
    }

    private void ConfigureUrls(IConfiguration configuration)
    {
        Configure<AppUrlOptions>(options =>
        {
            options.Applications["MVC"].RootUrl = configuration["App:SelfUrl"];
            options.Applications["Angular"].RootUrl = configuration["App:AngularUrl"];
            options.Applications["Angular"].Urls[AccountUrlNames.PasswordReset] = "account/reset-password";
            options.Applications["Angular"].Urls[AccountUrlNames.EmailConfirmation] = "account/email-confirmation";
            options.RedirectAllowedUrls.AddRange(configuration["App:RedirectAllowedUrls"]?.Split(',') ?? Array.Empty<string>());
        });
    }

    private void ConfigureBundles()
    {
        Configure<AbpBundlingOptions>(options =>
        {
            options.StyleBundles.Configure(
                LeptonXThemeBundles.Styles.Global,
                bundle =>
                {
                    bundle.AddFiles("/global-styles.css");
                }
            );
        });
    }


    private void ConfigureVirtualFileSystem(ServiceConfigurationContext context)
    {
        var hostingEnvironment = context.Services.GetHostingEnvironment();

        if (hostingEnvironment.IsDevelopment())
        {
            Configure<AbpVirtualFileSystemOptions>(options =>
            {
                options.FileSets.ReplaceEmbeddedByPhysical<MyappDomainSharedModule>(Path.Combine(hostingEnvironment.ContentRootPath, $"..{Path.DirectorySeparatorChar}Pm.Myapp.Domain.Shared"));
                options.FileSets.ReplaceEmbeddedByPhysical<MyappDomainModule>(Path.Combine(hostingEnvironment.ContentRootPath, $"..{Path.DirectorySeparatorChar}Pm.Myapp.Domain"));
                options.FileSets.ReplaceEmbeddedByPhysical<MyappApplicationContractsModule>(Path.Combine(hostingEnvironment.ContentRootPath, $"..{Path.DirectorySeparatorChar}Pm.Myapp.Application.Contracts"));
                options.FileSets.ReplaceEmbeddedByPhysical<MyappApplicationModule>(Path.Combine(hostingEnvironment.ContentRootPath, $"..{Path.DirectorySeparatorChar}Pm.Myapp.Application"));
            });
        }
    }

    private void ConfigureConventionalControllers()
    {
        Configure<AbpAspNetCoreMvcOptions>(options =>
        {
            options.ConventionalControllers.Create(typeof(MyappApplicationModule).Assembly);
        });
    }

    private static void ConfigureSwagger(ServiceConfigurationContext context, IConfiguration configuration)
    {
        context.Services.AddAbpSwaggerGenWithOAuth(
            configuration["AuthServer:Authority"]!,
            new Dictionary<string, string>
            {
                    {"Myapp", "Myapp API"}
            },
            options =>
            {
                options.SwaggerDoc("v1", new OpenApiInfo { Title = "Myapp API", Version = "v1" });
                options.DocInclusionPredicate((docName, description) => true);
                options.CustomSchemaIds(type => type.FullName);
            });
    }

    private void ConfigureCors(ServiceConfigurationContext context, IConfiguration configuration)
    {
        context.Services.AddCors(options =>
        {
            options.AddDefaultPolicy(builder =>
            {
                builder
                    .WithOrigins(
                        configuration["App:CorsOrigins"]?
                            .Split(",", StringSplitOptions.RemoveEmptyEntries)
                            .Select(o => o.Trim().RemovePostFix("/"))
                            .ToArray() ?? Array.Empty<string>()
                    )
                    .WithAbpExposedHeaders()
                    .SetIsOriginAllowedToAllowWildcardSubdomains()
                    .AllowAnyHeader()
                    .AllowAnyMethod()
                    .AllowCredentials();
            });
        });
    }

    private void ConfigureExternalProviders(ServiceConfigurationContext context)
    {
        var configuration = context.Services.GetConfiguration();
        context.Services.AddAuthentication()
            .AddJwtBearer(options =>
            {
                options.Authority = configuration["AuthServer:Authority"];
                options.RequireHttpsMetadata = Convert.ToBoolean(configuration["AuthServer:RequireHttpsMetadata"]);
                options.Audience = "Myapp";
        
                options.TokenValidationParameters.IssuerValidator = TokenWildcardIssuerValidator.IssuerValidator;
                options.TokenValidationParameters.ValidIssuers = new[]
                {
                    configuration["App:CommonUrl"]
                };
            })
            .AddGoogle(GoogleDefaults.AuthenticationScheme, _ => { })
            .WithDynamicOptions<GoogleOptions, GoogleHandler>(
                GoogleDefaults.AuthenticationScheme,
                options =>
                {
                    options.WithProperty(x => x.ClientId);
                    options.WithProperty(x => x.ClientSecret, isSecret: true);
                }
            )
            .AddMicrosoftAccount(MicrosoftAccountDefaults.AuthenticationScheme, options =>
            {
                    //Personal Microsoft accounts as an example.
                    options.AuthorizationEndpoint = "https://login.microsoftonline.com/consumers/oauth2/v2.0/authorize";
                options.TokenEndpoint = "https://login.microsoftonline.com/consumers/oauth2/v2.0/token";
            })
            .WithDynamicOptions<MicrosoftAccountOptions, MicrosoftAccountHandler>(
                MicrosoftAccountDefaults.AuthenticationScheme,
                options =>
                {
                    options.WithProperty(x => x.ClientId);
                    options.WithProperty(x => x.ClientSecret, isSecret: true);
                }
            )
            .AddTwitter(TwitterDefaults.AuthenticationScheme, options => options.RetrieveUserDetails = true)
            .WithDynamicOptions<TwitterOptions, TwitterHandler>(
                TwitterDefaults.AuthenticationScheme,
                options =>
                {
                    options.WithProperty(x => x.ConsumerKey);
                    options.WithProperty(x => x.ConsumerSecret, isSecret: true);
                }
            );
    }

    private void ConfigureImpersonation(ServiceConfigurationContext context, IConfiguration configuration)
    {
        context.Services.Configure<AbpAccountOptions>(options =>
        {
            options.TenantAdminUserName = "admin";
            options.ImpersonationTenantPermission = SaasHostPermissions.Tenants.Impersonation;
            options.ImpersonationUserPermission = IdentityPermissions.Users.Impersonation;
        });
    }

    public override void OnApplicationInitialization(ApplicationInitializationContext context)
    {
        var app = context.GetApplicationBuilder();
        var env = context.GetEnvironment();

        var forwardOptions = new ForwardedHeadersOptions {
            ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto | ForwardedHeaders.XForwardedHost, RequireHeaderSymmetry = false
        };

        forwardOptions.KnownNetworks.Clear();
        forwardOptions.KnownProxies.Clear();

    // ref: https://github.com/aspnet/Docs/issues/2384
        app.UseForwardedHeaders(forwardOptions);

        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseAbpRequestLocalization();

        if (!env.IsDevelopment())
        {
            app.UseErrorPage();
        }

        app.UseAbpSecurityHeaders();
        app.UseStaticFiles();
        app.UseRouting();
        app.UseCors();
        app.UseAuthentication();
        app.UseAbpOpenIddictValidation();

        if (MultiTenancyConsts.IsEnabled)
        {
            app.UseMultiTenancy();
        }

        app.UseUnitOfWork();

        app.UseAuthorization();



        if (!env.IsDevelopment())
        {
            app.Use(async (httpContext, next) =>
            {
                if (httpContext.Request.Path.StartsWithSegments("/swagger") && !httpContext.User.IsInRole("admin"))
                {
                    httpContext.Response.StatusCode = StatusCodes.Status403Forbidden;
                    return;
                }

                await next.Invoke();
            });
        }


        app.UseSwagger();
        app.UseAbpSwaggerUI(options =>
        {
            options.SwaggerEndpoint("/swagger/v1/swagger.json", "Myapp API");

            var configuration = context.ServiceProvider.GetRequiredService<IConfiguration>();
            options.OAuthClientId(configuration["AuthServer:SwaggerClientId"]);
        });
        
        RecurringJob.AddOrUpdate<ResetMonthlyQuestionsCountJob>("reset-monthly-questions",
            job => job.ExecuteAsync(new ResetMonthlyQuestionsCountArgs()), Cron.Monthly);
        
        
        app.UseAuditing();
        app.UseAbpSerilogEnrichers();
        app.UseConfiguredEndpoints();
    }

    private X509Certificate2 GetSigningCertificate(IWebHostEnvironment hostingEnv, IConfiguration configuration)
    {
        var fileName = "authserver.pfx";
        var passPhrase = "f123a4f5-678a-4b4d-a2c4-3f62b6033d4d";
        var file = Path.Combine(hostingEnv.ContentRootPath, fileName);

        if (!File.Exists(file))
        {
            throw new FileNotFoundException($"Signing Certificate couldn't found: {file}");
        }

        return new X509Certificate2(file, passPhrase);
    }
}

Hi,

Can you please tell me which file specifically you need?

Hi, please see the logs below:

20:03:07 [18:03:07 INF] Request finished HTTP/1.1 GET https://mybackend.com/api/saas/tenants/3a114414-b352-6751-1023-c40755a4a1bb/image - 500 null application/json; charset=utf-8 194.2802ms 20/06/2024
20:03:07 [18:03:07 INF] Request starting HTTP/1.1 GET http://mybackend.com/connect/authorize?response_type=code&client_id=Myapp_App&state=MFFzdn5-NENLRkFKTlZOLlZuRDhNVFdiUC4zVmRlMC1UX3RxV00zWkVvSk05%3B%252Ffree-inquiry&redirect_uri=https%3A%2F%2Fmyfrontend.com&scope=openid%20offline_access%20Myapp&code_challenge=0bxO4MWionxUKMExy-9tJkcC-sN8WJhDjQts2c6LHbo&code_challenge_method=S256&nonce=MFFzdn5-NENLRkFKTlZOLlZuRDhNVFdiUC4zVmRlMC1UX3RxV00zWkVvSk05&culture=en&ui-culture=en&returnUrl=%2Ffree-inquiry - null null 20/06/2024
20:03:07 [18:03:07 INF] The request URI matched a server endpoint: Authorization. 20/06/2024
20:03:07 [18:03:07 INF] The authorization request was successfully extracted: { 20/06/2024
20:03:07   "response_type": "code", 20/06/2024
20:03:07   "client_id": "Myapp_App", 20/06/2024
20:03:07   "state": "MFFzdn5-NENLRkFKTlZOLlZuRDhNVFdiUC4zVmRlMC1UX3RxV00zWkVvSk05;%2Ffree-inquiry", 20/06/2024
20:03:07   "redirect_uri": "https://myfrontend.com", 20/06/2024
20:03:07   "scope": "openid offline_access Myapp", 20/06/2024
20:03:07   "code_challenge": "0bxO4MWionxUKMExy-9tJkcC-sN8WJhDjQts2c6LHbo", 20/06/2024
20:03:07   "code_challenge_method": "S256", 20/06/2024
20:03:07   "nonce": "MFFzdn5-NENLRkFKTlZOLlZuRDhNVFdiUC4zVmRlMC1UX3RxV00zWkVvSk05", 20/06/2024
20:03:07   "culture": "en", 20/06/2024
20:03:07   "ui-culture": "en", 20/06/2024
20:03:07   "returnUrl": "/free-inquiry" 20/06/2024
20:03:07 }. 20/06/2024
20:03:08 [18:03:08 INF] Client validation failed because 'https://myfrontend.com' was not a valid redirect_uri for Myapp_App. 20/06/2024
20:03:08 [18:03:08 INF] The authorization request was rejected because the redirect_uri was invalid: 'https://myfrontend.com'. 20/06/2024
20:03:08 [18:03:08 INF] Request finished HTTP/1.1 GET https://mybackend.com/connect/authorize?response_type=code&client_id=Myapp_App&state=MFFzdn5-NENLRkFKTlZOLlZuRDhNVFdiUC4zVmRlMC1UX3RxV00zWkVvSk05%3B%252Ffree-inquiry&redirect_uri=https%3A%2F%2Fmyfrontend.com&scope=openid%20offline_access%20Myapp&code_challenge=0bxO4MWionxUKMExy-9tJkcC-sN8WJhDjQts2c6LHbo&code_challenge_method=S256&nonce=MFFzdn5-NENLRkFKTlZOLlZuRDhNVFdiUC4zVmRlMC1UX3RxV00zWkVvSk05&culture=en&ui-culture=en&returnUrl=%2Ffree-inquiry - 302 0 null 269.0968ms 20/06/2024

FYI, I have substituted the real domains with:

mybackend.com representing our backend domain myfrontend.com in place of the actual frontend domain

  • ABP Framework version: v8.1
  • UI Type: Angular
  • Database System: EF Core MySQL
  • Tiered (for MVC) or Auth Server Separated (for Angular): no
  • Exception message and full stack trace: NullInjectorError: NullInjectorError: No provider for InjectionToken CORE_OPTIONS!

Hi devs, I just updated our ABP commercial version from 8.0.4 to 8.1 and everything works fine except i get the following error in the frontend:

I also found this issue in other forum posts and tried the solutions there: https://support.abp.io/QA/Questions/5874/Upgrade-732-to-740-rc4-error I removed the cache and the node modules and reinstalled but the issue still remains.

here is my package.json, maybe there is a version mismatch somewhere: { "name": "GovernmentGpt", "version": "0.0.0", "scripts": { "ng": "ng", "start": "ng serve --open --host 0.0.0.0 --disable-host-check", "build": "ng build", "build:prod": "ng build --configuration production", "watch": "ng build --watch --configuration development", "test": "ng test", "lint": "ng lint" }, "private": true, "dependencies": { "@abp/ng.components": "~8.1.4", "@abp/ng.core": "~8.1.4", "@abp/ng.oauth": "~8.1.4", "@abp/ng.setting-management": "~8.1.4", "@abp/ng.theme.shared": "~8.1.4", "@angular/animations": "~17.0.0", "@angular/common": "~17.0.0", "@angular/compiler": "~17.0.0", "@angular/core": "~17.0.0", "@angular/forms": "~17.0.0", "@angular/localize": "~17.0.0", "@angular/platform-browser": "~17.0.0", "@angular/platform-browser-dynamic": "~17.0.0", "@angular/router": "~17.0.0", "@microsoft/signalr": "^8.0.0", "@volo/abp.commercial.ng.ui": "~8.1.4", "@volo/abp.ng.account": "~8.1.4", "@volo/abp.ng.audit-logging": "~8.1.4", "@volo/abp.ng.gdpr": "~8.1.4", "@volo/abp.ng.identity": "~8.1.4", "@volo/abp.ng.language-management": "~8.1.4", "@volo/abp.ng.openiddictpro": "~8.1.4", "@volo/abp.ng.saas": "~8.1.4", "@volo/abp.ng.text-template-management": "~8.1.4", "@volosoft/abp.ng.theme.lepton-x": "~3.0.2", "marked": "9.0.0", "ngx-markdown": "^17.1.1", "pdfmake": "^0.2.10", "primeicons": "^6.0.1", "primeng": "^17.4.0", "rxjs": "~7.8.1", "tslib": "^2.0.0", "zone.js": "~0.14.0" }, "devDependencies": { "@abp/ng.schematics": "~8.1.4", "@angular-devkit/build-angular": "~17.0.0", "@angular-eslint/builder": "~17.0.0", "@angular-eslint/eslint-plugin": "~17.0.0", "@angular-eslint/eslint-plugin-template": "~17.0.0", "@angular-eslint/schematics": "~17.0.0", "@angular-eslint/template-parser": "~17.0.0", "@angular/cli": "~17.0.0", "@angular/compiler-cli": "~17.0.0", "@angular/language-service": "~17.0.0", "@types/jasmine": "~3.6.0", "@types/node": "^12.0.0", "@typescript-eslint/eslint-plugin": "6.9.1", "@typescript-eslint/parser": "6.9.1", "eslint": "^8.0.0", "jasmine-core": "~4.0.0", "karma": "~6.3.0", "karma-chrome-launcher": "~3.1.0", "karma-coverage": "~2.1.0", "karma-jasmine": "~4.0.0", "karma-jasmine-html-reporter": "^1.0.0", "ng-packagr": "~17.0.0", "typescript": "~5.2.0" } } and here is my app.module.ts

`import { CoreModule } from '@abp/ng.core';
import { GdprConfigModule } from '@volo/abp.ng.gdpr/config';
import { SettingManagementConfigModule } from '@abp/ng.setting-management/config';
import { ThemeSharedModule } from '@abp/ng.theme.shared';
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { CommercialUiConfigModule } from '@volo/abp.commercial.ng.ui/config';
import { AccountAdminConfigModule } from '@volo/abp.ng.account/admin/config';
import { AccountPublicConfigModule } from '@volo/abp.ng.account/public/config';
import { AuditLoggingConfigModule } from '@volo/abp.ng.audit-logging/config';
import { IdentityConfigModule } from '@volo/abp.ng.identity/config';
import { LanguageManagementConfigModule } from '@volo/abp.ng.language-management/config';
import { registerLocale } from '@volo/abp.ng.language-management/locale';
import { SaasConfigModule } from '@volo/abp.ng.saas/config';
import { TextTemplateManagementConfigModule } from '@volo/abp.ng.text-template-management/config';
import { HttpErrorComponent, ThemeLeptonXModule } from '@volosoft/abp.ng.theme.lepton-x';
import { SideMenuLayoutModule } from '@volosoft/abp.ng.theme.lepton-x/layouts';
import { environment } from '../environments/environment';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { APP_ROUTE_PROVIDER } from './route.provider';
import { OpeniddictproConfigModule } from '@volo/abp.ng.openiddictpro/config';
import { FeatureManagementModule } from '@abp/ng.feature-management';
import { AbpOAuthModule } from '@abp/ng.oauth';
import { AccountLayoutModule } from '@volosoft/abp.ng.theme.lepton-x/account';
import { ButtonModule } from 'primeng/button';
import { LpxBrandLogoModule, LpxIconModule, LpxNavbarModule } from '@volo/ngx-lepton-x.core';
import { PM_THEME_PROVIDER } from './theme/theme.provider';
import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { AcceptLanguageInterceptor } from './language-interceptor/accept-language.interceptor';
import { CustomTenantModule } from './tenant/custom-tenant.module';

@NgModule({
  declarations: [AppComponent],
  imports: [
    BrowserModule,
    ButtonModule,
    BrowserAnimationsModule,
    AppRoutingModule,
    CoreModule.forRoot({
      environment,
      registerLocaleFn: registerLocale()
    }),
    AbpOAuthModule.forRoot(),
    ThemeSharedModule.forRoot({
      httpErrorConfig: {
        errorScreen: {
          component: HttpErrorComponent,
          forWhichErrors: [401, 403, 404, 500],
          hideCloseIcon: true
        }
      }
    }),
    AccountAdminConfigModule.forRoot(),
    AccountPublicConfigModule.forRoot(),
    IdentityConfigModule.forRoot(),
    LanguageManagementConfigModule.forRoot(),
    SaasConfigModule.forRoot(),
    AuditLoggingConfigModule.forRoot(),
    OpeniddictproConfigModule.forRoot(),
    TextTemplateManagementConfigModule.forRoot(),
    SettingManagementConfigModule.forRoot(),
    CommercialUiConfigModule.forRoot(),
    FeatureManagementModule.forRoot(),
    GdprConfigModule.forRoot({
      privacyPolicyUrl: 'gdpr-cookie-consent/privacy',
      cookiePolicyUrl: 'gdpr-cookie-consent/cookie'
    }),
    ThemeLeptonXModule.forRoot({}),
    SideMenuLayoutModule.forRoot(),
    AccountLayoutModule.forRoot(),
    LpxNavbarModule,
    LpxIconModule,
    LpxBrandLogoModule,
    CustomTenantModule
  ],
  providers: [
    APP_ROUTE_PROVIDER,
    PM_THEME_PROVIDER,
    {
      provide: HTTP_INTERCEPTORS,
      useExisting: AcceptLanguageInterceptor,
      multi: true,
    },
  ],
  bootstrap: [AppComponent],
  exports: [
  ]
})
export class AppModule {}

any hints would be greatly appreciated!

best wishes

Hi,

Thanks for your reply.

I have already implemented the provided configuration in our project at the time of creating this ticket. However, this solution does not resolve the issue.

Could you please provide further assistance or an alternative approach to dynamically handle tenant-specific redirect URIs?

Thanks in advance

  • ABP Framework version: v8.0.2
  • UI Type: Angular
  • Database System: EF Core (MySQL)
  • Tiered (for MVC) or Auth Server Separated (for Angular): no
  • Exception message and full stack trace: Redirect URI not matched to the allowed list
  • Steps to reproduce the issue:Enable multitenancy in abp using official documentation (https://docs.abp.io/en/abp/latest/Multi-Tenancy#domain-subdomain-tenant-resolver, https://github.com/abpframework/abp-samples/tree/master/DomainTenantResolver), create new tenant, try to login to the tenant using tenant URL.

I need assistance with an issue we're encountering with our ABP Commercial application configured for multitenancy (https://docs.abp.io/en/abp/1.0/Multi-Tenancy#domain-tenant-resolver). We have enabled multitenancy and are using OpenIddict for authentication. The configuration details for OpenIddict are stored in a database table named OpenIddictApplications, including the RedirectUris and PostLogoutRedirectUris columns.

Our application uses subdomain-based URLs for each tenant (e.g., tenant.mydomain.com). When creating a new tenant, the new tenant URL must be added to the list of allowed URIs in the RedirectUris and PostLogoutRedirectUris columns. However, this is not happening automatically, and we are facing a significant issue.

Redirect URI Mismatch Error: If the new tenant URL is not added to these lists, we receive an error indicating a mismatch of redirect URIs, preventing login and logout operations. No Support for Wildcards: The redirection endpoint URI must be an absolute URI as defined by [RFC3986] Section 4.3 (https://www.rfc-editor.org/rfc/rfc3986#section-4.3), and therefore we cannot use wildcard values like https://*.mydomain.com or https://{0}.mydomain.com. Given these constraints, we cannot dynamically handle new tenant URLs without manual updates to the allowed URIs lists.

Could you please guide how to resolve this issue? Specifically, we are looking for a solution that allows us to manage tenant-specific redirect URIs more dynamically without requiring manual updates to the database for each new tenant.

Any suggestions or best practices to handle this situation effectively would be greatly appreciated.

Hi,

Is it OK to disable the issuer validation on production?

also, without SetIssuer the login works just fine on all other tenants (tenant1.mydomain.com, tenant2.mydomain.com) but not for mydomain.com, it should work the same way for all URLs, right?

Can I somehow remove SetIssuer and find a solution to the problem described above? or the only way is to bring it back and disable issuer validation?

Many thanks for considering my request.

Hi,

Thanks for your response.

There are no backend logs on this issue, on the frontend console I see:

invalid issuer in discovery document expected: https://tenant.api.mydomain.com current: https://api.mydomain.com/

and when I check the https://api.mydomain.com/.well-known/openid-configuration endpoint, I see the following configuration:

{
  "issuer": "https://api.mydomain.com",
  "authorization_endpoint": "https://tenant.api.mydomain.com/connect/authorize",
  "token_endpoint": "https://tenant.api.mydomain.com/connect/token",
  "introspection_endpoint": "https://tenant.api.mydomain.com/connect/introspect",
  "end_session_endpoint": "https://tenant.api.mydomain.com/connect/logout"
}

FYI, this issue is not reproducible locally as soon as SetIssuer is in the if (!hostingEnvironment.IsDevelopment()) block.

عرض 1 الي 10 من 22 إدخالات
Made with ❤️ on ABP v8.2.0-preview Updated on مارس 25, 2024, 15:11