I have a .NET 6 web API project that calls Graph as the app (rather than on behalf of the user).
I'm using the Microsoft.Identity.Web package, and my Program.cs has this code to initialise it:
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"))
.EnableTokenAcquisitionToCallDownstreamApi()
.AddMicrosoftGraphAppOnly(auth => new Microsoft.Graph.GraphServiceClient(auth))
.AddInMemoryTokenCaches();
I've given the Azure AD App Registration the necessary Graph app permissions (User.Read.All in this example) and granted admin consent.
When I'm debugging locally, I've set a ClientSecret in my User Secrets and the following call works a treat:
var photo = await _graph.Users[id].Photo.Content.Request().GetAsync();
However, when I'm deployed to an Azure App Service, I don't want to use a ClientSecret. I want to use the System-Assigned Managed Identity of my App Service.
Microsoft.Identity.Web apparently supports a UserAssignedManagedIdentityClientId
option, so I have set an environment variable to the ClientID of my App Service:
... and that does seem to be getting picked up by the code.
However, when I try to execute the graph call, I get an error. The stack trace looks like this (sensitive info redacted):
An unhandled exception has occurred while executing the request.
Exception:
Status Code: 0
Microsoft.Graph.ServiceException: Code: generalException
Message: An error occurred sending the request.
---> MSAL.NetCore.4.42.0.0.MsalServiceException:
ErrorCode: invalid_request
Microsoft.Identity.Client.MsalServiceException: AADSTS70021: No matching federated identity record found for presented assertion. Assertion Issuer: 'https://login.microsoftonline.com/{tenant}/v2.0'. Assertion Subject: '{msi-objectid}'. Assertion Audience: 'fb60f99c-7a34-4190-8149-302f77469936'. https://learn.microsoft.com/en-us/azure/active-directory/develop/workload-identity-federation
Trace ID: 7862bb35-0bdd-40c9-9c7b-cb12a8a0f200
Correlation ID: 97f749c8-f91d-434e-9ecd-111c65037399
Timestamp: 2022-03-23 05:11:08Z
at Microsoft.Identity.Client.Internal.Requests.RequestBase.HandleTokenRefreshErrorAsync(MsalServiceException e, MsalAccessTokenCacheItem cachedAccessTokenItem)
at Microsoft.Identity.Client.Internal.Requests.ClientCredentialRequest.ExecuteAsync(CancellationToken cancellationToken)
at Microsoft.Identity.Client.Internal.Requests.RequestBase.RunAsync(CancellationToken cancellationToken)
at Microsoft.Identity.Client.ApiConfig.Executors.ConfidentialClientExecutor.ExecuteAsync(AcquireTokenCommonParameters commonParameters, AcquireTokenForClientParameters clientParameters, CancellationToken cancellationToken)
at Microsoft.Identity.Web.TokenAcquisitionAuthenticationProvider.AuthenticateRequestAsync(HttpRequestMessage request)
at Microsoft.Graph.AuthenticationHandler.SendAsync(HttpRequestMessage httpRequestMessage, CancellationToken cancellationToken)
at System.Net.Http.HttpClient.<SendAsync>g__Core|83_0(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationTokenSource cts, Boolean disposeCts, CancellationTokenSource pendingRequestsCts, CancellationToken originalCancellationToken)
at Microsoft.Graph.HttpProvider.SendRequestAsync(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationToken cancellationToken)
StatusCode: 400
ResponseBody: {"error":"invalid_request","error_description":"AADSTS70021: No matching federated identity record found for presented assertion. Assertion Issuer: 'https://login.microsoftonline.com/{tenant}/v2.0'. Assertion Subject: '{msi-objectid}'. Assertion Audience: 'fb60f99c-7a34-4190-8149-302f77469936'. https://learn.microsoft.com/en-us/azure/active-directory/develop/workload-identity-federation\r\nTrace ID: 7862bb35-0bdd-40c9-9c7b-cb12a8a0f200\r\nCorrelation ID: 97f749c8-f91d-434e-9ecd-111c65037399\r\nTimestamp: 2022-03-23 05:11:08Z","error_codes":[70021],"timestamp":"2022-03-23 05:11:08Z","trace_id":"7862bb35-0bdd-40c9-9c7b-cb12a8a0f200","correlation_id":"97f749c8-f91d-434e-9ecd-111c65037399","error_uri":"https://login.microsoftonline.com/error?code=70021"}
Headers: Cache-Control: no-store, no-cache
The interesting thing here is that the "Assertion Subject" in the stack trace erorr is the ObjectID of my managed identity, not the ClientID. So it seems like it has found the App Service correctly but hitting a wall.
Has anyone been able to pull this off? Can I call Graph using the system managed identity of my app service?