Provide Admin Consent for Azure AD Applications Programmatically

If you have worked with Azure AD Applications or Service Principals, you have likely come across the issue of consent. It is often necessary to grant an application the ability to access resources, API's or act as the user. To ensure that only applications are only granted access to resources you allow, Azure AD has a concept of consent. Where someone with the correct rights allows that level of access for the application. Consent comes in two forms:

  • User Consent - where the application requires access to use specific resources that the end-user is allowed to provide consent for
  • An administrator must provide admin Consent - where access is required to more sensitive resources, or at a broader scope, the consent. This is someone in the Global Administrator or Application Administrator role

Consenting to applications can be done manually through the Azure Portal, or in the case of user consent, at the time the application tries to use the permission. This is fine where you have this interactive scenario, but sometimes you are looking to undertake this as part of an automated scenario. An excellent example of this is with AKS. If you want to automate the deployment of your AKS clusters fully and you are using Azure AD Authentication for AKS (which you should be), then you get a bit stuck. The server application used by AKS requires admin consent for a right it requires, which required a manual step.

Up until recently, it has not been possible to automate this process. There is a CLI command for granting admin consent, but it does not work if you try and use a service principal (see here). A recent update to the Azure AD REST API makes this possible. At the moment, this is only possible using REST; there is no built-in CLI or PowerShell command to do this; however, we will look at how you can do this in a PowerShell script below.

Beta Warning

At present, the “oAuth2Permissiongrants” API that we will use is in beta. I've not experienced any issues with it, but be aware of this. It will move into GA in the future.

Prerequisites

Admin Service Principal

To be able to grant consent through automation, you will need a service principal to run your automation as. If you're not familiar with doing this, then see here.

This service principal needs to have the required permissions to grant consent; in particular, it needs the “Directory.ReadWrite.All” application (not delegated) permission.

Permission

This permission grants a lot of rights, but unfortunately, there is not currently a way to reduce this scope. Given this, you need to be careful to secure this service principal and make sure only authorised processes and users have access to it. Make sure you are OK with this and understand the consequences before using this technique.

Application Service Principal

For your application to be granted these rights, there must already be a service principal associated with that application; it cannot be just an application without a service principal. If you do have an application without a service principal and you need to create one you can do so with the following PowerShell, this requires the Azure AD PowerShell modules.

New-AzureADServicePrincipal -AppId <your application id>

Authentication

Now we have a service principal setup we can start writing the code to undertake this consent. We are going to do this in PowerShell. The first step is for us to authenticate against the Azure AD API using our service principal. For this, we need to know the application ID (clientID), password (clientSecret) and tenant ID for the service principal.

    $clientId = "xxxxxx"
    $clientSecret = "xxxxxx"
    $tenantID = "xxxxxx"


    $ReqTokenBody = @{
        Grant_Type    = "client_credentials"
        Scope         = "https://graph.microsoft.com/.default"
        client_Id     = $clientID
        Client_Secret = $clientSecret
    }
    $TokenResponse = Invoke-RestMethod -Uri "https://login.microsoftonline.com/$TenantID/oauth2/v2.0/token" -Method POST -Body $ReqTokenBody

By running the command above we will receive back a bearer token that we can then use to authentication our next requests.

To grant consent, we need to collect the following data:

  • Service Principal ID - the object ID of the service principal that you need to grant consent for. Note that this is the object ID of the SP object found in the “Enterprise Applications” section of the portal, not the application
  • Resource ID - the ID of the API that the SP is going to be granted access to, for example, the Azure AD Graph API, see below for more details
  • Scope - the scope that the SP will have rights to on the API, e.g. group.read.all
  • PrincipalID - usually this is null as you want to grant rights for any user, but if you need to scope the right to a specific user you would need their object ID

Resource ID

The resource ID is the ID of the API you want to grant the Service Principal permission to. Finding this ID can be a pain. Every application that you can grant rights onto in Azure AD has a service principal, even those created by Microsoft. To get the resource ID, you need to find this in the “Enterprise Applications” tab in Azure AD. For example, we want to grant rights to the Microsoft Graph so that we can look in Enterprise Applications. Unfortunately, the service principal for Microsoft Graph is not called Microsoft Graph, so we need to try and find it. I do know that the application ID for graph is “00000003-0000-0000-c000-000000000000” in all tenants, so we can find it using that.

If you did not know the application ID one thing you could do is assign the required permission to your app, then in Powershell run the following:

$(Get-AzureADApplication -ObjectId <application object ID>).RequiredResourceAccess

This command returns the application ID which you can then search for in the Enterprise App page. The Graph app is helpfully called “GraphAggregatorService”. Once you find the app, click on it and then copy the ObjectID, this is your Resource ID.

App ID

Now that we have the resource ID, we are ready to grant consent. Using PowerShell again, we will first create the body object containing all our values.

$body = @{
    clientId    = $clientID
    consentType = "AllPrincipals"
    principalId = $null
    resourceId  = $resourceID
    scope       = "Group.Read.All"
    startTime   = "2019-10-19T10:37:00Z"
    expiryTime  = "2019-10-19T10:37:00Z"
}

A few things to note:

  • $clientID and $ resourceID are the values noted from above
  • consentType is “AllPrincipals” unless you want to scope to a specific user, then it is “Principal”.
  • principalID is null unless you want to scope to a specific user, then it is that users object ID
  • startTime and expiryTime are not used but must be supplied, so any date/time will work

Now we are ready to send this to the API to be processed, using the token we got above:

$apiUrl = "https://graph.microsoft.com/beta/oauth2PermissionGrants"
Invoke-RestMethod -Uri $apiUrl -Headers @{Authorization = "Bearer $($Tokenresponse.access_token)" }  -Method POST -Body $($body | convertto-json) -ContentType "application/json"

If all went well, you should get a response back showing that this completed successfully.

Completed

It can take a couple of minutes for this apply, but once that is done if you check your application, you should now see that consent has been applied.

Granted