Use PowerShell to setup AAD Authentication for Business Central APIs

After spending some time trying to play with the Automation APIs for BC it became clear that using the Basic Authentication with Username and Password was not going to work for me.

I have read Vjeko’s article: How do I: Really set up Azure Active Directory based authentication for Business Central APIs and know that navcontainerhelper does setup AAD authentication setup for you.

I will probably have to set this up a few times for colleagues and clients, so I thought that it would save a bit of time in the future if I hacked this script together from Freddy’s work and tested its usage with the help of Vjeko’s article.

Thanks and credit to Vjeko and Freddy for their efforts.

I have it on GitHub here

You will need to install Nuget Package Provider the AzureAD Package (if you dont have them already)

Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force -WarningAction Ignore | Out-Null
Install-Package AzureAD -Force -WarningAction Ignore | Out-Null

You can now use the script below to setup for your BC tenant

$bcAppDisplayName = "BC OAuth 2.0"
$bcSignOnURL      = "https://businesscentral.dynamics.com/"
$bcAuthURL        = "https://login.windows.net/{bcDirectoryId}/oauth2/authorize?resource=https://api.businesscentral.dynamics.com"
$bcAccessTokenURL = "https://login.windows.net/{bcDirectoryId}/oauth2/token?resource=https://api.businesscentral.dynamics.com"

function Create-AesKey {
    $aesManaged = New-Object "System.Security.Cryptography.AesManaged"
    $aesManaged.Mode = [System.Security.Cryptography.CipherMode]::CBC
    $aesManaged.Padding = [System.Security.Cryptography.PaddingMode]::Zeros
    $aesManaged.BlockSize = 128
    $aesManaged.KeySize = 256
    $aesManaged.GenerateKey()
    [System.Convert]::ToBase64String($aesManaged.Key)
}

$AesKey = Create-AesKey

# Login to AzureRm
$AadAdminCredential = Get-Credential
$account = Connect-AzureAD -Credential $AadAdminCredential
$bcDirectoryId = $account.Tenant.Id

#Delete the old one if it is there
Get-AzureADApplication -All $true | Where-Object { $_.DisplayName.Contains($bcAppDisplayName) } | Remove-AzureADApplication

#Create New One
$ssoAdApp = New-AzureADApplication -DisplayName $bcAppDisplayName -Homepage $bcSignOnURL -ReplyUrls ($bcSignOnURL)

# Add a key to the AAD App Properties
$SsoAdAppId = $ssoAdApp.AppId.ToString()
$AdProperties = @{}
$AdProperties["AadTenant"] = $account.TenantId
$AdProperties["SsoAdAppId"] = $SsoAdAppId
$startDate = Get-Date
New-AzureADApplicationPasswordCredential -ObjectId $ssoAdApp.ObjectId `
                                         -Value $AesKey `
                                         -StartDate $startDate `
                                         -EndDate $startDate.AddYears(10) | Out-Null
#
#Set the permissions
#

# Windows Azure Active Directory -> Delegated permissions for Sign in and read user profile (User.Read)
$req1 = New-Object -TypeName "Microsoft.Open.AzureAD.Model.RequiredResourceAccess" 
$req1.ResourceAppId = "00000002-0000-0000-c000-000000000000"
$req1.ResourceAccess = New-Object -TypeName "Microsoft.Open.AzureAD.Model.ResourceAccess" -ArgumentList "311a71cc-e848-46a1-bdf8-97ff7156d8e6","Scope"

# Dynamics 365 Business Central -> Delegated permissions for Access as the signed-in user (Financials.ReadWrite.All)
$req2 = New-Object -TypeName "Microsoft.Open.AzureAD.Model.RequiredResourceAccess" 
$req2.ResourceAppId = "996def3d-b36c-4153-8607-a6fd3c01b89f"
$req2.ResourceAccess = New-Object -TypeName "Microsoft.Open.AzureAD.Model.ResourceAccess" -ArgumentList "2fb13c28-9d89-417f-9af2-ec3065bc16e6","Scope"

Set-AzureADApplication -ObjectId $ssoAdApp.ObjectId -RequiredResourceAccess @($req1, $req2)

#Write out information for the developer
Write-Host "AesKey / Client Secret" $AesKey
Write-Host "Directory Id" $bcDirectoryId
Write-Host "Application Id / Client ID" $ssoAdApp.AppId
Write-Host "Call Back Url" $bcSignOnURL
Write-Host "Auth URL" $bcAuthURL.Replace('{bcDirectoryId}', $bcDirectoryId)
Write-Host "Access Token URL" $bcAccessTokenURL.Replace('{bcDirectoryId}', $bcDirectoryId)

/cal;