Open Closed

IntegrationService throws unauthorized error when accessed via another backend service #9992


User avatar
0
tapmui created

Documentation read: https://github.com/abpframework/abp/blob/dev/docs/en/framework/api-development/integration-services.md https://abp.io/community/articles/integration-services-explained-what-they-are-when-to-use-them-and-how-they-behave-lienmsy8#gsc.tab=0 Support notes: https://abp.io/support/questions/8012/Service-to-Service-communication

Problem description:

  • backend service A has and endpoint from where the another module integrationservice is accessed. If the the endpoint in integration service is protected by permission it fails on unauthorized exception (401).
  • the integration endpoint can be accessed directly ie. with postman, no issues.
  • if IotPermissions.IotCombinedDatas.Default permission is removed then this works. But then also this endpoint can be accessed without token. And that is not acceptable.
  • if I add [Authorize] at the service level, again same 401 error. I can add permission IotPermissions.IotCombinedDatas.Default in the backend service A endpoint; user can access this nicely--> this validates that he has the permission allowed.

My excpectation is that the same permissions are to be used also when integrationservice is accessed. What might be the reaso for this; and what is the solution to overcome ? Please advice.

Integrationservice example below:

` [Authorize] // If this is removed then access without token possible, fatal security risk. public class IotintegrationAppService: IotAppService, IIotIntegrationApiService { protected IDistributedCache<IotCombinedDataDownloadTokenCacheItem, string> _downloadTokenCache; protected IIotCombinedDataRepository _iotCombinedDataRepository; protected IotCombinedDataManager _iotCombinedDataManager;

    public IotintegrationAppService(IIotCombinedDataRepository iotCombinedDataRepository, IotCombinedDataManager iotCombinedDataManager, IDistributedCache<IotCombinedDataDownloadTokenCacheItem, string> downloadTokenCache)
    {
        _downloadTokenCache = downloadTokenCache;
        _iotCombinedDataRepository = iotCombinedDataRepository;
        _iotCombinedDataManager = iotCombinedDataManager;

    }

    [Authorize(IotPermissions.IotCombinedDatas.Default)] // If this is removed then I can call this API point.
    public virtual async Task<PagedResultDto<IotCombinedDataDto>> GetListAsync(GetIotCombinedDatasInput input)
    {
        var totalCount = await _iotCombinedDataRepository.GetCountAsync(input.FilterText, input.Status, input.StorageTimeMin, input.StorageTimeMax, input.WorkPhaseOn);
        var items = await _iotCombinedDataRepository.GetListAsync(input.FilterText, input.Status, nput.StorageTimeMin, input.StorageTimeMax, input.WorkPhaseOn, input.Sorting, input.MaxResultCount, input.SkipCount);

        return new PagedResultDto<IotCombinedDataDto>
        {
            TotalCount = totalCount,
            Items = ObjectMapper.Map<List<IotCombinedData>, List<IotCombinedDataDto>>(items)
        };
    }
}


[IntegrationService]
public interface IIotIntegrationApiService : IApplicationService
{
    Task<PagedResultDto<IotCombinedDataDto>> GetListAsync(GetIotCombinedDatasInput input);
}

`


5 Answer(s)
  • User Avatar
    0
    AI-Bot created
    Support Team ABP Agent
    • When you access an ABP Integration Service endpoint from another backend service, the request must include a valid authentication token with the required permissions. If the endpoint is protected by [Authorize] or a permission attribute, and the calling service does not forward the user's access token or does not use a valid service-to-service token with the necessary claims, you will get a 401 Unauthorized error.

    • Integration Services are not exposed by default and typically do not require authorization, but if you add [Authorize] or permission attributes, you must ensure the caller is authenticated and authorized. When you call the endpoint directly (e.g., via Postman), you provide a valid token, so it works. When called from another backend service, unless you explicitly forward the user's token or use a client credentials flow, the call is unauthenticated.

    Solution:

    1. Forward the User's Access Token:

      • When backend service A calls the integration service, ensure it forwards the current user's access token in the Authorization header. This way, the integration service can perform authorization checks based on the user's permissions.
      • In ABP, you can use the IAccessTokenProvider or similar mechanism to retrieve and forward the token.
    2. Use Client Credentials (Service-to-Service):

      • If the call is not on behalf of a user, configure IdentityServer to allow client credentials for service A, and assign the required permissions to the client. The integration service will then authorize based on the client identity.
    3. Check Integration Service Exposure:

      • Make sure you have set AbpAspNetCoreMvcOptions.ExposeIntegrationServices = true in your module configuration to expose integration services.
    4. Security Note:

      • If you remove [Authorize], the endpoint is open to anyone, which is a security risk. Always require authentication and proper permissions.

    Example: Forwarding the Token

    // In backend service A, when calling the integration service:
    var client = _httpClientFactory.CreateClient("IntegrationService");
    client.DefaultRequestHeaders.Authorization = 
        new AuthenticationHeaderValue("Bearer", userAccessToken); // Forward user's token
    

    References:


    This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.

  • User Avatar
    0
    tapmui created

    [AI-Bot] said:

    • When you access an ABP Integration Service endpoint from another backend service, the request must include a valid authentication token with the required permissions. If the endpoint is protected by [Authorize] or a permission attribute, and the calling service does not forward the user's access token or does not use a valid service-to-service token with the necessary claims, you will get a 401 Unauthorized error.

    • Integration Services are not exposed by default and typically do not require authorization, but if you add [Authorize] or permission attributes, you must ensure the caller is authenticated and authorized. When you call the endpoint directly (e.g., via Postman), you provide a valid token, so it works. When called from another backend service, unless you explicitly forward the user's token or use a client credentials flow, the call is unauthenticated.

    Solution:

    1. Forward the User's Access Token:

      • When backend service A calls the integration service, ensure it forwards the current user's access token in the Authorization header. This way, the integration service can perform authorization checks based on the user's permissions.
      • In ABP, you can use the IAccessTokenProvider or similar mechanism to retrieve and forward the token.
    2. Use Client Credentials (Service-to-Service):

      • If the call is not on behalf of a user, configure IdentityServer to allow client credentials for service A, and assign the required permissions to the client. The integration service will then authorize based on the client identity.
    3. Check Integration Service Exposure:

      • Make sure you have set AbpAspNetCoreMvcOptions.ExposeIntegrationServices = true in your module configuration to expose integration services.
    4. Security Note:

      • If you remove [Authorize], the endpoint is open to anyone, which is a security risk. Always require authentication and proper permissions.

    Example: Forwarding the Token

    // In backend service A, when calling the integration service: 
    var client = _httpClientFactory.CreateClient("IntegrationService"); 
    client.DefaultRequestHeaders.Authorization =  
        new AuthenticationHeaderValue("Bearer", userAccessToken); // Forward user's token 
    

    References:


    This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.

    Thanks for the fast initial response. Comments to it below. to point 1;2; Based on this document I understood that abp.io is doing the addtion of access token automatically: https://abp.io/docs/latest/framework/api-development/dynamic-csharp-clients --> Authenticates the HTTP Client by adding access token to the HTTP header. to point 3; yes already done. -I have also tried to use the dynamic http API directly without integrationservice model; same result (unauthorized). **To point 4: **that is clear as I already said. I'm a bit worried that this is not highlighed in the abp.io documentation clearly.

    Example usage of integration/dynamic proxy:

    `

            GetIotCombinedDatasInput combinedDatasInput = new GetIotCombinedDatasInput
            {
                MaxResultCount = 10,
                SkipCount = 0,
                // DeviceTime < 2025-09-29 12:51:35.394
                DeviceTimeMax = DateTime.Parse("2025-09-29T12:51:35.394", null, DateTimeStyles.AdjustToUniversal)
            };
            try
            {
                var ressu = await _iotCombinedDatasAppService.GetListAsync(combinedDatasInput);
            } catch(Exception e)
            {
                _logger.LogWarning("not working...", e.Message);
                throw;
            }
    

    `

  • User Avatar
    0
    berkansasmaz created
    Support Team .NET Developer

    Hi Tapmui,

    You don’t need to apply authorization to Integration Services, because these endpoints are not exposed externally. If a user request is already validated by [Authorize] in your Application Service or Controller, there’s no need to check authorization again for internal calls. Integration Services are only used internally between modules or services, and users cannot directly send requests to these endpoints if it's not intentionally exposed to the outside in your deployment configuration.

    See more:

    • https://github.com/abpframework/abp/issues/12470
    • https://abp.io/docs/latest/framework/api-development/integration-services#exposing-integration-services
  • User Avatar
    0
    tapmui created

    [berkansasmaz] said: Hi Tapmui,

    You don’t need to apply authorization to Integration Services, because these endpoints are not exposed externally. If a user request is already validated by [Authorize] in your Application Service or Controller, there’s no need to check authorization again for internal calls. Integration Services are only used internally between modules or services, and users cannot directly send requests to these endpoints if it's not intentionally exposed to the outside in your deployment configuration.

    See more:

    • https://github.com/abpframework/abp/issues/12470
    • https://abp.io/docs/latest/framework/api-development/integration-services#exposing-integration-services

    Hi BerkansasMaz, thank you for the response. I have to expose the API, due we have modular monolith implementation (or even kind of microservice though not following microservice patterns but logical modules)

    • main backend running in own azure appservice
    • iot processing running in own azure appservice Now special processing is needed between them to be done in controlled order. Thus Azure service bus is not valid for this case. Due modules are in separate app services, the expose is needed. As per documentation I think I need to expose this integration API and then to protect in the gateway.

    Related issue: I also tried to use the dynamic proxy directly via the client API that already exists there. (I would not need to use integration service at all). But I had the same issue with authorization (401). Can you please advice on this. As per my understanding (from documentation) dynamic or static proxy client should use automatically existing token during the call ?

    Best regards Tapio

  • User Avatar
    0
    tapmui created

    I got this solved with this document and some guesses: https://abp.io/docs/latest/guides/synchronous-interservice-communication Point 1: set UseCurrentAccessToken to false

    appsettings: "RemoteServices": { "Iot": { "BaseUrl": "https://localhost:44351/", "UseCurrentAccessToken": "false" --> I was missing this. } }, Point 2: define client "IdentityClients": { "Default": { "GrantType": "client_credentials", "ClientId": "IotIntegration", "ClientSecret": "IotIntegration__something", "Authority": "https://localhost:44321", "Scope": "IotCombinedIntegrationAppService" } },

    Point 3: Create client and scope for the openIdDict also with proper resource (missing from instructions) that shall used. --> I was missing this.

    Point 4: when querying token the scope "IotCombinedIntegrationAppService" needs to be included

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 21, 2025, 11:36