Activities of "maliming"

You can listen for language changes in ABP Angular using the built-in services from @abp/ng.core. Here are the recommended approaches:

Option 1: LocalizationService.languageChange$ (Recommended)

This is the best option because it fires after the language switch is fully complete (localization resources refreshed, locale registered):

import { LocalizationService } from '@abp/ng.core';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';

@Component({ ... })
export class MyComponent implements OnInit, OnDestroy {
  private destroy$ = new Subject<void>();

  constructor(private localizationService: LocalizationService) {}

  ngOnInit() {
    this.localizationService.languageChange$
      .pipe(takeUntil(this.destroy$))
      .subscribe(newLanguage => {
        console.log('Language changed to:', newLanguage);
        // your custom logic here
      });
  }

  ngOnDestroy() {
    this.destroy$.next();
    this.destroy$.complete();
  }
}

Option 2: SessionStateService.onLanguageChange$()

This fires immediately when the language starts changing (localization resources may not be refreshed yet):

import { SessionStateService } from '@abp/ng.core';

constructor(private sessionState: SessionStateService) {}

ngOnInit() {
  this.sessionState.onLanguageChange$()
    .pipe(takeUntil(this.destroy$))
    .subscribe(lang => {
      console.log('Language is changing to:', lang);
    });
}

Option 3: SessionStateService.getLanguage$()

Returns an Observable of the current language including the initial value:

import { distinctUntilChanged } from 'rxjs/operators';

this.sessionState.getLanguage$()
  .pipe(distinctUntilChanged(), takeUntil(this.destroy$))
  .subscribe(lang => {
    console.log('Current language:', lang);
  });

About the API call

The GET /api/abp/application-configuration call is made by AbpApplicationConfigurationService, and ConfigStateService.refreshLocalization() is responsible for refreshing localization resources when the language changes. The internal flow is:

  1. SessionStateService.setLanguage() → updates the store state
  2. LocalizationService.listenToSetLanguage() → detects the change
  3. ConfigStateService.refreshLocalization(lang) → calls the API to refresh localization
  4. LocalizationService.languageChange$ → emits the event after everything is done

You don't need to intercept the API call directly — just subscribe to the Observables above to react to language changes.

hi

To answer your question: this is partly an ABP framework issue. HttpContextIdentityModelRemoteServiceHttpClientAuthenticator should not silently fall back to client credentials when ICurrentUser.IsAuthenticated is true — that fallback produces incorrect results for user-context endpoints regardless of why the token is unavailable. We'll look into improving this in the framework.

However, we still need to understand why httpContext.GetTokenAsync("access_token") returns null for some authenticated requests in your environment. The backup/recovery mechanism works around the symptom, but we want to find the root cause. The latest code we pushed includes detailed diagnostic output (AUTH DUMP) that fires automatically when the token is missing — it dumps all stored tokens, the full AuthenticateAsync() result, authentication properties, and the cookie header size.

Could you share the Web tier logs after the deployment has been running for a day or two with real users? Specifically we're looking for:

  • ABP_DIAG: AUTH DUMP entries — these reveal exactly what's present vs missing in the OIDC session when the token loss occurs
  • ABP_DIAG: RECOVERED from backup entries — confirms the backup mechanism is working and that the primary source did return null
  • ABP_DIAG: Authenticator entries at Warning/Error level — shows the state at the HTTP client authenticator layer

This will tell us whether the issue is cookie-related (truncation, data protection), session-related (ticket store eviction), or something else entirely.

Thanks.

hi

Can you share your Gateway project source code to liming.ma@volosoft.com?

Thanks.

ok, you can subscribe to this issue https://github.com/abpframework/abp/issues/24213. We will close it once MySQL supports .NET 10.

Thanks,

hi

Your case may be caused by:

HttpContextIdentityModelRemoteServiceHttpClientAuthenticator.Authenticate()
  → AccessTokenProvider.GetTokenAsync() returns null
  → Falls back to base.Authenticate()
  → IdentityModelAuthenticationService: client credentials grant
  → 825-char token, no 'sub', no 'session_id'

We also reviewed your identitymodel.txt (March 20-23) — 58 out of 95 tokens are client credentials, generated every 30-90 minutes 24/7, including all day Saturday with zero users online. That's your Hangfire workers (CachePingWorker, EDT workers, health checks, etc.) running in the API Host process with no HttpContext — completely legitimate and unaffected by our changes.

We've pushed updated code to the PR with three layers:

Layer 1: Token backup + recovery (AccessTokenBackupMiddleware + AccessTokenBackupStore)

A new middleware saves a copy of the user's access_token to Redis on every authenticated request. When the primary source (OIDC cookie) returns null, both the decorator and the authenticator attempt to recover from this backup. If the backup exists, the request proceeds normally with the recovered token — the user never sees missing menus.

This is registered in the middleware pipeline:

app.UseAuthentication();
app.UseMiddleware<AccessTokenDiagnosticMiddleware>();
app.UseMiddleware<AccessTokenBackupMiddleware>();  // saves token to Redis

Layer 2: SafeRemoteServiceHttpClientAuthenticator (prevents client credentials fallback)

Replaces ABP's HttpContextIdentityModelRemoteServiceHttpClientAuthenticator in the Web tier only. When the user's token is unavailable:

  1. Tries to recover from the Redis backup
  2. If backup found → uses it (request succeeds normally)
  3. If backup not found → skips authentication entirely (no client credentials token sent)

Also detects Polly retry scenarios by checking if the Authorization header is already set when Authenticate() is called — this would indicate the request is being retried by the resilience handler.

Layer 3: DiagnosticApplicationConfigurationClientDecorator guard (prevents cache poisoning)

Last line of defense. If both primary token and backup are unavailable, blocks the remote API call and returns an empty AppConfig WITHOUT caching it. The page renders with reduced permissions for that single request only.

Diagnostic output

We still need to understand WHY the token goes missing. When the primary source fails, the code dumps:

  • All stored tokens in the OIDC session (access_token, refresh_token, id_token, expires_at)
  • Full AuthenticateAsync() result with Properties.Items
  • Cookie header size (to detect truncation)
  • HttpContext.User identity state
  • Thread ID (to detect async context loss)
  • Whether the request is a Polly retry

After deploying, watch for these entries in the Web tier logs:

| Log pattern | What it means | |---|---| | RECOVERED from backup | Token was missing from cookie but recovered from Redis — user experience preserved | | Both primary and backup token sources returned null | First request for a new user where no backup exists yet | | AUTH DUMP — Stored tokens | Shows exactly which tokens are present/missing in the OIDC session | | AUTH DUMP — Cookie header size | If unusually large, cookies may be getting truncated | | Authenticator — called again on a request that ALREADY has Authorization header | Polly retry detected | | Authenticator — BLOCKING client credentials fallback | Fallback prevented |

Your Hangfire background jobs are unaffected — all changes are in CabMD.Web and CabMD.Web.Public only.

You can try again and share the new logs.

Thanks.

: )

hi

This vulnerability (GHSA-rvv3-g6hj-g44x) has been addressed in ABP 10.2 via [PR #25138](https://github.com/abpframework/abp/pull/25138), which sets a default MaxDepth = 64 for all AutoMapper maps.

For ABP 8.x, you can apply the same mitigation without modifying framework code. Add the following to ConfigureServices in any of your modules:

Configure<AbpAutoMapperOptions>(options =>
{
    options.Configurators.Add(ctx =>
    {
        ctx.MapperConfiguration.Internal().ForAllMaps((typeMap, _) =>
        {
            if (typeMap.MaxDepth == 0)
            {
                typeMap.MaxDepth = 64;
            }
        });
    });
});

This iterates over all registered maps and sets MaxDepth = 64 for any map that doesn't already have an explicit MaxDepth configured, which prevents the StackOverflow DoS caused by deeply nested object graphs.

You'll need to add using AutoMapper.Internal; for the Internal() extension method.

Thanks.

I'm glad you solved the problem. 👍

Great 👍

👍

Showing 731 to 740 of 12917 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.