Failing to connect to Microsoft Bookings API

Copper Contributor

I am trying to pull Microsoft Booking calendar data into my WP site.

I have created the required web app and granted my user the required access and delegation to connect to the app, and gave my app access to ‘Microsoft Graph’ and selected ‘Manage bookings information’ and read and write.

I am using PHP, and below is my code: but I am always getting this error although I know for a fact that I am using the right credentials:
Error: HTTP request failed with code 403. Response: {"error":{"code":"ErrorAccessDenied","message":"Access is denied. Check credentials and try again."}}NULL

 

<?php
require 'vendor/autoload.php';
use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;

function bookings_init($calendar){
    $clientId = "MY_CLIENT_ID";
    $clientSecret = "MY_SECRET_ID";
    $tenantId = "MY_TENANT_ID";
    $username = "MY_USER_EMAIL";
    $password = "MY_PASSWORD";
    $accessToken = getAccessToken($clientId, $clientSecret, $tenantId, $username, $password);

    if ($accessToken) {
        $businessId = "BUSINESS_ID";
        $start = "2023-09-25T08:00:00Z";
        $end = "2023-10-25T17:00:00Z";

        $bookingsData = retrieveBookingsData($accessToken, $businessId, $start, $end);

        if ($bookingsData) {
            var_dump($bookingsData);
        }
    }
}

function getAccessToken($clientId, $clientSecret, $tenantId, $username, $password){
    $client = new GuzzleHttp\Client();
    $response = $client->post("https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token", [
        'form_params' => [
            'grant_type'    => 'password',
            'client_id'     => $clientId,
            'client_secret' => $clientSecret,
            'scope'         => 'https://graph.microsoft.com/.default',
            'username'      => $username,
            'password'      => $password
        ],
    ]);

    $body = $response->getBody();
    $data = json_decode($body, true);
    return $data['access_token'];
}

function retrieveBookingsData($accessToken, $businessId, $start, $end) {
    $bookingsEndpoint = "https://graph.microsoft.com/v1.0/me/calendar/getSchedule";
    $payload = [
        'Schedules' => [$businessId],
        'StartTime' => [
            'dateTime' => $start,
            'timeZone' => 'UTC'
        ],
        'EndTime' => [
            'dateTime' => $end,
            'timeZone' => 'UTC'
        ]
    ];

    $client = new GuzzleHttp\Client();
    try {
        $response = $client->request('POST', $bookingsEndpoint, [
            'headers' => [
                'Authorization' => "Bearer $accessToken",
                'Content-Type' => 'application/json'
            ],
            'json' => $payload
        ]);

        $body = $response->getBody();
        return $body->getContents();
    } catch (RequestException $e) {
        // Catch any Guzzle HTTP request exceptions
        echo "HTTP request failed with code {$e->getCode()}. Response: {$e->getResponse()->getBody()->getContents()}";
        return false;
    } catch (Exception $e) {
        // Catch any other exceptions
        echo "An error occurred: {$e->getMessage()}";
        return false;
    }
}

 

 I appreciate your help in guiding me through this.

 

Thanks.

1 Reply

First of all, I can recommend the PHP package microsoft/microsoft-graph for the usage of the Microsoft Graph API. It's easier than writing all the requests on yourself with Guzzle.

I'm confused that you are trying to use your username with password and a client secret at the same time. Client secrets have the advantage that you don't need to use (and therefore expose) your account password compared to a simple app token with strictly limited permissions. So you should try to get an access token with client ID, client secret, scope and grant type, for example like this:

 

 

$guzzle = new \GuzzleHttp\Client();
$url = 'https://login.microsoftonline.com/' . $tenantId . '/oauth2/v2.0/token';
$token = json_decode($guzzle->post($url, [
    'form_params' => [
        'client_id' => $clientId,
        'client_secret' => $clientSecret,
        'scope' => 'https://graph.microsoft.com/.default',
        'grant_type' => 'client_credentials',
    ],
])->getBody()->getContents());
$accessToken = $token->access_token;