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.ClientVolo.Abp.Http.Client.IdentityModel.WebVolo.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:
AbpHttpClientIdentityModelWebModuleAddAbpJwtBearer(...)AddHttpClientProxies(..., remoteServiceConfigurationName: "hiddenNameService")
Problem
Incoming request to Orchestrator is authenticated correctly.
However, when Orchestrator calls downstream service through ABP dynamic proxy:
- incoming
Authorizationheader exists HttpContext.User.Identity.IsAuthenticated == trueclient_idclaim 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
4 Answer(s)
-
0
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 toIdentityClients, 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) -
0
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)