title: Simple Directory Lookup in Azure Active Directory
body: <p>I am writing a simple desktop application that needs to retrieve some basic properties about a user from Microsoft’ directory. Specifically:</p>
  
  <ol>
  <li>I am writing a single tenant native LOB application.</li>
  <li>The application runs on my desktop.</li>
  <li>The application runs as my logged on domain account.</li>
  <li>The organization' domain accounts are synced to AAD. </li>
  <li>I am not trying to secure a native web app or a Web API or anything like that. I do not need users to sign in.</li>
  <li>I have email addresses of folks in my organization from an external event management tool. I need to lookup the AAD account profile data (address book info - specifically job title) from AAD based on the email address. I will only be reading AAD data.</li>
  </ol>
  
  <p>So far, I have done the following:-</p>
  
  <ol>
  <li><p>It appears that the Azure AD Graph API is the right way to fetch the profile information. In particular, the information is available at the endpoint: <a href="https://graph.windows.net/" rel="nofollow noreferrer">https://graph.windows.net/</a>{tenant}/users/{email}?api-version=1.6</p></li>
  <li><p>When registering the native application in AAD, no key was provided. So I don't have a client secret.</p></li>
  <li><p>Looked at the sample in GitHub here: <a href="https://github.com/Azure-Samples/active-directory-dotnet-graphapi-console" rel="nofollow noreferrer">https://github.com/Azure-Samples/active-directory-dotnet-graphapi-console</a>. The instructions here seem to be wrong because no Keys section is available [see (2)]. </p></li>
  </ol>
  
  <p>Based on the sample above, I wrote a simple function. Code is below:</p>
  
  <pre><code>    private static async Task PrintAADUserData(string email)
      {
          string clientId = "0a202b2c-6220-438d-9501-036d4e05037f";
          Uri redirectUri = new Uri("http://localhost:4000");
          string resource = "https://graph.windows.net/{tenant}";
          string authority = "https://login.microsoftonline.com/{tenant}/oauth2/authorize";
          AuthenticationContext authContext = new AuthenticationContext(authority);
  
          AuthenticationResult authResult = await authContext.AcquireTokenAsync(resource, clientId, redirectUri, new PlatformParameters(PromptBehavior.Auto));
  
          string api = String.Format("https://graph.windows.net/{tenant}/users/{0}?api-version=1.6", email);
          LOG.DebugFormat("Using API URL {0}", api);
  
          // Create an HTTP client and add the token to the Authorization header
          HttpClient httpClient = new HttpClient();
          httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(authResult.AccessTokenType, authResult.AccessToken);
          HttpResponseMessage response = await httpClient.GetAsync(api);
  
          string data = await response.Content.ReadAsStringAsync();
          LOG.Debug(data);
      }
  </code></pre>
  
  <p><strong>Questions</strong></p>
  
  <ol>
  <li><p>The application when run was able to bring up the authentication page. Why do I need that? The application already runs as my domain account. Is an additional authentication necessary? If I were to run this application in Azure as a worker process, then I would not want to use my domain credentials.</p></li>
  <li><p>The primary problem seems to be the resource URL which is wrong. What resource do I need to specify to access the Azure AD Graph API?</p></li>
  </ol>
  
  <p>Thanks,</p>
  
  <p>Vijai.</p>
  
  <p><strong>EDITS</strong></p>
  
  <p>Based on the comments from @Saca, the code and application has been edited. </p>
  
  <p><strong><em>Code</em></strong></p>
  
  <pre><code>string clientId = ConfigurationManager.AppSettings["AADClientId"];
  string clientSecret = ConfigurationManager.AppSettings["AADClientSecret"];
  string appIdUri = ConfigurationManager.AppSettings["AADAppIdURI"];
  string authEndpoint = ConfigurationManager.AppSettings["AADGraphAuthority"];
  string graphEndpoint = ConfigurationManager.AppSettings["AADGraphEndpoint"];
  
  AuthenticationContext authContext = new AuthenticationContext(authEndpoint, false);
  AuthenticationResult authResult = await authContext.AcquireTokenAsync("https://graph.windows.net", new ClientCredential(clientId, clientSecret));
  ExistingTokenWrapper wrapper = new ExistingTokenWrapper(authResult.AccessToken);
  ActiveDirectoryClient client = new ActiveDirectoryClient(new Uri(graphEndpoint), async () =&gt; await wrapper.GetToken());
  
  IUser user = client.Users.Where(_ =&gt; _.UserPrincipalName.Equals(email.ToLowerInvariant())).Take(1).ExecuteSingleAsync().Result;
  </code></pre>
  
  <p><strong><em>App</em></strong>
  <a href="https://i.stack.imgur.com/tvYay.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/tvYay.png" alt="AAD Application Permissions Setup"></a>
  <strong><em>Error</em></strong>
  Unhandled Exception: System.AggregateException: One or more errors occurred. ---> System.AggregateException: One or more errors occurred. ---> Microsoft.Data.OData.ODataErrorException: Insufficient privileges to complete the operation. ---> System.Data.Services.Client.DataServiceQueryException: An error occurred while processing this request. ---> System.Data.Services.Client.DataServiceClientException: {"odata.error":{"code":"Authorization_RequestDenied","message":{"lang":"en","value":"Insufficient privileges to complete the operation."}}}</p>
  
  <p>It appears that despite giving the right permissions, the correct resource and being able to acquire a token, there is still something missing.</p>