Take token using ‘authorized code’ grant type of Microsoft Graph API

Microsoft Graph API supports an authentication flow of The OAuth 2.0 Authorization Framework, there are four types of grant types of it (refer to the article). The ‘authorization code’ grant type is one of them, and Microsoft Graph API returns the authorization code when corresponding to the request of the authorizing the Azure Active Directory account.
In the authentication flow, an app uses this authorization code to request a token which is used for accessing user resources.
Microsoft Identity Platform provides a feature that these processes that are from calling authorization an account to taking a token complete automatically. And a token acquired is kept in the cache provided by a feature of the Microsoft Identity Platform.
If the app wants to use correctly several tokens in an individual situation, it is good that the app interrupts a code or a token and changes to minimum scopes properly to access individual resources.
For example, in case of the app login as an account of Azure Active Directory and sharing a resource owned by login user to another user and post a message to Microsoft Teams as a login user. In this case, the token acquired at the app login should have all scopes that permitted to execute. there are to post to Microsoft Teams, to read all groups of the domain, to access login user’s resources.
It is not bad that the Azure Active Directory application has all scopes, but it is not good to request to acquire a token that has all scopes because the individual request is not needed for all scopes.
Therefore, it is good to choose properly in case of using the Microsoft Identity Platform and in case of taking a token per minimum scopes.
This article how to take authorization code and throw requests a token using the code.

>>The code sample of this article

・Setting configuration for development environment

As first, this article using The code sample of the article which implements already the ‘authorization code’ grant type authentication flow. Download the code sample, restore packages and run debug done, then modify ‘Sign In’ action in the ‘Account’ controller of [Controllers] folder at the Solution Explorer to usable for the development environment.

using Microsoft.AspNetCore.Mvc;

namespace React.Sample.Webpack.CoreMvc.Controllers
{
  public class AccountController : Controller
    {
    [Route("Account/SignIn")]
    [ResponseCache(Location = ResponseCacheLocation.None, NoStore = true)]
    public void SignIn()
    {
      var tenant = "__YOUR TENANT__";//this grant_type allows common
      var clientId = "__APP CLIENT ID__";
      var redirectUri = "http://localhost:9457/home";
      Response.Redirect("https://login.microsoftonline.com/" + tenant 
        + "/oauth2/v2.0/authorize?client_id=" + clientId + "&redirect_uri=" 
        + redirectUri + "&grant_type=implicit&response_type=code&scope=User.Read");
    }
  }
}

Modify lines of the variable ‘tenant’ and ‘clientId’ to useable for the development environment(11th line and 12th line).

And open ‘Index’ action in the ‘Home’ controller of [Controllers] folder at the Solution Explorer, put a breakpoint at the 45th line. Then run debug and confirm acquiring ‘code’ and ‘state’ variables.

・Get token

Insert code below after the place that acquiring a ‘state’ variable, and modify lines of the variable ‘tenant’, ‘clientId’ and ‘secret’ to useable for the development environment.

var signIn = false;
var token = string.Empty;
if (!string.IsNullOrEmpty(code))
{
  var tenant = "__YOUR TENANT__";//this grant_type allows common
  var clientId = "__APP CLIENT ID__";
  var redirectUri = "http://localhost:9457/home";
  var secret = "__CLIENT SECRET__";
  token = new AccessGraph().GetToken(clientId, secret, redirectUri, "", code, tenant, "user.read");
  if (!string.IsNullOrEmpty(token)) signIn = true;
}
ViewBag.IsSignin = signIn;

Add a new class file name that is ‘AccessGraph.cs’ at the root of the solution, and create the ‘GetToken’ method of the ‘AccessGraph’ class. (the code sample includes it)

namespace React.Sample.Webpack.CoreMvc
{
  public class AccessGraph
  {
    public string GetToken(string clientid, string secret, string redirect, string refreshtoken,
                           string authCode, string tenant, string resource = "user.read")
    {
      string result = string.Empty;
      MSGraphAuthTokens tokens = null;
      var url = $"https://login.microsoftonline.com/" + tenant + "/oauth2/v2.0/token";// AAD
      url = $"https://login.microsoftonline.com/common/oauth2/token";// live API
      using (var httpClient = new HttpClient())
      {
        var properties = "client_id=" + clientid + "&client_secret=" + secret + "&scope=" + resource;
        properties += "&redirect_uri=" + redirect;
        if (!string.IsNullOrEmpty(refreshtoken))
        {
          properties += "&refresh_token=" + refreshtoken + "&grant_type=refresh_token";
        }
        if (!string.IsNullOrEmpty(authCode))
        {
          properties += "&code=" + authCode + "&grant_type=authorization_code";
        }
        var content
              = new StringContent(properties, Encoding.UTF8, "application/x-www-form-urlencoded");
        var res = httpClient.PostAsync(url, content).Result;
        string resultJson = res.Content.ReadAsStringAsync().Result;
        if (res.IsSuccessStatusCode)
        {
          tokens = JsonConvert.DeserializeObject(resultJson);
          result = tokens.access_token;
        }
      }
      return result;
    }
  }
  public class MSGraphAuthTokens
  {
    public string access_token { get; set; }
    public string token_type { get; set; }
    public string expires_in { get; set; }
    public string scope { get; set; }
    public string refresh_token { get; set; }
    public string id_token { get; set; }
  }
}

Put a breakpoint after the line of putting the ‘signIn’ variable to the ‘ViewBag.IsSignin’ container (56th line) to confirm succeed acquiring token since the ‘sign’ variable is ‘true’.

>>The code sample of this article

About takao

I'm Microsoft MVP since June 2010.