Search code examples
phpazuremicrosoft-graph-apionedriveguzzle

Why does Microsoft Graph API deny my request to upload files to OneDrive from a PHP website?


I have a website where my clients can view their invoices and upload design assets related to the invoice. I want to create a PHP form which uploads the files to OneDrive, instead of storing them on our web server.

I have followed the instructions in this StackOverflow answer to get started.

I have created the app in Microsoft Azure, and entered the appropriate Application (client) ID, Object ID, and Directory (tenant) ID. I am using a client secret to authorize the application, and submitting a POST request using my account's email and password to get the access token.

The relevant code for my upload form looks like this:

if (isset($_FILES['uploads'])) {
    $guzzle = new \GuzzleHttp\Client();
    $tenantId = 'xxxxxx';
    $clientId = 'xxxxxx';
    $clientSecret = 'xxxxxx';
    $url = 'https://login.microsoftonline.com/' . $tenantId . '/oauth2/token';
    $user_token = json_decode($guzzle->post($url, [
        'form_params' => [
            'client_id' => $clientId,
            'client_secret' => $clientSecret,
            'resource' => 'https://graph.microsoft.com/',
            'grant_type' => 'password',
            'username' => 'xxxxxx@companydomain.com', 
            'password' => 'xxxxxx'
        ],
    ])->getBody()->getContents());
    $user_accessToken = $user_token->access_token;

    $graph = new Graph();
    $graph->setAccessToken($user_accessToken);

    foreach ($_FILES['uploads']['name'] as $key => $name) {
        try {
            $graph->createRequest(
                "PUT", "/drive/root:/Documents/".$_FILES['uploads']['name'][$key].":/content"
            )->upload(
                $_FILES['uploads']['tmp_name'][$key]
            );
        } catch (Exception $e) {
            var_dump($e);
        }
    }
}

This code throws an exception, showing the following error message when I try to upload a :

Client error: `PUT https://graph.microsoft.com/v1.0/drive/root:/Documents/Screen%20Shot%202022-10-30%20at%204.03.44%20PM.png:/content` resulted in a `403 Forbidden` response

In the Azure API Permissions, I have granted the Files.Read.All, Files.ReadWrite.All, and User.Read permissions. However, when I check the access token in https://jwt.ms/, I just see "scp": "User.Read".

So it looks like my access token might not have the correct permissions, but I can see that I do have permissions to read and write files when I look at the API Permissions page in Azure.

How can I further debug this issue and find a solution to upload files from my server to OneDrive?


Solution

  • Thanks to Nikolay's comment, I added a scope parameter to form_params and that fixed it.

    I also changed the grant_type to client_credentials, and removed the username/password authorization.

        $user_token = json_decode($guzzle->post($url, [
            'form_params' => [
                'client_id' => $clientId,
                'client_secret' => $clientSecret,
                'resource' => 'https://graph.microsoft.com/',
                'grant_type' => 'client_credentials',
                'scope' => 'https://graph.microsoft.com/.default'
            ],
        ])->getBody()->getContents());
        $user_accessToken = $user_token->access_token;