Skip to content

Latest commit

 

History

History
314 lines (241 loc) · 12 KB

scenario-web-app-call-api-call-api.md

File metadata and controls

314 lines (241 loc) · 12 KB
title description author manager ms.author ms.custom ms.date ms.reviewer ms.service ms.topic
Call a web API from a web app
Learn how to build a web app that calls web APIs (calling a protected web API).
cilwerner
CelesteDG
cwerner
09/25/2020
jmprieur
identity-platform
concept-article

A web app that calls web APIs: Call a web API

Now that you have a token, you can call a protected web API. You usually call a downstream API from the controller or pages of your web app.

Call a protected web API

Calling a protected web API depends on your language and framework of choice:

When you use Microsoft.Identity.Web, you have three usage options for calling an API:

Option 1: Call Microsoft Graph with the SDK

In this scenario, you call Microsoft Graph by adding the Microsoft.Identity.Web.GraphServiceClient NuGet package and including .AddMicrosoftGraph() in Startup.cs as specified in Code configuration. You can then directly inject the GraphServiceClient into your controller or page constructor to use it in the actions. The following example Razor page displays the photo of the signed-in user.

[Authorize]
[AuthorizeForScopes(Scopes = new[] { "user.read" })]
public class IndexModel : PageModel
{
 private readonly GraphServiceClient _graphServiceClient;

 public IndexModel(GraphServiceClient graphServiceClient)
 {
    _graphServiceClient = graphServiceClient;
 }

 public async Task OnGet()
 {
  var user = await _graphServiceClient.Me.GetAsync();
  try
  {
   using (var photoStream = await _graphServiceClient.Me.Photo.Content.GetAsync())
   {
    byte[] photoByte = ((MemoryStream)photoStream).ToArray();
    ViewData["photo"] = Convert.ToBase64String(photoByte);
   }
   ViewData["name"] = user.DisplayName;
  }
  catch (Exception)
  {
   ViewData["photo"] = null;
  }
 }
}

For a full sample, see ASP.NET Core web app that calls Microsoft Graph.

Option 2: Call a downstream web API with the helper class

You want to call a web API other than Microsoft Graph. In that case, you add AddDownstreamApi in Startup.cs as specified in Code configuration, and you can directly inject an IDownstreamApi service in your controller or page constructor and use it in the actions:

[Authorize]
[AuthorizeForScopes(ScopeKeySection = "TodoList:Scopes")]
public class TodoListController : Controller
{
  private IDownstreamApi _downstreamApi;
  private const string ServiceName = "TodoList";

  public TodoListController(IDownstreamApi downstreamApi)
  {
    _downstreamApi = downstreamApi;
  }

  public async Task<ActionResult> Details(int id)
  {
    var value = await _downstreamApi.CallApiForUserAsync(
      ServiceName,
      options =>
      {
        options.RelativePath = $"me";
      });
      return View(value);
  }
}

The CallWebApiForUserAsync also has strongly typed generic overrides that enable you to directly receive an object. For example, the following method receives a Todo instance, which is a strongly typed representation of the JSON returned by the web API.

    // GET: TodoList/Details/5
    public async Task<ActionResult> Details(int id)
    {
        var value = await _downstreamApi.CallApiForUserAsync<object, Todo>(
            ServiceName,
            null,
            options =>
            {
                options.HttpMethod = HttpMethod.Get;
                options.RelativePath = $"api/todolist/{id}";
            });
        return View(value);
    }

For a full sample, see ASP.NET Core web app that calls an API

Option 3: Call a downstream web API without the helper class

You've decided to acquire a token manually using the IAuthorizationHeaderProvider service, and you now need to use the token. In that case, the following code continues the example code shown in A web app that calls web APIs: Acquire a token for the app. The code is called in the actions of the web app controllers.

After you've acquired the token, use it as a bearer token to call the downstream API, in this case Microsoft Graph.

public async Task<IActionResult> Profile()
{
  // Acquire the access token.
  string[] scopes = new string[]{"user.read"};
  string authorizationHeader = await IAuthorizationHeaderProvider.GetAuthorizationHeaderForUserAsync(scopes);

  // Use the access token to call a protected web API.
  HttpClient httpClient = new HttpClient();
  client.DefaultRequestHeaders.Add("Authorization", authorizationHeader);

  var response = await httpClient.GetAsync($"{webOptions.GraphApiUrl}/beta/me");

  if (response.StatusCode == HttpStatusCode.OK)
  {
    var content = await response.Content.ReadAsStringAsync();

    dynamic me = JsonConvert.DeserializeObject(content);
    ViewData["Me"] = me;
  }

  return View();
}

Note

You can use the same principle to call any web API.

Most Azure web APIs provide an SDK that simplifies calling the API as is the case for Microsoft Graph.

When you use Microsoft.Identity.Web, you have three usage options for calling an API:

Option 1: Call Microsoft Graph with the SDK from OWIN app

You want to call Microsoft Graph. In this scenario, you've added AddMicrosoftGraph in Startup.cs as specified in Code configuration, and you can get the GraphServiceClient in your controller or page constructor for use in the actions by using the GetGraphServiceClient() extension method on the controller. The following example displays the photo of the signed-in user.

[Authorize]
[AuthorizeForScopes(Scopes = new[] { "user.read" })]
public class HomeController : Controller
{

 public async Task GetIndex()
 {
  var graphServiceClient = this.GetGraphServiceClient();
  var user = await graphServiceClient.Me.GetAsync();
  try
  {
   using (var photoStream = await graphServiceClient.Me.Photo.Content.GetAsync())
   {
    byte[] photoByte = ((MemoryStream)photoStream).ToArray();
    ViewData["photo"] = Convert.ToBase64String(photoByte);
   }
   ViewData["name"] = user.DisplayName;
  }
  catch (Exception)
  {
   ViewData["photo"] = null;
  }
 }
}

For a full sample, see ASP.NET OWIN Web app that calls Microsoft Graph

Option 2: Call a downstream web API with the helper class from OWIN app

You want to call a web API other than Microsoft Graph. In that case, you've added AddDownstreamApi in Startup.cs as specified in Code configuration, and you can get IDownstreamApi service in your controller by calling the GetDownstreamApi extension method on the controller:

[Authorize]
public class TodoListController : Controller
{ 
  public async Task<ActionResult> Details(int id)
  {
    var downstreamApi = this.GetDownstreamApi();
    var value = await downstreamApi.CallApiForUserAsync(
      ServiceName,
      options =>
      {
        options.RelativePath = $"me";
      });
      return View(value);
  }
}

The CallApiForUserAsync also has strongly typed generic overrides that enable you to directly receive an object. For example, the following method receives a Todo instance, which is a strongly typed representation of the JSON returned by the web API.

    // GET: TodoList/Details/5
    public async Task<ActionResult> Details(int id)
    {
        var downstreamApi = this.GetDownstreamApi();
        var value = await downstreamApi.CallApiForUserAsync<object, Todo>(
            ServiceName,
            null,
            options =>
            {
                options.HttpMethod = HttpMethod.Get;
                options.RelativePath = $"api/todolist/{id}";
            });
        return View(value);
    }

Option 3: Call a downstream web API without the helper class from OWIN app

You've decided to acquire an authorization header using the IAuthorizationHeaderProvider service, and you now need to use it in your HttpClient or HttpRequest. In that case, the following code continues the example code shown in A web app that calls web APIs: Acquire a token for the app. The code is called in the actions of the web app controllers.

public async Task<IActionResult> Profile()
{
  // Acquire the access token.
  string[] scopes = new string[]{"user.read"};
  var IAuthorizationHeaderProvider = this.GetAuthorizationHeaderProvider();
  string authorizationHeader = await IAuthorizationHeaderProvider.GetAuthorizationHeaderForUserAsync(scopes);

  // Use the access token to call a protected web API.
  HttpClient httpClient = new HttpClient();
  client.DefaultRequestHeaders.Add("Authorization", authorizationHeader);

  var response = await httpClient.GetAsync($"{webOptions.GraphApiUrl}/beta/me");

  if (response.StatusCode == HttpStatusCode.OK)
  {
    var content = await response.Content.ReadAsStringAsync();

    dynamic me = JsonConvert.DeserializeObject(content);
    ViewData["Me"] = me;
  }

  return View();
}
private String getUserInfoFromGraph(String accessToken) throws Exception {
    // Microsoft Graph user endpoint
    URL url = new URL("https://graph.microsoft.com/v1.0/me");

    HttpURLConnection conn = (HttpURLConnection) url.openConnection();

    // Set the appropriate header fields in the request header.
    conn.setRequestProperty("Authorization", "Bearer " + accessToken);
    conn.setRequestProperty("Accept", "application/json");

    String response = HttpClientHelper.getResponseStringFromConn(conn);

    int responseCode = conn.getResponseCode();
    if(responseCode != HttpURLConnection.HTTP_OK) {
        throw new IOException(response);
    }

    JSONObject responseObject = HttpClientHelper.processResponse(responseCode, response);
    return responseObject.toString();
}

After successfully retrieving a token, the code uses the axios package to query the API endpoint and retrieve a JSON result.

:::code language="js" source="~/../ms-identity-node/App/fetch.js" range="8-28":::

After successfully retrieving a token, the code uses the requests package to query the API endpoint and retrieve a JSON result.

:::code language="python" source="~/../ms-identity-python-webapp-tutorial/app.py" range="60-71" highlight="7-11":::


Next steps

  • Learn more by building an ASP.NET Core web app that signs in users in the following multi-part tutorial series

  • Explore Microsoft identity platform web app samples