Activities of "maliming"

Hi,

The output paths are fixed in Theme Builder. There is no setting or config file to change them, either in the solution or in ABP Studio.

The only thing you can choose is which projects the theme is applied to, in the Select Projects step.

You can copy the files elsewhere after applying a theme, but it won't stick. The next apply recreates them in the original folders and points its own style entries in angular.json back there. So you'd have to redo the copy after every apply.

Could you tell me why you need them in a different place, and how your Angular workspace is laid out? If it's not the standard template layout, that's something we should handle on our side.

Thanks

Hi,

Closing this one. A short summary first, since the thread ended up covering several different problems.

The missing aud came from the scope records. Every row in OpenIddictScopes had IsDeleted = true, and ABP's scope lookup filters soft-deleted rows:

... FROM "OpenIddictScopes" AS o
WHERE NOT (o."IsDeleted") AND (o."Name" = ANY (@names) ...)

Nothing comes back, so there are no resources, so there are no audiences, and OpenIddict only writes aud when the audience set is not empty. Restoring the rows brought aud back:

update "OpenIddictScopes"
set "IsDeleted" = false, "DeletionTime" = null, "DeleterId" = null
where "IsDeleted" = true;

This was hard to see because RegisterScopes(...) registers the scope names in code. The discovery document still listed every scope and the token requests still returned 200. Only the resources are read from the database.

The 401 on refresh was a separate thing. The refresh call sent client_id but no client_secret, and the client is registered as confidential, so OpenIddict rejected it with invalid_client / ID2198. That rule is not new in ABP 10.6, OpenIddict 5.5 enforces it too and reports it as ID2054.

Two things worth noting for anyone reading this later. ValidateAudience was turned off during the investigation and should be turned back on once each API host's expected audience is confirmed. And a browser app should use a public client with no secret, ideally with authorization code and PKCE.

The remaining work is on the application side and the team is handling it. For anything new, please open a new question with the details and logs.

Thanks

Hi,

While the audience switch is going in, it's worth deploying one more thing in the same round. These three log points pin down exactly where the resources are lost, so the call can start from an answer instead of a guess.

Add this to the identity service:

using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using OpenIddict.Abstractions;
using OpenIddict.Server;
using Volo.Abp.DependencyInjection;
using Volo.Abp.OpenIddict;

namespace SCV.Litmus.Identity;

public class AudienceDiagnosticsBefore : IAbpOpenIddictClaimsPrincipalHandler, ITransientDependency
{
    private readonly ILogger<AudienceDiagnosticsBefore> _logger;

    public AudienceDiagnosticsBefore(ILogger<AudienceDiagnosticsBefore> logger)
    {
        _logger = logger;
    }

    public Task HandleAsync(AbpOpenIddictClaimsPrincipalHandlerContext context)
    {
        _logger.LogError(
            "AUD-DIAG 1/3 before custom handlers | grant={Grant} requestScope={RequestScope} principalScopes=[{Scopes}] principalResources=[{Resources}]",
            context.OpenIddictRequest.GrantType,
            context.OpenIddictRequest.Scope,
            string.Join(",", context.Principal.GetScopes()),
            string.Join(",", context.Principal.GetResources()));

        return Task.CompletedTask;
    }
}

public class AudienceDiagnosticsAfter : IAbpOpenIddictClaimsPrincipalHandler, ITransientDependency
{
    private readonly ILogger<AudienceDiagnosticsAfter> _logger;

    public AudienceDiagnosticsAfter(ILogger<AudienceDiagnosticsAfter> logger)
    {
        _logger = logger;
    }

    public Task HandleAsync(AbpOpenIddictClaimsPrincipalHandlerContext context)
    {
        _logger.LogError(
            "AUD-DIAG 2/3 after custom handlers | principalScopes=[{Scopes}] principalResources=[{Resources}] principalAudiences=[{Audiences}] identityType={IdentityType}",
            string.Join(",", context.Principal.GetScopes()),
            string.Join(",", context.Principal.GetResources()),
            string.Join(",", context.Principal.GetAudiences()),
            context.Principal.Identity?.GetType().Name);

        return Task.CompletedTask;
    }
}

public class AudienceDiagnosticsOnSignIn : IOpenIddictServerHandler<OpenIddictServerEvents.ProcessSignInContext>
{
    public static OpenIddictServerHandlerDescriptor Descriptor { get; }
        = OpenIddictServerHandlerDescriptor.CreateBuilder<OpenIddictServerEvents.ProcessSignInContext>()
            .AddFilter<OpenIddictServerHandlerFilters.RequireAccessTokenGenerated>()
            .UseSingletonHandler<AudienceDiagnosticsOnSignIn>()
            .SetOrder(OpenIddictServerHandlers.PrepareAccessTokenPrincipal.Descriptor.Order + 1)
            .SetType(OpenIddictServerHandlerType.Custom)
            .Build();

    private readonly ILogger<AudienceDiagnosticsOnSignIn> _logger;

    public AudienceDiagnosticsOnSignIn(ILogger<AudienceDiagnosticsOnSignIn> logger)
    {
        _logger = logger;
    }

    public ValueTask HandleAsync(OpenIddictServerEvents.ProcessSignInContext context)
    {
        _logger.LogError(
            "AUD-DIAG 3/3 access token principal | resources=[{Resources}] audiences=[{Audiences}] scopes=[{Scopes}]",
            string.Join(",", context.AccessTokenPrincipal?.GetResources() ?? Enumerable.Empty<string>()),
            string.Join(",", context.AccessTokenPrincipal?.GetAudiences() ?? Enumerable.Empty<string>()),
            string.Join(",", context.AccessTokenPrincipal?.GetScopes() ?? Enumerable.Empty<string>()));

        return default;
    }
}

Register it in your identity module:

public override void PreConfigureServices(ServiceConfigurationContext context)
{
    PreConfigure<OpenIddictServerBuilder>(builder =>
    {
        builder.AddEventHandler(AudienceDiagnosticsOnSignIn.Descriptor);
    });
}

public override void ConfigureServices(ServiceConfigurationContext context)
{
    Configure<AbpOpenIddictClaimsPrincipalOptions>(options =>
    {
        options.ClaimsPrincipalHandlers.Insert(0, typeof(AudienceDiagnosticsBefore));
        options.ClaimsPrincipalHandlers.Add(typeof(AudienceDiagnosticsAfter));
    });
}

Two things to watch when you wire it up. Insert(0, ...) matters, that one has to run before your own handlers. And if your module already has a PreConfigure<OpenIddictServerBuilder> inside an if (!hostingEnvironment.IsDevelopment()) block, don't put the AddEventHandler line in there, it needs to run in every environment.

Then log in once and send me the three AUD-DIAG lines. On a working setup they come out like this, from a password grant with one API scope:

AUD-DIAG 1/3 before custom handlers | grant=password requestScope=openid profile ... MyApi principalScopes=[openid,profile,...,MyApi] principalResources=[MyApi]
AUD-DIAG 2/3 after custom handlers | principalScopes=[openid,profile,...,MyApi] principalResources=[MyApi] principalAudiences=[] identityType=ClaimsIdentity
AUD-DIAG 3/3 access token principal | resources=[] audiences=[MyApi] scopes=[openid,profile,...,MyApi]

Two empty fields in there are normal, so don't read them as the fault: principalAudiences is empty on 2/3, and resources is empty on 3/3. OpenIddict carries the resources onto the access token principal as audiences, which is the audiences=[MyApi] on 3/3.

Against that baseline:

  • 1/3 has empty principalResources - the scope lookup against OpenIddictScopes came back with nothing, so it's the data or the database the service is actually connected to
  • 1/3 has resources but 2/3 is empty - one of your own handlers is rebuilding or replacing the principal and dropping them
  • 1/3 and 2/3 both have resources but 3/3 has empty audiences - they're lost between sign-in and token generation

It logs at Error level so you don't have to change any log configuration, and it comes back out once we're done.

Two more things that would help before we meet:

On the database the identity service actually connects to, run this and send the output along with the host and database name:

select "Name", "Resources", "LastModificationTime" from "OpenIddictScopes" order by "Name";

And clear the browser site data before you judge the login result. A redeploy doesn't touch local storage, so the previous token is still sitting there and it will look like nothing changed.

Thanks

Hi,

Thanks for the logs and the class files, they made this much easier to narrow down.

The switch didn't take effect because it went into the wrong block. In ConfigureAuthenticationSetup, options.TokenValidationParameters.ValidateAudience = false; sits inside .AddOpenIdConnect(...), while the failing requests are handled by the Bearer scheme, the .AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, ...) block right after AddAuthentication.

Could you move it there, redeploy both the identity service and the gateway, and try a login? If the app comes up, the audience check is the only thing still failing. If it doesn't, the gateway log for that one request would tell us a lot.

Thanks

Hi,

It's tied to the seat count, not to the specific people.

  1. Yes, member management keeps working after expiry. You can remove a developer and add someone else into the freed seat on the organization management page, the same way as while the license is active. The number of seats stays the same.

  2. Yes. Once added, the new developer's abp login works the same way as for the rest of the team.

  3. Yes. The Development-mode check passes for them as well, including on a machine that never had ABP installed. The fresh-machine steps from my previous reply are the same for them.

Thanks

Hi,

Thanks, these logs show where it stands now. The scheme change worked: the gateway reads jwks_uri over https and the token signature validates. What's left is the audience, every request to the gateway fails with:

IDX10206: Unable to validate audience. The 'audiences' parameter is empty.

The access token has no aud claim. ABP fills it from the resources of the granted scopes, read from OpenIddictScopes in the host database, and for your token that lookup comes back empty.

To confirm that quickly, add this inside AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, ...) in ConfigureAuthenticationSetup, which both the gateway and the identity host use, and redeploy both:

options.TokenValidationParameters.ValidateAudience = false;

That only hides the problem though, the token is still issued without aud. To find the actual cause, please send the result of this query on the host database:

select "Name", "Resources" from "OpenIddictScopes";

Along with it, send the code that adds the ua, client_ip and session_id claims to the token, and any override you have of the token endpoint. Those claims are added while the token is being issued, the same step where the resources get set.

Thanks

Hi,

The logs and files you shared last week are what found the jwks_uri, aud and MapInboundClaims problems. Now that those changes are deployed, we need logs from the current build to see what's still failing. What I asked for earlier still stands, nothing has come in yet for the new build:

  • the identitymodel logs from both projects, with the Scheme / X-Forwarded-Proto lines: https://abp.io/support/questions/10870#answer-3a23a2b0-aad3-9c4a-1b74-7106468c25bb
  • the gateway debug log: https://abp.io/support/questions/10870#answer-3a23a193-9b07-d809-4954-dcff5005d4b2

For the debug log, replace the #if DEBUG / #else / #endif block in the gateway Program.cs with this line, otherwise Release builds drop every Debug entry:

loggerConfiguration.MinimumLevel.Debug();

In addition, for the same application-configuration call:

  1. The gateway log lines containing [AUTH or Token Validation
  2. Its request headers from the Network tab: is Authorization: Bearer there, and does Cookie contain .AspNetCore.Identity.Application (mask the values)
  3. The current jwks_uri in /.well-known/openid-configuration

These are the same things I'd need on a call, so sending them first saves that time. Email works too: liming.ma@volosoft.com

Thanks

Hi,

In the Angular app, logout (including the idle/automatic logout) goes through the OpenIddict end session endpoint (connect/endsession), not the /Account/Logout page, so your CustomLogoutModel is never called. When Angular starts the login again, the authorize request has no tenantName or _tenantHost, so the login page falls back to the host.

You can remember the tenant in a cookie on the auth server after a tenant login, and use it when the login page has no tenant info. Changes in CustomLoginModel:

using Microsoft.AspNetCore.Http;

private const string TenantHostCookieName = "Ifs.TenantHostName";

In OnGetAsync, fall back to the cookie:

var tenantFromReturnUrl = ExtractTenantFromReturnUrl(ReturnUrl)
                          ?? Request.Cookies[TenantHostCookieName];

In ProcessLoginAsync, save it after a successful login:

var result = await base.OnPostAsync(action);
if (IsLoginFailed(result))
{
    return AddErrorAndReturnPage("LoginInput.UserNameOrEmailAddress", "The username or password is incorrect.");
}

RememberTenantHost(tenant);
private void RememberTenantHost(Tenant? tenant)
{
    if (tenant == null || string.IsNullOrWhiteSpace(TenantHostName))
    {
        Response.Cookies.Delete(TenantHostCookieName);
        return;
    }

    Response.Cookies.Append(TenantHostCookieName, TenantHostName, new CookieOptions
    {
        HttpOnly = true,
        Secure = Request.IsHttps,
        SameSite = SameSiteMode.Lax,
        IsEssential = true,
        Expires = DateTimeOffset.UtcNow.AddDays(30)
    });
}

Thanks

Hi,

Could you share the exact Devart.Data.Oracle.EFCore version in your solution? You can run this in the .EntityFrameworkCore project folder and send the Devart.* and Microsoft.EntityFrameworkCore* lines:

dotnet list package --include-transitive

In the meantime, could you try these one at a time and let us know the result:

  1. Upgrade Devart.Data.Oracle.EFCore to the latest 11.2.192.10. Devart has fixed several Contains query issues for EF Core 10 in recent releases: https://www.devart.com/dotconnect/oracle/revision_history.html

  2. If it still fails, switch the parameterized collection translation to constants in your YourProjectNameEntityFrameworkCoreModule:

Configure<AbpDbContextOptions>(options =>
{
    options.UseOracle(builder =>
    {
        builder.UseParameterizedCollectionMode(Microsoft.EntityFrameworkCore.ParameterTranslationMode.Constant);
    });
});

The question was closed shortly after it was created. If you've already solved it, could you share what fixed it?

Thanks

ok : )

Showing 111 to 120 of 12911 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.8.0-preview. Updated on November 02, 2026, 06:56
1
ABP Assistant
🔐 You need to be logged in to use the chatbot. Please log in first.