Reputation: 1416
I am trying to get information about users from Microsoft Graph via
https://graph.microsoft.com/v1.0/users
.
It's returning a 401 - Unauthorized
:
{
"error": {
"code": "InvalidAuthenticationToken",
"message": "Access token validation failure. Invalid audience.",
"innerError": {
"request-id": "3157d513-6f31-4d2d-a3d7-a97eed7207ba",
"date": "2019-12-11T05:39:02"
}
}
}
My code:
AuthenticationContext authContext =
new AuthenticationContext(string.Format(CultureInfo.InvariantCulture,
"https://login.microsoftonline.com/{0}", "my-domain name"));
ClientCredential clientCred =
new ClientCredential("Client-id", "Client-Secret-id");
AuthenticationResult authenticationResult = authContext
.AcquireTokenAsync("https://graph.windows.net", clientCred).Result;
var token = authenticationResult.AccessToken;
var client = new HttpClient();
var uri = "https://graph.microsoft.com/v1.0/me/";
client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue(token);
var response = await client.GetAsync(uri);
Where I did go wrong? Why I am not getting a proper access token? Could anyone please help me to use the MS Graph?
Upvotes: 2
Views: 2598
Reputation: 33122
You have a few issues going on:
You should be requesting a token for https://graph.microsoft.com
, not https://graph.windows.net
. The graph.windows.net
is the older AAD Graph, not the newer Microsoft Graph:
AuthenticationResult authenticationResult = authContext
.AcquireTokenAsync("https://graph.windows.net", clientCred).Result;
You cannot use /me
with the Client Credentials grant. Graph translates /me
into /users/{currently authenticated user id}
. Since you're not authenticating a user, the "currently authenticated user id" is null
:
var uri = "https://graph.microsoft.com/v1.0/users/user@domain.onmicrosoft.com";
You are setting the Authorization header's value but not the scheme. You need to set both:
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", token);
It isn't clear from your question which scopes you've requested or if you've received Admin Consent. You need to make sure you've requested the Application scope User.Read.All
and received Admin Consent from a tenant administrator.
Upvotes: 0
Reputation: 21
Make sure the account you're using while making the Graph API calls has the Required Permissions. As you're invoking a GET call,
Below permissions should be set up.
More about permissions here: https://learn.microsoft.com/en-us/graph/permissions-reference
The Error posted clearly states that the account you're using to make calls to GRAPH API is unauthorized. Have the permissions set right and the access token will be generated and will be authenticated against your application.
EDIT: Try the below code to get a valid access token.
static string AppID = "<Your Application ID>";
static string APPKey = "<Your Application Key>";
static string tenantId = "<Your ORG Tenant ID>";
static string RedirectURI = "<Your Application's custom Redirect URI>";
static string GraphApi = "https://graph.microsoft.com/v1.0/"
public static IAuthenticationProvider CreateAuthorizationProvider()
{
var authority = $"https://login.microsoftonline.com/{tenantId}/v2.0";
List<string> scopes = new List<string>();
scopes.Add("https://graph.microsoft.com/.default");
var cca = ConfidentialClientApplicationBuilder.Create(AppID)
.WithAuthority(authority)
.WithRedirectUri(RedirectURI)
.WithClientSecret(APPKey)
.Build();
return new MsalAuthenticationProvider(cca, scopes.ToArray());
}
public static HttpClient GetAuthenticatedHTTPClient()
{
var authenticationProvider = CreateAuthorizationProvider();
_httpClient = new HttpClient(new AuthHandler(authenticationProvider, new HttpClientHandler()));
return _httpClient;
}
private static async Task<User> GetADUserInfo(HttpClient client,string email)
{
User user = new User();
client = GetAuthenticatedHTTPClient();
client.BaseAddress = new Uri(GraphApi);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
WriteToConsole("Call Graph API :: retrieving AD Info for the employee ::" + email);
using (client)
{
try
{
HttpResponseMessage res = await client.GetAsync("users/" + email);
res.EnsureSuccessStatusCode();
if (res.IsSuccessStatusCode)
{
user = await res.Content.ReadAsAsync<User>();
WriteToConsole("Call Graph API :: Call Success for employee ::" + email);
}
}
catch (Exception ex)
{
LogError(ex, "Error in Getting AD User info via Graph API");
return null;
}
return user;
}
}
The Above code uses MSALAuthentication, Use the code below :
public class MsalAuthenticationProvider : IAuthenticationProvider
{
private IConfidentialClientApplication _clientApplication;
private string[] _scopes;
public MsalAuthenticationProvider(IConfidentialClientApplication clientApplication, string[] scopes)
{
_clientApplication = clientApplication;
_scopes = scopes;
}
public async Task AuthenticateRequestAsync(HttpRequestMessage request)
{
var token = await GetTokenAsync();
request.Headers.Authorization = new AuthenticationHeaderValue("bearer", token);
}
public async Task<string> GetTokenAsync()
{
AuthenticationResult authResult = null;
authResult = await _clientApplication.AcquireTokenForClient(_scopes).ExecuteAsync();
return authResult.AccessToken;
}
}
AuthHandler Class :
public class AuthHandler : DelegatingHandler
{
private IAuthenticationProvider _authenticationProvider;
public AuthHandler(IAuthenticationProvider authenticationProvider, HttpMessageHandler innerHandler)
{
InnerHandler = innerHandler;
_authenticationProvider = authenticationProvider;
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
await _authenticationProvider.AuthenticateRequestAsync(request);
return await base.SendAsync(request, cancellationToken);
}
}
Upvotes: 1
Reputation: 42143
You use the wrong resource, you need to get the token for Microsoft Graph instead of AAD Graph,
it should be https://graph.microsoft.com
, not https://graph.windows.net
.
AuthenticationResult authenticationResult = authContext.AcquireTokenAsync("https://graph.microsoft.com",
clientCred).Result;
Update:
Make sure you grant the User.Read.All
Application permission.
Then try the code as below, it works on my side.
using System;
using System.Net.Http;
using Microsoft.IdentityModel.Clients.ActiveDirectory;
namespace ConsoleApp3
{
class Program
{
static void Main(string[] args)
{
string _authString = "https://login.microsoftonline.com/xxxxxx.onmicrosoft.com";
string _clientId = "<client-id>";
string _clientSecret = "<client-secret>";
AuthenticationContext authenticationContext = new AuthenticationContext(_authString, false);
ClientCredential clientCred = new ClientCredential(_clientId, _clientSecret);
AuthenticationResult authenticationResult;
authenticationResult = authenticationContext.AcquireTokenAsync("https://graph.microsoft.com", clientCred).GetAwaiter().GetResult();
Console.WriteLine(authenticationResult.AccessToken);
var token = authenticationResult.AccessToken;
var client = new HttpClient();
var uri = "https://graph.microsoft.com/v1.0/users";
client.DefaultRequestHeaders.Add("Authorization", "Bearer " + token);
client.DefaultRequestHeaders.Accept.Clear();
//GET Method
HttpResponseMessage response = client.GetAsync(uri).GetAwaiter().GetResult();
Console.WriteLine(response.Content.ReadAsStringAsync().Result.ToString());
}
}
}
Upvotes: 1
Reputation: 27588
There are two issues :
Wrong resource , the resource should be https://graph.microsoft.com
. And confirm that you have grant correct Microsoft Graph's permissions in Azure AD portal
You are using client credential flow as using AcquireTokenAsync(String, ClientCredential)
method without user , so https://graph.microsoft.com/v1.0/me/
won't work since there is no user in it . Use GET /users/{id | userPrincipalName}
instead . Also , you should grant Application Permission
in azure portal since you are using M2M flow .
Permissions (from least to most privileged) :
Application :User.Read.All, User.ReadWrite.All, Directory.Read.All, Directory.ReadWrite.All
Upvotes: 1
Reputation: 2447
I think if you're calling Microsoft Graph the resource needs to be https://graph.microsoft.com
instead of AAD Graph (graph.windows.net). Can you try changing that in your AcquireTokenAsync
call?
Upvotes: 1