Why is my Web API with Application Permissions to Bookings.ReadWrite.All unauthorized when querying Graph API Bookings endpoints
We are building an API to get and update Booking Appointments using Microsoft Graph API and application permissions.
We have registered an app in Azure, added the Bookings.ReadWrite.All application permission and admin consent has been granted.
When we query the endpoint with application permissions we receive an Unauthorized error, but if we query using delegated permissions, as a user who is a member of the Bookings Calendar, it's fine.
var result = await _graphServiceClient.Solutions.BookingBusinesses[_BookingCalendarId].Appointments[appointmentId].GetAsync();
We have queried Appointments, StaffMembers and Services all with the same result.
We're constructing our Graph Service Client this way:
public AppGraphService(IConfiguration config)
{
_config = config ?? throw new ArgumentNullException(nameof(config));
_client = new Lazy<GraphServiceClient>(() =>
{
var credential = new ClientSecretCredential(
config["AzureAd:TenantId"],
config["AzureAd:ClientId"],
config["AzureAd:ClientSecret"]);
return new GraphServiceClient(credential, new[] { "https://graph.microsoft.com/.default" });
});
}
We inspected the Token for the Graph Client to ensure it had the expected scopes
{
"typ": "JWT",
"nonce": "[REDACTED_NONCE]",
"alg": "RS256",
"x5t": "[REDACTED_X5T]",
"kid": "[REDACTED_KID]"
}.
{
"aud": "https://graph.microsoft.com",
"iss": "https://sts.windows.net/[TENANT_ID]/",
"iat": 1749575758,
"nbf": 1749575758,
"exp": 1749579658,
"aio": "[REDACTED_AIO]",
"app_displayname": "[APP_DISPLAY_NAME]",
"appid": "[APP_ID]",
"appidacr": "1",
"idp": "https://sts.windows.net/[TENANT_ID]/",
"idtyp": "app",
"oid": "[OBJECT_ID]",
"rh": "[REDACTED_RH]",
"roles": [
"Bookings.ReadWrite.All",
"OnlineMeetings.ReadWrite.All"
],
"sub": "[OBJECT_ID]",
"tenant_region_scope": "NA",
"tid": "[TENANT_ID]",
"uti": "[REDACTED_UTI]",
"ver": "1.0",
"wids": [
"[REDACTED_WID]"
],
"xms_ftd": "[REDACTED_XMS_FTD]",
"xms_idrel": "[REDACTED_XMS_IDREL]",
"xms_rd": "[REDACTED_XMS_RD]",
"xms_tcdt": 1523990055
}.
[Signature]
We retrieved the request URI and tried it in Graph Explorer and that worked fine
var uriinfo = _graphServiceClient.Solutions.BookingBusinesses[_BookingCalendarId].Appointments[appointmentId].ToGetRequestInformation();
return uriinfo.URI.AbsoluteUri;
Retrieving a token via Thunder Client returns a token with the correct roles, but when we use that token immediately following the request fails with a 500 error.
The same request with a User token is always successful.
// Sample from https://learn.microsoft.com/en-us/graph/auth-v2-service?tabs=http#token-request used to get an App token
POST https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token HTTP/1.1
Host: login.microsoftonline.com
Content-Type: application/x-www-form-urlencoded
client_id=535fb089-9ff3-47b6-9bfb-4f1264799865
&scope=https%3A%2F%2Fgraph.microsoft.com%2F.default
&client_secret=qWgdYA....L1qKv5bPX
&grant_type=client_credentials
According to the Devblog post from 2022-06
"In this release, we are providing application permissions for a limited set of Bookings APIs. This includes application permissions support for read and write APIs for the ‘bookingCustomer ‘and ‘bookingAppointment’ entities. For other entities, including ‘bookingBusiness’, ‘bookingStaffMember’, ‘bookingCustomQuestion’ and ‘bookingService’, we are supporting the read APIs only. Because these tasks are for Bookings admins, delegated permissions are recommended for these use cases."
We should be able to work with the API using Application Permissions. Yes, it specifies beta
and we have used both v1.0 and beta for our queries with the same result.
Why isn't the app able to query the Bookings endpoint at all? What else should we try in order to resolve this? Is there another permission, similar to an Application Access Policy in Exchange?