sion005
sion005

Reputation: 51

Unable to get access to onedrive content

I'm developing an application where I need to use Microsoft Graph to access the files on a OneDrive for Business. I created a web app on Azure and I manage to get the authentication token and I'm able to retrieve the user information with https://graph.microsoft.com/v1.0/me. However, if I try to get the content of the OneDrive with https://graph.microsoft.com/v1.0/me/drive/root/children I get an access denied error.

I already checked on Graph Explorer and I'm able to get the result for the query without any issues. For my web app, I'm using the following Graph permissions:

public async Task<string> GetTokenAsync()
{
    HttpResponseMessage resp;
    using(var httpClient = new HttpClient())
    {
        httpClient.DefaultRequestHeaders.Accept
            .Add(new MediaTypeWithQualityHeaderValue("application/x-www-form-urlencoded"));

        var req = new HttpRequestMessage(HttpMethod.Post,
            $"https://login.microsoftonline.com/{tenant}/oauth2/token/");

        req.Content = new FormUrlEncodedContent(new Dictionary<string, string>
        { { "grant_type", "password" },
            { "client_id", clientId },
            { "client_secret", clientSecret },
            { "resource", "https://graph.microsoft.com" },
            { "username", username },
            { "password", password },
            { "scope", "https%3A%2F%2Fgraph.microsoft.com%2F.default" }
        });

        resp = await httpClient.SendAsync(req);
        string content = await resp.Content.ReadAsStringAsync();
        var jsonObj = new JavaScriptSerializer().Deserialize<dynamic>(content);
        string token = jsonObj["access_token"];
        Console.WriteLine(token);
        return token;
    }
}

public async Task<string> SendGraphRequest(string requestUrl)
{
    using(HttpClient httpClient = new HttpClient())
    {
        // Set up the HTTP GET request
        HttpRequestMessage apiRequest =
            new HttpRequestMessage(HttpMethod.Get, requestUrl);
        apiRequest.Headers.UserAgent
            .Add(new ProductInfoHeaderValue("OAuthStarter", "2.0"));
        apiRequest.Headers.Authorization =
            new AuthenticationHeaderValue("Bearer", await GetTokenAsync());

        // Send the request and return the response
        HttpResponseMessage response = await httpClient.SendAsync(apiRequest);
        var s = response.Content.ReadAsStringAsync();
        Console.WriteLine(s.Result);
        return s.Result;
    }
}

My call for the graph api is:

SendGraphRequest("https://graph.microsoft.com/v1.0/me/drive").Wait();

The result I get from this is:

{
  "error": {
    "code": "accessDenied",
    "message": "There has been an error authenticating the request.",
    "innerError": {
      "request-id": "request-id",
      "date": "2019-09-24T11:03:29"
    }
  }
}

Upvotes: 4

Views: 2252

Answers (2)

sion005
sion005

Reputation: 51

After almost two week trying to fix this issue I realised that the problem was not the code, but the azure configuration. I was under the assumption that if a web app is installed on the account of the administrator of the active directory, that all users on that active directory would be capable of using the same web app to access their respective One Drive accounts. Unfortunately this is not the case, if a user (not the administrator) tries to use the web app to access One Drive, the only thing he or she will be capable of reaching is their account information, with no access to files. In order to use the graph api to access the files, the web app needs to be installed on their respective active directories.

Upvotes: 1

Marc LaFleur
Marc LaFleur

Reputation: 33132

You're way over-provisioning your scopes here. You don't need both Read and ReadWrite scopes for example. You're also requesting some Application scopes but using the OAuth Password grant which will only work with Delegated scopes (you can't mix the two).

I would recommend pairing down your scopes to the following Delegated permissions:

openid User.ReadWrite User.ReadBasic.All Files.ReadWrite.All
People.Read Sites.ReadWrite.All Tasks.ReadWrite offline_access

Note that Sites.ReadWrite.All is a bit different than Files.ReadWrite.All. One concerns SharePoint, the other OneDrive.

Upvotes: 2

Related Questions