Skip to content

Instantly share code, notes, and snippets.

@jackawatts
Last active February 7, 2023 05:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jackawatts/42b8e7f7ae0691d28b90677424b52e9e to your computer and use it in GitHub Desktop.
Save jackawatts/42b8e7f7ae0691d28b90677424b52e9e to your computer and use it in GitHub Desktop.

Managed Identity auth with simple app authentication (via Add identity provider from the Authentication tab of the app that needs to be protected) is outlined here. This covers the most rudimentary case.

However, often we want to be more specific as to which actions should be protected and which not, where something such as what is outlined here would be done. In this case code is used to configure Auth via the Services.AddAuthentication pattern or the like.

Calling such a web API with Managed identity is achieved using app roles described here

App roles are necessary for app to app communication as apps cannot consent to granular permissions.

The following steps outline how to enable app to app communication via Managed Identity using app roles taken from here:

  1. Enable managed identity on the resource
  2. Copy the Object ID from the identity tab of the resource -> $miOid
  3. Copy the Object ID of the Enterprise Application which represents the app the resource need to authenticate with -> $serviceOid
  4. Create an app role for the App Registration of the app the resource needs to communicate with and copy the appRoleId eg. 'access_as_application' (the name is up to you)
  5. Run the following script
$miOid="<step_2>"
$serviceOid="<step_3>"
$appRoleId="<step_4>"
$body = (@{
  principalId=$miOid
  resourceId=$serviceOid
  appRoleId=$appRoleId
} | ConvertTo-Json -Compress).Replace('"', '\"')
az rest -m POST -u https://graph.microsoft.com/v1.0/servicePrincipals/$miOid/appRoleAssignments -b $body

If successful the result should appear as follows

{
  "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#servicePrincipals('<miOID>')/appRoleAssignments/$entity",
  "appRoleId": "<appRoleId>",
  "createdDateTime": "2022-10-31T11:57:11.6563782Z",
  "deletedDateTime": null,
  "id": "vkSTufiNCkmE1dDhZDxE1dFLII64-WVOpNL5Trgm-3w",
  "principalDisplayName": "<miAppName>",
  "principalId": "<miOid>",
  "principalType": "ServicePrincipal",
  "resourceDisplayName": "<serviceAppName>",
  "resourceId": "<serviceOid>"
}

Code for calling the API is as follows

NOTE: you should likely be using HttpClientFactory for this.

var httpClient = new HttpClient();
var azureCredential = new DefaultAzureCredential();
var context = new TokenRequestContext(
  new string[] { "api://<app_id>/.default" }); // the Application ID URI copied from the protected app App Registration + /.default 
var token = await azureCredential.GetTokenAsync(context);

httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token.Token);

var result = await httpClient.GetStringAsync("https://service_app.azurewebsites.net/");

The calling API will receive a token with the appropriate role claim defined above

The receiving API can than verify that role as follows:

[Authorize(Roles = "access_as_application")]

With more details outlined in the original link describing protecting a web api from the start of this gist

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment