Create Azure App Registration for API using Powershell

This post shows how to setup an Azure App registration using Powershell for an application access token using an application role. In Azure roles are used for App only, scopes are used for delegated flows (Or roles for users). The Azure App registration uses OAuth2 with the client credentials flow. A secret and a client_id is used.

Code: https://github.com/damienbod/GrpcAzureAppServiceAppAuth

The AzureAD Powershell module is used to create a new Azure App registration. The New-AzureADApplication function creates a new Azure App registration with a secret on the defined tenant from the authentication flow.

$Guid = New-Guid
$startDate = Get-Date
$allowPassthroughUsers = false

$PasswordCredential = New-Object -TypeName Microsoft.Open.AzureAD.Model.PasswordCredential
$PasswordCredential.StartDate = $startDate
$PasswordCredential.EndDate = $startDate.AddYears(20)
$PasswordCredential.KeyId = $Guid
$PasswordCredential.Value = ([System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes(($Guid))))

if(!($myApp = Get-AzureADApplication -Filter "DisplayName eq '$($appName)'"  -ErrorAction SilentlyContinue))
{
    $myApp = New-AzureADApplication -DisplayName $appName -PasswordCredentials $PasswordCredential -AllowPassthroughUsers $allowPassthroughUsers

	# Write-Host $myApp | Out-String | ConvertFrom-Json	
}

We need an App Role and this is exposed in the access token. The App Role can be created using this function. See this link for the original:

https://stackoverflow.com/questions/51651889/how-to-add-app-roles-under-manifest-in-azure-active-directory-using-powershell-s

This Azure App registration is created for an Application client, ie no user. If creating this for delegated flows, the AllowedMemberTypes would need to be changed and no secret/certificate is required. A scope would probably be used as well instead of a Role, but this depends on the solution authorization architecture.

function CreateApplicationAppRole([string] $Name, [string] $Description)
{
    $appRole = New-Object Microsoft.Open.AzureAD.Model.AppRole
    $appRole.AllowedMemberTypes = New-Object System.Collections.Generic.List[string]
    $appRole.AllowedMemberTypes.Add("Application");
    $appRole.DisplayName = $Name
    $appRole.Id = New-Guid
    $appRole.IsEnabled = $true
    $appRole.Description = $Description
    $appRole.Value = $Name;
    return $appRole
}

The Set-AzureADApplication function adds the roles to the Azure App registration.

$appRoles = $myApp.AppRoles
$newRole = CreateApplicationAppRole -Name $appRoleName -Description $appRoleName
$appRoles.Add($newRole)
Set-AzureADApplication -ObjectId $myApp.ObjectId -AppRoles $appRoles 
$appRoleId = $newRole.Id

The App Role can now be used and exposed in the access token. This is added using the RequiredResourceAccess

$req = New-Object -TypeName "Microsoft.Open.AzureAD.Model.RequiredResourceAccess"
$acc1 = New-Object -TypeName "Microsoft.Open.AzureAD.Model.ResourceAccess" -ArgumentList $appRoleId,"Role"
$req.ResourceAccess = $acc1
$req.ResourceAppId = $myApp.AppId
Set-AzureADApplication -ObjectId $myApp.ObjectId -RequiredResourceAccess $req

For some unknown reasin, the Powershell AzureAD module add default Oauth2Permissions to the Azure App registration. This can be disabled. We have no scopes as this is an application client, i.e. AppOnly.

$Scopes = New-Object System.Collections.Generic.List[Microsoft.Open.AzureAD.Model.OAuth2Permission]
$Scope = $myApp.Oauth2Permissions | Where-Object { $_.Value -eq "user_impersonation" }
$Scope.IsEnabled = $false
$Scopes.Add($Scope)
Set-AzureADApplication -ObjectId $myApp.ObjectID -Oauth2Permissions $Scopes

The API IdentifierUris is added to the Azure App registration.

$apiUrl = "api://" + $myApp.AppId
$IdentifierUris = New-Object System.Collections.Generic.List[string]
$IdentifierUris.Add($apiUrl)
Set-AzureADApplication -ObjectId $myApp.ObjectID -IdentifierUris $IdentifierUris

A service principal can be created for the Azure App Registration. This can then be used in the enterprise applications.

$createdServicePrincipal = New-AzureADServicePrincipal -AccountEnabled $true -AppId $myApp.AppId -DisplayName $appName

Graph application roles can also be added to the Azure App Registration if required. I usually separated this to a different Azure App registration.

$req = New-Object -TypeName "Microsoft.Open.AzureAD.Model.RequiredResourceAccess"
$acc1 = New-Object -TypeName "Microsoft.Open.AzureAD.Model.ResourceAccess" -ArgumentList "62a82d76-70ea-41e2-9197-370581804d09","Role"
$acc2 = New-Object -TypeName "Microsoft.Open.AzureAD.Model.ResourceAccess" -ArgumentList "5b567255-7703-4780-807c-7be8301ae99b","Role"
$acc3 = New-Object -TypeName "Microsoft.Open.AzureAD.Model.ResourceAccess" -ArgumentList "9e3f62cf-ca93-4989-b6ce-bf83c28f9fe8","Role"
$acc4 = New-Object -TypeName "Microsoft.Open.AzureAD.Model.ResourceAccess" -ArgumentList "741f803b-c850-494e-b5df-cde7c675a1ca","Role"
$acc5 = New-Object -TypeName "Microsoft.Open.AzureAD.Model.ResourceAccess" -ArgumentList "df021288-bdef-4463-88db-98f22de89214","Role"
$acc6 = New-Object -TypeName "Microsoft.Open.AzureAD.Model.ResourceAccess" -ArgumentList "7ab1d382-f21e-4acd-a863-ba3e13f7da61","Role"
$acc7 = New-Object -TypeName "Microsoft.Open.AzureAD.Model.ResourceAccess" -ArgumentList "19dbc75e-c2e2-444c-a770-ec69d8559fc7","Role"
$req.ResourceAccess = $acc1,$acc2,$acc3,$acc4,$acc5,$acc6,$acc7
$req.ResourceAppId = "00000003-0000-0000-c000-000000000000"

Add the item to the Azure App registration.

##################################
### Create an RequiredResourceAccess list
##################################
$requiredResourceAccessItems = New-Object System.Collections.Generic.List[Microsoft.Open.AzureAD.Model.RequiredResourceAccess]
$requiredResourceAccessItems.Add($req)
Set-AzureADApplication -ObjectId $myApp.ObjectId -RequiredResourceAccess $requiredResourceAccessItems

Access tokens version 2 are used. This needs to be set in the manifest. This property is called accessTokenAcceptedVersion in the portal and requestedAccessTokenVersion in Graph. Set the accessTokenAcceptedVersion to version 2 access tokens.

$Body = @{
    api = @{
        requestedAccessTokenVersion = 2
    }
} | ConvertTo-Json -Compress | ConvertTo-Json
$null = az rest --method PATCH --uri "https://graph.microsoft.com/v1.0/applications/$($appRegObjectId)" --body $Body --headers "Content-Type=application/json"

Running the scripts

Install the required Azure AD Powershell module:

Install-Module AzureAD -AllowClobber

Connect to the correct tenant using an account which has the privileges to create App registrations:

Connect-AzureAD -TenantId 5698af84-5720-4ff0-bdc3-9d9195314244

Run the script replacing the tenantId and your Azure App Registration name:

.\app-reg-application-cc.ps1 -tenantId 5698af84-5720-4ff0-bdc3-9d9195314244 -appName AppRegTest

Login Azure CLI and Update access token version

az login --tenant 5698af84-5720-4ff0-bdc3-9d9195314244

You can read the id from the manufest (ObjectId) “id”: “ba62783f-fb6b-48a9-ba51-f56355e84926”,

.\update-access-token-version2.ps1 -TenantId 5698af84-5720-4ff0-bdc3-9d9195314244 -appRegObjectId ba62783f-fb6b-48a9-ba51-f56355e84926

Create new secret

You can read the id from the manufest (ObjectId) “id”: “ba62783f-fb6b-48a9-ba51-f56355e84926”,

.\app-new-secrets.ps1 -TenantId 5698af84-5720-4ff0-bdc3-9d9195314244 -appRegObjectId ba62783f-fb6b-48a9-ba51-f56355e84926

See the full scripts in the Github repository accompanying this blog.

Notes

We are using secrets in this demo. You can also update to using certificates instead of secrets which then use client assertions on the access token request. I normal store the secret or certificate in an Azure Key Vault and use this directly from the application and services. I would normally add this to DevOps and create a single script for all infrastructure.

After the App registrations have been created, you need to grant consent before these can be used.

Links:

https://docs.microsoft.com/en-us/powershell/module/azuread/new-azureadapplication?view=azureadps-2.0

https://stackoverflow.com/questions/42164581/how-to-configure-a-new-azure-ad-application-through-powershell

4 comments

  1. […] Create Azure App Registration for API using Powershell (Damien Bowden) […]

  2. […] Create Azure App Registration for API using Powershell – Damien Bowden […]

  3. I see you using azure ad module, but AZ.resources also contains methodz with similar actions.
    It is not clear to me which one to use, as I would assume AZ.resources is the way to go and I thoughts to have Read azuread module is deprecated end of 2023?

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.