0

I'm working in an Unity app that needs to connect to a Microsoft Dynamics 365 which uses OAuth2.0. I was trying using UnityWebRequest to retrieve an access token by calling:

https://login.microsoftonline.com/[TENANT_ID]/oauth2/v2.0/token

using something similar to this thread:

OAuth2 Authentication and Operations in Unity

And it works, I'm able to get and access_token, however, when I try to consume the service with the Bearer token, I always get "401 unauthorized".

I then tried to call instead:

https://login.microsoftonline.com/[TENANT_ID]/oauth2/v2.0/authorize

But when I do that, the response is the actual HTML code of the Microsoft login screen. As far I know, getting an auth code requires a user interaction right? but I've been able to get this done by using Microsoft.IdentityModel.Clients.ActiveDirectory package from NuGet in a console C# app without user interaction, so there must be a way right?

I would really appreciate your help on this! thank you!

UPDATE 1 - My code

Get access token

private IEnumerator GetAccessToken(Action<string> result)
{
    Dictionary<string, string> content = new Dictionary<string, string>();
    //Fill key and value
    content.Add("scope", "https://graph.microsoft.com/.default");
    content.Add("grant_type", "client_credentials");
    content.Add("client_id", "xxxxx");
    content.Add("client_secret", "xxxx");

    UnityWebRequest www = UnityWebRequest.Post("https://login.microsoftonline.com/[TENANTID]/oauth2/v2.0/token", content);
    //Send request
    yield return www.Send();

    if (!www.isError)
    {
        string resultContent = www.downloadHandler.text;
        TokenClassName json = JsonUtility.FromJson<TokenClassName>(resultContent);

        //Return result
        result(json.access_token);
    }
    else
    {
        //Return null
        result("");
    }
}

Call API

private IEnumerator GetData(Action<string> result)
{
    Dictionary<string, string> content = new Dictionary<string, string>();
    //Fill key and value
    content.Add("CustomerGroupId", "10");

    UnityWebRequest www = UnityWebRequest.Post("https://[ENVIRONMENT].cloudax.dynamics.com/data/TestEntity", content);

    string token = null;

    yield return GetAccessToken((tokenResult) => { token = tokenResult; });

    result(token);

    www.SetRequestHeader("Authorization", "Bearer " + token);
    www.Send();

    if (!www.isError)
    {
        string resultContent = www.downloadHandler.text;
        // Perform additional operations...
    }
}
saman0suke
  • 762
  • 1
  • 8
  • 24
  • Before making the HTTP call to your authenticated endpoint, can you check that you definitely have the Bearer token in the Headers? – Dave C Feb 19 '19 at 13:32
  • Which API are you calling and are you sure the resource identifier / scope is correct in your request to /token? – juunas Feb 19 '19 at 13:36
  • Please show your code. – shingo Feb 19 '19 at 13:48
  • @juunas I updated the thread with my code. I am not sure if I understand what you mean by "identifier", would that be the client_id? the scope that I'm using is https://graph.microsoft.com/.default, should I specify it somewhere else in the ERP side? thanks. – saman0suke Feb 19 '19 at 14:01
  • @DaveC I set it by calling SetRequestHeader() but during debugging, where do I see that value in UnityWebRequest object? FYI, I also tested the access_token in Postman, but it did not work either, so I'm think that I really need to get an authorization token first, and then get the access token. Any idea is welcome, thanks! – saman0suke Feb 19 '19 at 14:12
  • @shingo Code added, thanks! – saman0suke Feb 19 '19 at 14:22
  • did you make sure there is no `www.error` in the first request and you are getting an empty string? and what does `result(token);` do? – derHugo Feb 19 '19 at 19:21
  • I don't know anything about oauth and `Bearer` but with `Basic` I had to use base64 encoding like `"Basic " + Convert.ToBase64String(Encoding.GetEncoding("ISO-8859-1").GetBytes($"{username}:{password}"))` to get it to work .. maybe you have to do the same for the token? – derHugo Feb 19 '19 at 19:27
  • @derHugo the www shows "401 unauthorized". I think I need to use Bearer for OAuth2.0. – saman0suke Feb 19 '19 at 20:32
  • yes you have to ... what I ment is maybe you have to use it like `"Bearer " + Convert.ToBase64String(Encoding.GetEncoding("ISO-8859-1").GetBytes(token)` – derHugo Feb 19 '19 at 20:33
  • @derHugo Same result. 401 unauthorized. – saman0suke Feb 20 '19 at 02:08
  • Do not encode tokens. The problem is the scope you are using means the token will be for MS Graph API, not Dynamics. – juunas Feb 20 '19 at 06:09

1 Answers1

0

The resource is different for the token and the API call. In the token request, the resource is https://graph.microsoft.com, it's not your destination API. You should request the token for your destination API.

SunnySun
  • 1,900
  • 1
  • 6
  • 8
  • Could you please elaborate on that? do you mean that i should not use graph.microsoft as the scope? if so, what should I add instead? Thanks for the help! – saman0suke Feb 20 '19 at 03:05
  • The scope should be app ID URI of the API you want, affixed with the `.default` suffix. For the Microsoft Graph example, the value is `https://graph.microsoft.com/.default`. – SunnySun Feb 20 '19 at 05:31