3

My C# program uses the Microsoft.Graph Nuget. And it needs be able to ensure that it has the correct Microsoft Graph application permissions.

I know how to add permissions in AD, but I want my program to be able test it has the permissions it needs.

Example of what I want to achieve :

var graphClient = new GraphServiceClient(authenticationProvider);

if(!graphClient.GetPermissions().Contains("AdministrativeUnit.Read.All"))
{
    throw new Exception("Missing Permission AdministrativeUnit.Read.All")
}

Thanks in advance !

Johan Polson
  • 117
  • 3
  • 12

2 Answers2

5

It's a long way.

Here I provide a general idea of Microsoft Graph beta version(through HTTP method):

  1. Get the Object ID of the servicePrincipal based on the App ID: GET https://graph.microsoft.com/beta/servicePrincipals?$filter=appId eq '{App ID}'.
  2. Get the appRole information (the application permission information) based on the Object ID from step 1: GET https://graph.microsoft.com/beta/servicePrincipals/{Object ID}/appRoleAssignedTo. enter image description here
  3. Get a match list of appRoleID and Microsoft Graph application permission name: GET https://graph.microsoft.com/beta/servicePrincipals?$filter=appId eq '00000003-0000-0000-c000-000000000000'. Please note that "00000003-0000-0000-c000-000000000000" is a fixed value, which represents the App ID of the Microsoft internal Graph App. enter image description here
  4. Compare the results of the 2nd and 3rd steps and you will know which application permissions are in your Azure AD app.

By the way, Get appRoleAssignment is only available in beta version currently, but beta version api is not recommended to use.

APIs under the /beta version in Microsoft Graph are subject to change. Use of these APIs in production applications is not supported.

Allen Wu
  • 15,529
  • 1
  • 9
  • 20
0

Even though this is an old question, I was challenged with the same issue and I want to share my solution which I find a lot more practical and easier to understand.

Introduce these two helper methods into your code:

using Newtonsoft.Json;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;

/// <summary>
/// Decodes a JWT token to a decoded string.
/// </summary>
/// <param name="jwtToken">The JWT token to decode.</param>
/// <returns>The decoded string representation of the JWT token.</returns>
public static string DecodeJwtToken(string jwtToken)
{
    var tokenHandler = new JwtSecurityTokenHandler();

    if (tokenHandler.CanReadToken(jwtToken))
    {
        var decodedToken = tokenHandler.ReadJwtToken(jwtToken);
        return decodedToken.ToString();
    }

    else
    {
        throw new ArgumentException("Invalid JWT token.");
    }
}

/// <summary>
/// Extracts the "roles" array from a JWT security token.
/// </summary>
/// <param name="jwtToken">The JWT security token from which to extract the roles array.</param>
/// <returns>A list of strings representing the roles extracted from the JWT security token.</returns>
public static List<string> ExtractRolesFromJwtSecurityToken(string jwtToken)
{
    var tokenHandler = new JwtSecurityTokenHandler();
    var securityToken = tokenHandler.ReadToken(jwtToken) as JwtSecurityToken;
 
    if (securityToken != null)
    {
        var rolesClaims = securityToken.Claims.Where(claim => claim.Type == "roles");
        if (rolesClaims != null)
        {
            var roleStrings = rolesClaims.Select(claim => claim.Value.Replace("roles:", "").Trim()).ToList();
            return roleStrings;
        }
    }
 
    // If roles claim is not found or cannot be extracted, return an empty list or handle the error accordingly.
    return new List<string>();
}

These two can be used like this:

var app = ConfidentialClientApplicationBuilder.Create(clientId)
                .WithAuthority(AzureCloudInstance.AzurePublic, tenantId)
                .WithClientSecret(clientSecret)
                .Build();
var authResult = await app.AcquireTokenForClient(scopes).ExecuteAsync();

var jwtToken = authResult.AccessToken;

// use this if you want to inspect the entire token
var decodedToken = DecodeJwtToken(jwtToken);

// and if you're lazy, this. The result will be like {"Mail.Read", "Mail.Write", ... }
var permissions = ExtractRolesFromJwtSecurityToken(jwtToken);
beggarboy
  • 173
  • 1
  • 12