Open Closed

ABP 10 - Dynamic HTTP client proxies no longer forward incoming bearer tokens and fall back to IdentityClients. #10772


User avatar
0
jeff.montouliu created

Hi team,

We are seeing what looks like a behavior change/regression after upgrading from ABP 9 to ABP 10.

Summary

In ABP 10, dynamic HTTP client proxies created with AddHttpClientProxies(...) are no longer forwarding the incoming Authorization: Bearer ... header to downstream internal microservices.

Instead, the proxy tries to resolve an IdentityClientConfiguration for the remote service and, if it is not configured, sends the request without an authorization header.

This results in:

  • authenticated incoming request in the gateway/orchestrator
  • no outgoing bearer token on the proxied HTTP call
  • warning: Could not find IdentityClientConfiguration for HiddenNameService. Either define a configuration for HiddenNameService or set a default configuration.
  • downstream service returning 401

Versions

Worked before:

  • ABP 9.3.7

Fails after upgrade:

  • ABP 10.2.0

Relevant packages:

  • Volo.Abp.Http.Client
  • Volo.Abp.Http.Client.IdentityModel.Web
  • Volo.Abp.AspNetCore.Authentication.JwtBearer

Architecture

Microservice solution with:

  • Orchestrator service
  • Internal downstream services (example: Fantasy name service)
  • JWT bearer authentication
  • confidential client calling the orchestrator (client_id = ForDemoPropurse)
  • dynamic client proxies via AddHttpClientProxies(...)

The orchestrator has:

  • AbpHttpClientIdentityModelWebModule
  • AddAbpJwtBearer(...)
  • AddHttpClientProxies(..., remoteServiceConfigurationName: "hiddenNameService")

Problem

Incoming request to Orchestrator is authenticated correctly.

However, when Orchestrator calls downstream service through ABP dynamic proxy:

  • incoming Authorization header exists
  • HttpContext.User.Identity.IsAuthenticated == true
  • client_id claim is present
  • outgoing proxied request does not contain Authorization

Then ABP tries to use IdentityClients config instead.

If IdentityClients is not configured, the request goes out unauthenticated.

Observed logs

Incoming request is authenticated, but outgoing proxy request does not carry auth:

Proxy auth debug before. GET http://localhost:44321/api/microserviceName/entityName?Name=For demo only&SkipCount=0&MaxResultCount=10&api-version=1.0.
OutgoingAuthPresent=False,
OutgoingAuthScheme=<null>,
OutgoingTokenLength=0,
IncomingContextPresent=True,
IncomingAuthPresent=True,
IncomingUserAuthenticated=True,
IncomingClientId=Boomi,
ResponseStatusCode=null 

ABP then logs:

text
Could not find IdentityClientConfiguration for HidenNameService. Either define a configuration for HidennameService or set a default configuration.

Expected behavior When an authenticated request reaches the orchestrator, the dynamic HTTP client proxy should preserve/forward the original bearer token to trusted internal downstream services, unless explicitly overridden. This is the behavior our solution relied on before the ABP 10 upgrade. Actual behavior In ABP 10: the incoming bearer token is not forwarded proxy tries IdentityClients resolution if not configured, request is sent without bearer token downstream authorized endpoints return 401

Is this behavior change in ABP 10 intentional? If yes, is there a recommended built-in way to restore the previous "forward incoming bearer token" behavior for internal proxy calls? If not intentional, can this be treated as a regression in Volo.Abp.Http.Client.IdentityModel.Web / dynamic proxy auth forwarding?

Minimal repro idea Create microservice A and B Protect an endpoint in B with authorization Authenticate request into A with JWT bearer From A, call B using AddHttpClientProxies(...) Do not configure IdentityClients Observe that:incoming request in A is authenticated outgoing request from A to B has no Authorization ABP logs missing IdentityClientConfiguration B returns 401

Logs in microservice A: 2026-07-01 16:57:37.152 -03:00 [INF] Start processing HTTP request GET http://localhost:44321/api/abp/api-definition 2026-07-01 16:57:37.158 -03:00 [INF] Sending HTTP request GET http://localhost:44321/api/abp/api-definition 2026-07-01 16:57:37.644 -03:00 [INF] Received HTTP response headers after 480.0987ms - 200 2026-07-01 16:57:37.646 -03:00 [INF] End processing HTTP request after 506.0534ms - 200 2026-07-01 16:57:37.872 -03:00 [WRN] Could not find IdentityClientConfiguration for HiddenNameService. Either define a configuration for HiddenNameService or set a default configuration. 2026-07-01 16:57:37.878 -03:00 [INF] Start processing HTTP request GET http://localhost:44321/api/microserviceName/consumableTypes?* 2026-07-01 16:57:37.891 -03:00 [INF] Sending HTTP request GET http://localhost:44321/api/microserviceName/consumableTypes?* 2026-07-01 16:57:40.996 -03:00 [INF] Received HTTP response headers after 3105.0265ms - 401 2026-07-01 16:57:40.996 -03:00 [INF] End processing HTTP request after 3118.6689ms - 401

Logs in microservice B: 2026-07-01 17:24:19.261 -03:00 [WRN] ---------- RemoteServiceErrorInfo ---------- { "code": "Volo.Authorization:010001", "message": "¡Autorización fallida! Dada la política no se ha concedido.", "details": "AbpAuthorizationException: Exception of type 'Volo.Abp.Authorization.AbpAuthorizationException' was thrown.\r\n", "data": {}, "validationErrors": null }

2026-07-01 17:24:19.264 -03:00 [WRN] Exception of type 'Volo.Abp.Authorization.AbpAuthorizationException' was thrown. Volo.Abp.Authorization.AbpAuthorizationException: Exception of type 'Volo.Abp.Authorization.AbpAuthorizationException' was thrown. at Microsoft.AspNetCore.Authorization.AbpAuthorizationServiceExtensions.CheckAsync(IAuthorizationService authorizationService, AuthorizationPolicy policy) at Volo.Abp.Authorization.MethodInvocationAuthorizationService.CheckAsync(MethodInvocationAuthorizationContext context) at Volo.Abp.Authorization.AuthorizationInterceptor.AuthorizeAsync(IAbpMethodInvocation invocation) at Volo.Abp.Authorization.AuthorizationInterceptor.InterceptAsync(IAbpMethodInvocation invocation) at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func3 proceed) at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo) at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue1.ProceedAsync() at Volo.Abp.Validation.ValidationInterceptor.InterceptAsync(IAbpMethodInvocation invocation) at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func3 proceed) at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo) at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue1.ProceedAsync() at Volo.Abp.Auditing.AuditingInterceptor.ProceedByLoggingAsync(IAbpMethodInvocation invocation, AbpAuditingOptions options, IAuditingHelper auditingHelper, IAuditLogScope auditLogScope) at Volo.Abp.Auditing.AuditingInterceptor.InterceptAsync(IAbpMethodInvocation invocation) at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func3 proceed) 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.DynamicProxy.CastleAsyncAbpInterceptorAdapter1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func3 proceed) at lambda_method3197(Closure, Object) at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.AwaitableObjectResultExecutor.Execute(ActionContext actionContext, IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask1 actionResultValueTask) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync() --- End of stack trace from previous location --- at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextExceptionFilterAsync>g__Awaited|26_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) 2026-07-01 17:24:19.264 -03:00 [WRN] Code:Volo.Authorization:010001 2

Markdown supported.
Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)

4 Answer(s)
  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    Hi,

    This is an unintended behavior change in ABP 10, not by design. When the request is authenticated by a client (client_credentials) instead of a user, the dynamic proxy no longer forwards the incoming token and falls back to IdentityClients, so the downstream call goes out without auth and returns 401.

    You can restore the previous behavior with this override:

    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Authentication;
    using Microsoft.AspNetCore.Http;
    using Volo.Abp.DependencyInjection;
    using Volo.Abp.Http.Client.Authentication;
    using Volo.Abp.Http.Client.IdentityModel.Web;
    
    namespace MyCompanyName.MyProject;
    
    [Dependency(ReplaceServices = true)]
    [ExposeServices(typeof(IAbpAccessTokenProvider))]
    public class MyHttpContextAbpAccessTokenProvider : HttpContextAbpAccessTokenProvider
    {
        public MyHttpContextAbpAccessTokenProvider(IHttpContextAccessor httpContextAccessor)
            : base(httpContextAccessor)
        {
        }
    
        public override async Task<string?> GetTokenAsync()
        {
            var httpContext = HttpContextAccessor?.HttpContext;
            if (httpContext == null)
            {
                return null;
            }
    
            if (httpContext.User.Identity?.IsAuthenticated != true)
            {
                return null;
            }
    
            return await httpContext.GetTokenAsync("access_token");
        }
    }
    

    We'll fix this in the framework in the next release, so you can drop the override after upgrading.

    Thanks

    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    Hi,

    Your current question credits have been refunded.

    Thanks

    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
  • User Avatar
    0
    jeff.montouliu created

    Hi!

    Thank you very much, we will implement that middleware until the new release.

    Thanks

    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    👍

    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
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 September 21, 2026, 06:18
1
ABP Assistant
🔐 You need to be logged in to use the chatbot. Please log in first.