microsoft-identity-web
microsoft-identity-web copied to clipboard
No way to use RequestOptionsExtension with Graph Bulk API (Microsoft.Identity.Web.GraphServiceClient)
Microsoft.Identity.Web Library
Microsoft.Identity.Web.GraphServiceClient
Microsoft.Identity.Web version
2.19.0
Web app
Not Applicable
Web API
Protected web APIs call downstream web APIs
Token cache serialization
Not Applicable
Description
BatchRequestBuilder
don't have a requestConfiguration
parameter and there is no way to specify the auth scheme and app only auth for batch requests, like
requestConfiguration.Options.WithAppOnly().WithAuthenticationScheme(JwtBearerDefaults.AuthenticationScheme);
public async Task<BatchResponseContent> PostAsync(BatchRequestContent batchRequestContent, CancellationToken cancellationToken = default, Dictionary<string, ParsableFactory<IParsable>> errorMappings = null)
{
_ = batchRequestContent ?? throw new ArgumentNullException(nameof(batchRequestContent));
var requestInfo = await ToPostRequestInformationAsync(batchRequestContent,cancellationToken);
var nativeResponseHandler = new NativeResponseHandler();
requestInfo.SetResponseHandler(nativeResponseHandler);
await this.RequestAdapter.SendNoContentAsync(requestInfo, cancellationToken:cancellationToken);
return new BatchResponseContent(nativeResponseHandler.Value as HttpResponseMessage, errorMappings);
}
Reproduction steps
var batchRequestContent = new BatchRequestContent(graphServiceClient);
var groupsRequestId = await batchRequestContent.AddBatchRequestStepAsync(groupsRequest);
var usersRequestId = await batchRequestContent.AddBatchRequestStepAsync(usersRequest);
var response = await graphServiceClient.Batch
.PostAsync(batchRequestContent, cancellationToken); // no way to specify options here
var groups = await response.GetResponseByIdAsync<GroupCollectionResponse>(groupsRequestId);
Error message
System.InvalidOperationException
IDW10503: Cannot determine the cloud Instance. The provided authentication scheme was ''. Microsoft.Identity.Web inferred 'JWT_OR_OIDC' as the authentication scheme. Available authentication schemes are 'JWT_OR_OIDC,Cookies,OpenIdConnect,Bearer'. See https://aka.ms/id-web/authSchemes.
at Microsoft.Identity.Web.TokenAcquisitionAspnetCoreHost.GetOptions(String authenticationScheme, String& effectiveAuthenticationScheme)
at Microsoft.Identity.Web.TokenAcquisition.GetAuthenticationResultForUserAsync(IEnumerable`1 scopes, String authenticationScheme, String tenantId, String userFlow, ClaimsPrincipal user, TokenAcquisitionOptions tokenAcquisitionOptions)
Id Web logs
No response
Relevant code snippets
The workaround is to implement custom PostAsync
that add GraphAuthenticationOptions
before the call, but this approach does not work with BatchRequestContentCollection
(ctor is internal), work only with BatchRequestContent
and require reverse engineering of 2 libs behavior
public static class GraphBatchApiExtensions
{
public static async Task<BatchResponseContent> SendBatchAsAppAsync(
this GraphServiceClient graphServiceClient,
BatchRequestContent batchRequestContent,
CancellationToken cancellationToken = default,
Dictionary<string, ParsableFactory<IParsable>>? errorMappings = null)
{
ArgumentNullException.ThrowIfNull(graphServiceClient);
ArgumentNullException.ThrowIfNull(batchRequestContent);
var requestInfo = await graphServiceClient.Batch.ToPostRequestInformationAsync(batchRequestContent,cancellationToken);
WithAppOnly(requestInfo);
var nativeResponseHandler = new NativeResponseHandler();
requestInfo.SetResponseHandler(nativeResponseHandler);
await graphServiceClient.RequestAdapter.SendNoContentAsync(requestInfo, cancellationToken:cancellationToken);
return new BatchResponseContent(nativeResponseHandler.Value as HttpResponseMessage, errorMappings);
}
private static void WithAppOnly(RequestInformation requestInformation)
{
var authOptions = requestInformation.RequestOptions.OfType<GraphAuthenticationOptions>().FirstOrDefault();
if (authOptions is null)
{
authOptions = new GraphAuthenticationOptions();
requestInformation.AddRequestOptions([authOptions]);
}
authOptions.RequestAppToken = true;
authOptions.AcquireTokenOptions ??= new ();
authOptions.AcquireTokenOptions.AuthenticationOptionsName =
JwtBearerDefaults.AuthenticationScheme;
}
}
Regression
No response
Expected behavior
API unification
var batchRequestContent = new BatchRequestContent(graphServiceClient);
var groupsRequestId = await batchRequestContent.AddBatchRequestStepAsync(groupsRequest);
var usersRequestId = await batchRequestContent.AddBatchRequestStepAsync(usersRequest);
var response = await graphServiceClient.Batch
.PostAsync(batchRequestContent, rc => {
rc.Options.WithAppOnly().WithAuthenticationScheme(JwtBearerDefaults.AuthenticationScheme);
}, cancellationToken); // new overload with requestConfiguration action
var groups = await response.GetResponseByIdAsync<GroupCollectionResponse>(groupsRequestId);