My project is based on this on-behalf-of-flow example.
In my web api I have a non-restricted by [Authorize] method which receives login and password. I also have a restricted method which gets some info from MS Graph API:
[HttpGet]
[Authorize]
[Route("[action]")]
public async Task<IActionResult> Info()
{
string realAccessToken = await _tokenAcquisition.GetAccessTokenOnBehalfOfUser(HttpContext, scopes).ConfigureAwait(false);
var userInfoJson = await AzureGraphDataProvider.GetCurrentUserAsync(realAccessToken).ConfigureAwait(false);
...
}
In the non-restricted method I do a post request to Azure and get back information with Access token. Then I try to call directly Graph Api method using this token, but get Unauthorize.
Since on-behalf-of-flow takes User from HttpContext, I get the error above only when I access non-restricted by [authorize] method and call Graph API directly from it using the obtained token.
Current work around is to call a restricted web api method with the obtained token, which then calls MS Graph API, as I guess it initializes HttpContext and on-behalf-of-flow works.
Any better idea, please?
[HttpPost]
[Route("[action]")]
public async Task<IActionResult> GetAzureOAuthData([FromBody]dynamic parameters)
{
string userName = parameters.userName.ToString();
string password = parameters.password.ToString();
using (HttpClient client = new HttpClient())
{
var oauthEndpoint = new Uri("https://login.microsoftonline.com/organizations/oauth2/v2.0/token");
var result = await client.PostAsync(oauthEndpoint, new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("client_id", _azureOptions.ClientId),
new KeyValuePair<string, string>("grant_type", "password"),
new KeyValuePair<string, string>("username", userName),
new KeyValuePair<string, string>("password", password),
new KeyValuePair<string, string>("client_secret", _azureOptions.ClientSecret),
new KeyValuePair<string, string>("client_info", "1"),
new KeyValuePair<string, string>("scope",
"openid offline_access profile api://xxxxxxxxxx-xxxxxxxx-xxxxxxxxx/access_as_user api://xxxxxxxxxx-xxxxxxxx-xxxxxxxxx/access_as_admin"),
})).ConfigureAwait(false);
var content = await result.Content.ReadAsStringAsync().ConfigureAwait(false);
var oar = JsonConvert.DeserializeObject<AzureOAuthResult>(content);
string[] scopes = { "user.read" };
// doesn't work, unauthorized
var currentUserContent = await AzureGraphDataProvider.GetCurrentUserAsync(oar.AccessToken).ConfigureAwait(false);
// It works, but have to call web api method
using (HttpClient client2 = new HttpClient())
{
client2.DefaultRequestHeaders.Add("Authorization", $"Bearer {oar.AccessToken}");
var currentUserResult = await client2.GetAsync($"{Request.Scheme}://{Request.Host}/api/users/userinfo");
var currentUserContent = await currentUserResult.Content.ReadAsStringAsync().ConfigureAwait(false);
}
return Ok(...);
}
}
In AzureGraphDataProvider:
public static async Task<string> GetCurrentUserAsync(string accessToken)
{
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
HttpResponseMessage response = await client.GetAsync(new Uri("https://graph.microsoft.com/v1.0/me")).ConfigureAwait(false);
if (response.StatusCode == HttpStatusCode.OK)
{
return await response.Content.ReadAsStringAsync().ConfigureAwait(false);
}
return string.Empty;
}