title: Web Application and API AzureAD authentication flow ASP.NET Core
body: <p>I'm currently confused about how to realize the authentication / authorization flow.</p>
  
  <p>I'm developing two applications, the one is the frontend/Webapplication and the other the backend/API, both with ASP.NET Core. The goal is to use the AzureAD and use the users/groups from the domain. The authentication I already implemented on both applications and I'm able to login and restrict content based on the login state.</p>
  
  <p>As reference I took <a href="https://github.com/Azure-Samples/active-directory-dotnet-webapp-webapi-openidconnect-aspnetcore" rel="nofollow noreferrer"><strong>this</strong></a> example from a microsoft developer. There should be exactly this what I want to do. There is a WebApp and API. The used authentication flow is the <em>authorization code flow</em>. First the user needs to login and after that when some data needs to be requested from the API, an access token will be requested.</p>
  
  <p><strong>Question 1:</strong> Is this the right authentication flow? For me this seems like a doubled authentication, because first I authenticate myself at the frontend and when the Webapp needs some data I need to authenticate myself again at the backend. The same Azure AD tenant is used, so what do you think here?</p>
  
  <p>The next point what seems very "ugly" is the procedure getting some data. In the example when some data is requested first the token will be requested and after this the data. But in my opinion with a lot of boilerplate. The example code below is needed for just one request of all ToDo items. </p>
  
  <pre><code>// GET: /&lt;controller&gt;/
  public async Task&lt;IActionResult&gt; Index()
  {
      AuthenticationResult result = null;
      List&lt;TodoItem&gt; itemList = new List&lt;TodoItem&gt;();
  
      try
      {
          // Because we signed-in already in the WebApp, the userObjectId is know
          string userObjectID = (User.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier"))?.Value;
  
          // Using ADAL.Net, get a bearer token to access the TodoListService
          AuthenticationContext authContext = new AuthenticationContext(AzureAdOptions.Settings.Authority, new NaiveSessionCache(userObjectID, HttpContext.Session));
          ClientCredential credential = new ClientCredential(AzureAdOptions.Settings.ClientId, AzureAdOptions.Settings.ClientSecret);
          result = await authContext.AcquireTokenSilentAsync(AzureAdOptions.Settings.TodoListResourceId, credential, new UserIdentifier(userObjectID, UserIdentifierType.UniqueId));
  
          // Retrieve the user's To Do List.
          HttpClient client = new HttpClient();
          HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, AzureAdOptions.Settings.TodoListBaseAddress + "/api/todolist");
          request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
          HttpResponseMessage response = await client.SendAsync(request);
  
          // Return the To Do List in the view.
          if (response.IsSuccessStatusCode)
          {
              List&lt;Dictionary&lt;String, String&gt;&gt; responseElements = new List&lt;Dictionary&lt;String, String&gt;&gt;();
              JsonSerializerSettings settings = new JsonSerializerSettings();
              String responseString = await response.Content.ReadAsStringAsync();
              responseElements = JsonConvert.DeserializeObject&lt;List&lt;Dictionary&lt;String, String&gt;&gt;&gt;(responseString, settings);
              foreach (Dictionary&lt;String, String&gt; responseElement in responseElements)
              {
                  TodoItem newItem = new TodoItem();
                  newItem.Title = responseElement["title"];
                  newItem.Owner = responseElement["owner"];
                  itemList.Add(newItem);
              }
  
              return View(itemList);
          }
  
          //
          // If the call failed with access denied, then drop the current access token from the cache, 
          //     and show the user an error indicating they might need to sign-in again.
          //
          if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
          {
              return ProcessUnauthorized(itemList, authContext);
          }
      }
      catch (Exception)
      {
          if (HttpContext.Request.Query["reauth"] == "True")
          {
              //
              // Send an OpenID Connect sign-in request to get a new set of tokens.
              // If the user still has a valid session with Azure AD, they will not be prompted for their credentials.
              // The OpenID Connect middleware will return to this controller after the sign-in response has been handled.
              //
              return new ChallengeResult(OpenIdConnectDefaults.AuthenticationScheme);
          }
          //
          // The user needs to re-authorize.  Show them a message to that effect.
          //
          TodoItem newItem = new TodoItem();
          newItem.Title = "(Sign-in required to view to do list.)";
          itemList.Add(newItem);
          ViewBag.ErrorMessage = "AuthorizationRequired";
          return View(itemList);
      }
      //
      // If the call failed for any other reason, show the user an error.
      //
      return View("Error");
  }
  </code></pre>
  
  <p><strong>Question 2:</strong> Is there a "less ugly" approach to access the data if the flow in Q1 is right?</p>