AzureAD / microsoft-identity-web

Helps creating protected web apps and web APIs with Microsoft identity platform and Azure AD B2C
MIT License
681 stars 210 forks source link

Issue Generating token after registering hosted service #2843

Open medbalighhamdi opened 5 months ago

medbalighhamdi commented 5 months ago

Microsoft.Identity.Web Library

Microsoft.Identity.Web.DownstreamApi

Microsoft.Identity.Web version

2.18.1

Web app

Sign-in users

Web API

Protected web APIs (validating tokens)

Token cache serialization

In-memory caches

Description

Observed Issue

I am getting the following error, only when adding a hosted service on applcation startup:

Cannot use WithTenantId(tenantId) in the application builder, because the authority Generic doesn't support it.

I precise that the error is not reproduced when I remove my hosted service that I register with classic aspnet core AddHostedService<> method.

Reproduction steps

  1. I add a hosted service that calls to an external service using CallApiForAppAsync method.
 .AddMicrosoftIdentityWebApiAuthentication(
           configuration,
           DownstreamApiTokens.AzureAdToken.ConfigValue)
 .EnableTokenAcquisitionToCallDownstreamApi()
 .AddMicrosoftGraph(graphApiSection)
 .AddDownstreamApi(downstreamService1Name,
       downstreamService1Configuration)
 .AddDownstreamApi(downstreamService2Name,
       downstreamService2Configuration)
 .AddInMemoryTokenCaches()

services.AddHostedService<ReplicasInitalizationHostedService>();

Please note that the hosted service calls the downstream service 1 declared in the above authentication configuration.

Azure Ad Configuration on appsettings.json level:

"AzureAd": {
  "Instance": "https://login.microsoftonline.com/",
  "TenantId": "XXXXXX-XXX-XXXX-XXXX-XXXXXXX",
  "ClientId": "XXXXX-XXXX-XXXX-XXX-XXXXXXXXX",
  "Scopes": "openid email profile app.read offline_access access_as_user",
  "ClientSecret": "XXXXX"
}

Service config section:

 "DownstreamService2": {
   "BaseUrl": "https://serice2url/api/v1",
   "RequestAppToken": true,
   "Scopes": [ "api://XXXX-XX-XX-X-XXXXX/.default" ]
 },
"DownstreamService1": {
  "BaseUrl": "https://service1url/api/v1/data",
  "RequestAppToken": true,
  "Scopes": [ "api://XXXX-XX-XXXX-XX-XXXX/.default" ]
},

Please note that I am not using a cross organization instance in my Azure Ad configuration.

  1. I run my API, this calls the hosted service which executes successfully. For calling the external service, I use IDownstreamApi interface like the following:
 var httpResult = await DownstreamApi.CallApiForAppAsync(
    ServiceName,
    !string.IsNullOrEmpty(computedRelativeUri) ?
        options =>
        {
            options.RelativePath = $"{computedRelativeUri}";
        }
: null,
    null,
    cancellationToken).ConfigureAwait(false);

httpResult.EnsureSuccessStatusCode();

var proxyResult = await httpResult.Content.ReadFromJsonAsync<T>
   (JsonSerializationStrategies.PermessiveJsonTextStrategy, cancellationToken);
return (proxyResult, httpResult.StatusCode);

The hosted service executes successfully without erros.

  1. When I try to downstreamService 2, I have the following error:

Cannot use WithTenantId(tenantId) in the application builder, because the authority Generic doesn't support it.

I am using the same code for calling downstream service 2 as for service 1.

Error message

Cannot use WithTenantId(tenantId) in the application builder, because the authority Generic doesn't support it.

Please notre that I only get this error message when I run the hosted service.

Id Web logs

An error occurred: Cannot use WithTenantId(tenantId) in the application builder, because the authority Generic doesn't support it. MSAL.NetCore.4.60.3.0.MsalClientException: ErrorCode: tenant_override_non_aad Microsoft.Identity.Client.MsalClientException: Cannot use WithTenantId(tenantId) in the application builder, because the authority Generic doesn't support it. at Microsoft.Identity.Client.BaseAbstractApplicationBuilder1.ResolveAuthority() at Microsoft.Identity.Client.AbstractApplicationBuilder1.BuildConfiguration() at Microsoft.Identity.Client.ConfidentialClientApplicationBuilder.BuildConcrete() at Microsoft.Identity.Client.ConfidentialClientApplicationBuilder.Build() at Microsoft.Identity.Web.TokenAcquisition.BuildConfidentialClientApplicationAsync(MergedOptions mergedOptions) at Microsoft.Identity.Web.TokenAcquisition.GetOrBuildConfidentialClientApplicationAsync(MergedOptions mergedOptions) at Microsoft.Identity.Web.TokenAcquisition.GetAuthenticationResultForAppAsync(String scope, String authenticationScheme, String tenant, TokenAcquisitionOptions tokenAcquisitionOptions) at Microsoft.Identity.Web.DefaultAuthorizationHeaderProvider.CreateAuthorizationHeaderForAppAsync(String scopes, AuthorizationHeaderProviderOptions downstreamApiOptions, CancellationToken cancellationToken) at Microsoft.Identity.Web.DownstreamApi.UpdateRequestAsync(HttpRequestMessage httpRequestMessage, HttpContent content, DownstreamApiOptions effectiveOptions, Boolean appToken, ClaimsPrincipal user, CancellationToken cancellationToken) at Microsoft.Identity.Web.DownstreamApi.CallApiInternalAsync(String serviceName, DownstreamApiOptions effectiveOptions, Boolean appToken, HttpContent content, ClaimsPrincipal user, CancellationToken cancellationToken) at....

Relevant code snippets

var httpResult = await DownstreamApi.CallApiForAppAsync(
    ServiceName,
    !string.IsNullOrEmpty(computedRelativeUri) ?
        options =>
        {
            options.RelativePath = $"{computedRelativeUri}";
        }
: null,
    null,
    cancellationToken).ConfigureAwait(false);

httpResult.EnsureSuccessStatusCode();

var proxyResult = await httpResult.Content.ReadFromJsonAsync<T>
   (JsonSerializationStrategies.PermessiveJsonTextStrategy, cancellationToken);
return (proxyResult, httpResult.StatusCode);

Regression

No response

Expected behavior

I expect the token to be acquired succesfully for the configured downstream service 2

jennyf19 commented 2 months ago

@medbalighhamdi do you see this with 3.0.1+ as well?