Activities of "fordz"

Found this line of code in our AuthServer service. It was added to try to fix the issue with the the 'discovery document' not returning as https. see #9849 https://abp.io/support/questions/9849/Error-retrieving-discovery-document-Endpoint-does-not-use-HTTPS-httpauthservermydomaindevconnectauthorize

// Force HTTPS scheme for AKS/ingress scenarios - must be early in pipeline
if (!env.IsDevelopment())
{
    app.Use((httpContext, next) =>
    {
        httpContext.Request.Scheme = "https";
        // Set the host to the authority from configuration, removing the scheme if present
            httpContext.Request.Host = new      HostString(configuration["AuthServer:Authority"]!.Replace("https://", "").Replace("http://", ""));
        return next();
    });
}

Added this line of code to NOT overwrite the url when the HttpContext.Request is not coming from the 'authserver.domain.dev'.

// Force HTTPS scheme for AKS/ingress scenarios - must be early in pipeline
if (!env.IsDevelopment())
{
    app.Use((httpContext, next) =>
    {
        httpContext.Request.Scheme = "https";
        if (httpContext.Request.Host.HasValue && httpContext.Request.Host.Value.Contains("authserver"))
        {
            // Set the host to the authority from configuration, removing the scheme if present
            httpContext.Request.Host = new HostString(configuration["AuthServer:Authority"]!.Replace("https://", "").Replace("http://", ""));
        }
        return next();
    });
}

This seems to have fixed the case where we are doing the EmailConfirmation and PasswordReset links that have the 'tenant' as part of the uri. I need to test now to see if I can still get a token via our token service as in #9849.

I get this error when I change the AuthServer__Authority to 'https://auth.{0}.cloverleafcms.dev'

[16:27:50 INF] Starting CloverleafCMS.AuthServer 2025-09-25T16:27:51.304356585Z CloverleafCMS.AuthServer terminated unexpectedly! 2025-09-25T16:27:51.312983837Z Volo.Abp.AbpInitializationException: An error occurred during ConfigureServicesAsync phase of the module Volo.Abp.OpenIddict.AbpOpenIddictAspNetCoreModule, Volo.Abp.OpenIddict.AspNetCore, Version=9.2.0.0, Culture=neutral, PublicKeyToken=null. See the inner exception for details. 2025-09-25T16:27:51.313015436Z ---> System.UriFormatException: Invalid URI: The hostname could not be parsed. 2025-09-25T16:27:51.313019508Z at System.Uri.CreateThis(String uri, Boolean dontEscape, UriKind uriKind, UriCreationOptions& creationOptions) 2025-09-25T16:27:51.313023141Z at System.Uri..ctor(String uriString) 2025-09-25T16:27:51.313026845Z at CloverleafCMS.AuthServer.CloverleafCMSAuthServerModule.<>c__DisplayClass3_0.<PreConfigureOpenIddict>b__1(OpenIddictServerBuilder serverBuilder) in D:\CodeRepositories\CloverleafCMS-Microservices-Abp\apps\auth-server\CloverleafCMS.AuthServer\CloverleafCMSAuthServerModule.cs:line 253 2025-09-25T16:27:51.313031158Z at Volo.Abp.Options.PreConfigureActionList1.Configure(TOptions options) 2025-09-25T16:27:51.313034387Z at Microsoft.Extensions.DependencyInjection.ServiceCollectionPreConfigureExtensions.ExecutePreConfiguredActions[TOptions](IServiceCollection services, TOptions options) 2025-09-25T16:27:51.313037294Z at Volo.Abp.OpenIddict.AbpOpenIddictAspNetCoreModule.<>c__DisplayClass1_0.<AddOpenIddictServer>b__0(OpenIddictServerBuilder builder) 2025-09-25T16:27:51.313040180Z at Microsoft.Extensions.DependencyInjection.OpenIddictServerExtensions.AddServer(OpenIddictBuilder builder, Action1 configuration) 2025-09-25T16:27:51.313043087Z at Volo.Abp.OpenIddict.AbpOpenIddictAspNetCoreModule.AddOpenIddictServer(IServiceCollection services) 2025-09-25T16:27:51.313045733Z at Volo.Abp.OpenIddict.AbpOpenIddictAspNetCoreModule.ConfigureServices(ServiceConfigurationContext context) 2025-09 -25T16:27:51.313048583Z at Volo.Abp.Modularity.AbpModule.ConfigureServicesAsync(ServiceConfigurationContext context) 2025-09-25T16:27:51.313051602Z at Volo.Abp.AbpApplicationBase.ConfigureServicesAsync() 2025-09-25T16:27:51.313054693Z --- End of inner exception stack trace --- 2025-09-25T16:27:51.313057457Z at Volo.Abp.AbpApplicationBase.ConfigureServicesAsync() 2025-09-25T16:27:51.313059913Z at Volo.Abp.AbpApplicationFactory.CreateAsync[TStartupModule](IServiceCollection services, Action1 optionsAction) 2025-09-25T16:27:51.313062722Z at Microsoft.Extensions.DependencyInjection.ServiceCollectionApplicationExtensions.AddApplicationAsync[TStartupModule](IServiceCollection services, Action1 optionsAction) 2025-09-25T16:27:51.313065556Z at Microsoft.Extensions.DependencyInjection.WebApplicationBuilderExtensions.AddApplicationAsync[TStartupModule](WebApplicationBuilder builder, Action1 optionsAction) at CloverleafCMS.AuthServer.Program.Main(String[] args) in D:\CodeRepositories\CloverleafCMS-Microservices-Abp\apps\auth-server\CloverleafCMS.AuthServer\Program.cs:line 58 2025-09-25T16:27:51.313136379Z at Volo.Abp.AbpApplicationBase.ConfigureServicesAsync() 2025-09-25T16:27:51.313141099Z at Volo.Abp.AbpApplicationFactory.CreateAsync[TStartupModule](IServiceCollection services, Action1 optionsAction) 2025-09-25T16:27:51.313145918Z at Microsoft.Extensions.DependencyInjection.ServiceCollectionApplicationExtensions.AddApplicationAsync[TStartupModule](IServiceCollection services, Action1 optionsAction) 2025-09-25T16:27:51.313148621Z at Microsoft.Extensions.DependencyInjection.WebApplicationBuilderExtensions.AddApplicationAsync[TStartupModule](WebApplicationBuilder builder, Action1 optionsAction) 2025-09-25T16:27:51.313151609Z at CloverleafCMS.AuthServer.Program.Main(String[] args) in D:\CodeRepositories\CloverleafCMS-Microservices-Abp\apps\auth-server\CloverleafCMS.AuthServer\Program.cs:line 58

I realize the {0} in the uri make it not a FQDN and that is the error - not parsing. So how do I get the correct tenant from the Email Confirmation link?

Here is the generated email confirmation link. It does look like suggested in Step 6 above. https://auth.cooptrustcu.cloverleafcms.dev/Account/EmailConfirmation?userId=7c35ab2c-1f30-b33f-1b3a-3a1c93671327&__tenant=7a5bc172-edda-3f19-78f6-3a1c7aa58661&confirmationToken=CfDJ8JgaA0MlWwBBhj6j207cixmu5y42jSy4ry8ycfDDBf%2BCXXc5yitosQCqt4qxGl1LuArwH0ucsbBbkxMfm1HwybHVP5NvjKRFg2Fl%2BbKwOd8HD7iMGufmXfRvDTvYLEzzRximE00AEz5WL5qCWsrru2b0e92EYxkW0IqkMItTuQSV7tTJpV136o3SOkfeZmY10Su731vOVAUkEFdLohNw58W7mEmLtZxf4Q%2Bc29yAmOciNHIj7nNuAGKmxnT3Y5wfxQ%3D%3D&returnUrl=%2fconnect%2fauthorize%3fclient_id%3dCloverleafCMS%26redirect_uri%3dhttps%253A%252F%252Fcooptrustcu.cloverleafcms.dev%252Fsignin-oidc%26response_type%3dcode%26scope%3daddress%2520email%2520phone%2520profile%2520roles%2520ActionItemService%2520AdministrationService%2520AIService%2520AuditLoggingService%2520AuthServer%2520ClientService%2520ClientServicesQuery%2520CommunicationsTemplateService%2520ContactService%2520DocTemplateService%2520DocumentService%2520EngagementLogService%2520FinancialService%2520GdprService%2520GuardianshipService%2520HousingService%2520HudService%2520IdentityService%2520LanguageService%2520MemberConfigService%2520NoteService%2520SaasService%2520ServicesService%2520SMSService%2520StaffService%2520TokenService%2520WorkshopService%26state%3d057a9c327a884cb4b4986b97b30e279f%26code_challenge%3dq_0a68W7EJ3fcOqZi_qDBr8TdB2rqQVwsdd80-HL1ok%26code_challenge_method%3dS256%26response_mode%3dquery

When I click on the link I get the 404 error because the httpContext host is 'authserver.cloverleafcms.dev' and not from the url which has the correct tenant.

Template: microservice

Created ABP Studio Version: 1.0.2

Current ABP Studio Version: 1.2.2

Multi-Tenancy: Yes

UI Framework: mvc

Theme: leptonx

Theme Style: system

Theme Menu Placement: side

Run Install Libs: Yes

Database Provider: ef

Database Management System: sqlserver

Mobile Framework: none

Public Website: No

Social Login: Yes

Include Tests: Yes

Dynamic Localization: Yes

Kubernetes Configuration: Yes

Grafana Dashboard: Yes

Use Local References: No

Optional Modules:

GDPR

TextTemplateManagement

AuditLogging

OpenIddictAdmin

Selected Languages: English, English (United Kingdom), Español

Default Language: English

Create Command: abp new CloverleafCMS -t microservice --ui-framework mvc --database-provider ef --database-management-system sqlserver --theme leptonx --skip-migrator --without-cms-kit --dont-run-bundling -no-file-management -no-language-management

We're using the microservice template and using the auth-server app for authentication. The auth-server application has been slightly modified for custom branding. We are running the authserver and microservices in Azure Kubernetes.

Exception message and full stack trace: The scenerio is we have a multi-tenant app and we are testing the confirm email and reset password processes and are getting the error below when we change to a new tenant. We are deriving the tenant from the url in the form of 'auth.tenantname.cloverleafcms.dev'. Our tenant resolver interrogates the httpContext host and resolves the tenant and sets the context.TenantIdOrName property. We are getting a 404 Page not found (no entity for IdentityUser) error after we register a new user then confirm email'.

After making the suggestions to correct the tenant aware email url that is produced by the email generator, I'm still getting the 404 user not found for identity guid error. Here was the AI bot generated response for ticket #9843. ***The issue you are experiencing is due to the email confirmation and reset password links being generated with the wrong base URL (e.g., https://authserver.cloverleafcms.dev instead of the required tenant-specific subdomain like https://auth.homefree.cloverleafcms.dev). This causes the tenant resolver to fail, resulting in a 404 error because the user cannot be found in the wrong tenant context.

To resolve this, you need to ensure that the URLs generated for email confirmation and password reset are tenant-aware and use the correct subdomain format that your HostTenantResolveContributor expects.***

Image of the Kubernetes Authserver pod environment variables for SelfUrl and Authority. Image of the user in the Identity database to show that it exists under the tenant. Image of the tenant 'cooptrustcu' in the SaasTenants table.

I need to find out where or how the 'host' from the httpContext request is still 'authserver.cloverleafcms.dev'. If I change the AuthServer__Authority to 'https://auth.{0}.cloverleafcms.dev' then the authserver throughs an error and will not start because it cannot parse the authority url. Bottom line is I need to get the Email Confirmation and Password Reset process to work before we can go live. Can we get credit for ticket #9843 or reopen it?

To add to the answer: Do the following to have the api-only (api with no database) permissions and permission grants added. *To ensure your microservice's permissions are persisted to the central Administration database:

Reference your microservice's Application.Contracts project from the AdministrationService. This allows the central service to discover and register your permission definitions.

Rebuild the solution and restart the AdministrationService. This ensures the new permissions are loaded and can be seeded.*

Okay... I got it to work (write the permissions) with my original code. I forgot to uncomment the database config getSection lines in the module class. These were commented out originally because we don't have a database for this microservice.

in the ClientServicesQueryModule.cs

private void ConfigureCustomConnectionStringResolver(ServiceConfigurationContext context)
{
    // Register the custom connection string resolver
    // This will override the default ABP connection string resolver
    context.Services.AddTransient<IConnectionStringResolver, CustomConnectionStringResolver>();

    // Configure database connection options for strongly-typed configuration
    var configuration = context.Services.GetConfiguration();

    // Configure individual database connection options sections if needed
    // This allows for future extensibility with strongly-typed configuration
    context.Services.Configure<DatabaseConnectionOptions>("AdministrationService", 
        configuration.GetSection("DatabaseConfig:AdministrationService"));
    // context.Services.Configure<DatabaseConnectionOptions>("IdentityService", 
    //     configuration.GetSection("DatabaseConfig:IdentityService"));
    context.Services.Configure<DatabaseConnectionOptions>("AuditLoggingService", 
        configuration.GetSection("DatabaseConfig:AuditLoggingService"));
    context.Services.Configure<DatabaseConnectionOptions>("SaasService", 
        configuration.GetSection("DatabaseConfig:SaasService"));
    context.Services.Configure<DatabaseConnectionOptions>("LanguageService", 
        configuration.GetSection("DatabaseConfig:LanguageService"));
    context.Services.Configure<DatabaseConnectionOptions>("AbpBlobStoring", 
        configuration.GetSection("DatabaseConfig:AbpBlobStoring"));
}

in the Data folder.

public class ClientServicesQueryDataSeeder : ITransientDependency
{
    private readonly ILogger _logger;
    private readonly IPermissionDataSeeder _permissionDataSeeder;
    
    public ClientServicesQueryDataSeeder(IPermissionDataSeeder permissionDataSeeder,
        ILogger<ClientServicesQueryDataSeeder> logger)
    {
        _permissionDataSeeder = permissionDataSeeder;
        _logger = logger;
    }
    
    [UnitOfWork]
    public virtual async Task SeedAsync(Guid? tenantId = null)
    {
        _logger.LogInformation("Starting ClientServicesQuery permission seeding...");
    
        try
        {
            var permissions = ClientServicesQueryPermissions.GetAll();
            _logger.LogInformation("Found {PermissionCount} permissions to seed: {Permissions}", 
                permissions.Length, 
                string.Join(", ", permissions));
    
            // Grant permissions to the "admin" role
            await _permissionDataSeeder.SeedAsync(
                RolePermissionValueProvider.ProviderName,
                "admin",
                permissions,
                tenantId
            );
    
            _logger.LogInformation("Successfully seeded ClientServicesQuery permissions for admin role");
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to seed ClientServicesQuery permissions");
            throw;
        }
    }
}

Thanks for the quick response.

This isn't clear... 'add the ClientServicesQueryContractsModule to the DependsOn of the IdentityService or ApplicationService or both'? This means that the Admin or Identity service has to reference the ClientServicesQueryContractsModule project. This tightly couples the to microservices!

Check the docs before asking a question: https://abp.io/docs/latest Check the samples to see the basic tasks: https://abp.io/docs/latest/samples The exact solution to your question may have been answered before, and please first use the search on the homepage.

Provide us with the following info: 🧐 Hint: If you are using the ABP Studio, you can see all the information about your solution from the configuration window, which opens when you right-click on the solution and click on the Solution Configuration button.

  • Exception message and full stack trace:
  • Steps to reproduce the issue:
  • Template: microservice
  • Created ABP Studio Version: 1.0.2
  • Current ABP Studio Version: 1.2.2
  • Multi-Tenancy: Yes
  • UI Framework: mvc
  • Theme: leptonx
  • Theme Style: system
  • Theme Menu Placement: side
  • Run Install Libs: Yes
  • Database Provider: ef
  • Database Management System: sqlserver
  • Mobile Framework: none
  • Public Website: No
  • Social Login: Yes
  • Include Tests: Yes
  • Dynamic Localization: Yes
  • Kubernetes Configuration: Yes
  • Grafana Dashboard: Yes
  • Use Local References: No
  • Optional Modules:
    • GDPR
    • TextTemplateManagement
    • AuditLogging
    • OpenIddictAdmin
  • Selected Languages: English, English (United Kingdom), Español
  • Default Language: English
  • Create Command: abp new CloverleafCMS -t microservice --ui-framework mvc --database-provider ef --database-management-system sqlserver --theme leptonx --skip-migrator --without-cms-kit --dont-run-bundling -no-file-management -no-language-management

I have a microservice project in this solution that is api only --- it has no database. I'm having trouble getting the permissions for this service saved to the administration permissions and permissionGrants tables.

under the /Data folder I have the ClientServicesQueryDataSeeder.cs If I don't have a database for the microservice, do I need to have the following:

  • ClientServicesQueryDbContext.cs
  • ClientServicesQueryDbContextFactory.cs
  • ClientServicesQueryDatabaseMigrationEventHandler.cs
  • ClientServicesQueryRuntimeDatabaseMigrator.cs

if so, how would I configure these without a database?

Here is the code that I've added that doesn't work:

public class ClientServicesQueryDataSeeder : ITransientDependency
{
    private readonly ILogger _logger;
    private readonly IPermissionDataSeeder _permissionDataSeeder;
    
    public ClientServicesQueryDataSeeder(IPermissionDataSeeder permissionDataSeeder,
        ILogger<ClientServicesQueryDataSeeder> logger)
    {
        _permissionDataSeeder = permissionDataSeeder;
        _logger = logger;
    }
    
    [UnitOfWork]
    public virtual async Task SeedAsync(Guid? tenantId = null)
    {
        _logger.LogInformation("Starting ClientServicesQuery permission seeding...");
    
        try
        {
            var permissions = ClientServicesQueryPermissions.GetAll();
            _logger.LogInformation("Found {PermissionCount} permissions to seed: {Permissions}", 
                permissions.Length, 
                string.Join(", ", permissions));
    
            // Grant permissions to the "admin" role
            await _permissionDataSeeder.SeedAsync(
                RolePermissionValueProvider.ProviderName,
                "admin",
                permissions,
                tenantId
            );
    
            _logger.LogInformation("Successfully seeded ClientServicesQuery permissions for admin role");
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to seed ClientServicesQuery permissions");
            throw;
        }
    }
}

I need guidance on how to get the permission to persist to the administration permissions databases where I do not have a database to migrate in the microservice.

Provide us with the following info: 🧐 Hint: If you are using the ABP Studio, you can see all the information about your solution from the configuration window, which opens when you right-click on the solution and click on the Solution Configuration button.

  • Template: microservice
  • Created ABP Studio Version: 1.0.2
  • Current ABP Studio Version: 1.2.2
  • Multi-Tenancy: Yes
  • UI Framework: mvc
  • Theme: leptonx
  • Theme Style: system
  • Theme Menu Placement: side
  • Run Install Libs: Yes
  • Database Provider: ef
  • Database Management System: sqlserver
  • Mobile Framework: none
  • Public Website: No
  • Social Login: Yes
  • Include Tests: Yes
  • Dynamic Localization: Yes
  • Kubernetes Configuration: Yes
  • Grafana Dashboard: Yes
  • Use Local References: No
  • Optional Modules:
    • GDPR
    • TextTemplateManagement
    • AuditLogging
    • OpenIddictAdmin
  • Selected Languages: English, English (United Kingdom), Español
  • Default Language: English
  • Create Command: abp new CloverleafCMS -t microservice --ui-framework mvc --database-provider ef --database-management-system sqlserver --theme leptonx --skip-migrator --without-cms-kit --dont-run-bundling -no-file-management -no-language-management

We're using the microservice template and using the auth-server app for authentication. The auth-server application has been slightly modified for custom branding. We are running the authserver and microservices in Azure Kubernetes.

Here is the 'HostTenantResolveContributor.cs'

public class HostTenantResolveContributor : TenantResolveContributorBase
{
    public override async Task ResolveAsync(ITenantResolveContext context)
    {
        var currentContextAccessor = context.ServiceProvider.GetRequiredService<IHttpContextAccessor>();
        var memberConfigService = context.ServiceProvider.GetRequiredService<IMemberConfigService>();
        
        if (memberConfigService != null)
        {
#if DEBUG
            currentContextAccessor.HttpContext.Request.Host = new HostString("auth.homefree.cloverleafcms.us"); // Set the host header to a default value for testing purposes
            //currentContextAccessor.HttpContext.Request.Path = new PathString("/Account/Login"); // Set the path to root for testing purposes
#endif
            string? prefix = currentContextAccessor?.HttpContext?.Request?.GetPrefixFromHost();
            Console.WriteLine($"Tenant prefix after GetPrefixFromHost is: {prefix}.");
            if (!string.IsNullOrEmpty(prefix) && prefix != "admin")
            {
                var responseDto = await memberConfigService.GetMemberConfigByUrlPrefixAsync(prefix);
    
                if (responseDto != null && responseDto.Success)
                {
                    var member = responseDto.MemberConfig;
                    context.TenantIdOrName = member?.Id.ToString();
                    Console.WriteLine($"Member found for prefix: {prefix}");
                    Console.WriteLine($"MemberId: {member?.Id.ToString()}");
                }
                else
                {
                    Console.WriteLine($"Member not found for prefix: {prefix}. See details: {responseDto?.ErrorResponse?.Error?.Message}");
                    context.TenantIdOrName = null;
                }
                return;
            }
            else
            {
                Console.WriteLine("Tenant prefix not found in the host.");
                context.TenantIdOrName = null;
            }
        }
        else
        {
            Console.WriteLine("MemberConfigService is not available.");
            context.TenantIdOrName = null;
        }
    }

    public override string Name => "Host";

}

Here is the GetPrefixFromHost.cs extension

public static class HttpRequestExtensions
{
    public static string? GetPrefixFromHost(this HttpRequest request)
    {
        if (request?.Host.HasValue != true)
        {
            return "invalid";
        }
        string host = request.Host.Host;
        try
        {
            // Check for localhost
            if (host.Contains("localhost"))
                return null;
            if (host.Contains("host.docker.internal"))
                return null;
            // Split the host into parts
            var parts = host.Split('.');
            
            if (parts.Length < 2)
                return null;
        
            var first = parts[0];
            var second = parts[1];
        
            if (second.Equals("admin", StringComparison.OrdinalIgnoreCase))
            {
                Console.WriteLine("Admin subdomain detected, returning null for prefix.");
                return null;
            }
        
            if (first.Equals("auth", StringComparison.OrdinalIgnoreCase) && parts.Length >= 3)
            {
                // Return the second part as prefix
                Console.WriteLine($"Member subdomain detected, returning {parts[1]} for prefix.");
                return parts[1];
            }
        
            return "invalid"; // Return "invalid" for other cases
        }
        catch
        {
            // Return "invalid" for invalid URLs
            return "invalid";
        }
    }
}

Okay... I think we found it. Here is my curl snippet.

There was an extra '}' at the end of the Bearer Token.

The GET Postman Authorization tab looked like this:

I removed the extra '}" and the GET returned data. Thanks for help.

Showing 1 to 10 of 31 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.1.0-preview. Updated on October 07, 2025, 05:59