Adding Scopes to Azure AD Application with Powershell (Expose an API) - azure

I'd like to add a Scope to an Azure AD App / Service Principal (UI=Expose an API) with Powershell.
$app = New-MgApplication -DisplayName $name -SignInAudience "AzureADMyOrg"
Update-MgApplication -ApplicationId $app.id -IdentifierUris #("api://$($app.AppId)")
$oauth_permission_scopes = #{
AdminConsentDescription = "admin desc"
AdminConsentDisplayName = "admin name"
Type = "Admin"
Value = "Read.all"
Id = $([guid]::NewGuid())
}
$sp = New-MgServicePrincipal -AppId $app.AppId -Notes $description -Tags #("HideApp","WindowsAzureActiveDirectoryIntegratedApp") #HideApp=VisibleToUsers
Update-MgServicePrincipal -ServicePrincipalId $sp.Id -Oauth2PermissionScopes $oauth_permission_scopes
But i get the message:
Update-MgServicePrincipal_UpdateExpanded1: Property 'oauth2PermissionScopes' is read-only and cannot be set.
Can this only be added in the UI?!

I tried to reproduce the same in my environment and got below results:
I ran the same code as you to add scopes and got same error as below:
When I checked the same in Portal, application is created but scope not added like below:
To add scope to Azure AD Application with PowerShell (Expose an API), you need to modify your script as suggested by Cpt.Whale like this:
$api = #{
oauth2PermissionScopes = #(
#{
AdminConsentDescription = "admin desc"
AdminConsentDisplayName = "admin name"
Type = "Admin"
Value = "Read.all"
Id = $([guid]::NewGuid())
}
)
}
Update-MgApplication -ApplicationId $app.id -Api $api
Response:
When I checked the same in Portal, scope added successfully in Expose an API tab of Azure AD application as below:

Related

Invoke-RestMethod :unauthorized client for getting Authentication-token

I have created app registration in azure active directory. I'm trying to invoke an azure ad authenticated with below PowerShell script, but it always display an error:
$clientID = '<clientID>'
$secretKey = '<key>'
$tenantID = '<TenantID>'
$password = ConvertTo-SecureString -String $secretKey -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential($ClientID,$password)
Connect-AzureRmAccount -ServicePrincipal -Credential $credential -Tenant $tenantID
$authUrl = "https://login.microsoftonline.com/" + $tenantID + "/oauth2/v2.0/token/"
$body = #{
"scope" = "api://a193b314b-7854-9aab-bb78-6a50ffxxxxxx/";
"grant_type" = "client_credentials";
"client_id" = $ClientID
"client_secret" = $secretKey
}
Write-Output "Getting Authentication-Token"
$adlsToken = Invoke-RestMethod -Uri $authUrl –Method POST -Body $body
Write-Output $adlsToken
I am getting this error. please make me to understand Why I am getting this error
Invoke-RestMethod:
{"error":"invalid_scope","error_description":"AADSTS1002012: The provided value for scope api://3e3643c5-90af-ece is not valid. Client credential flows must have a scope value with /.default suffixed to the resource identifier (application ID URI).\r\nTrace ID:2d4f23bf-b317-4d5c-b5xxxxx\r\nCorrelation ID:fe5945b4-b2c2-4814-9xxxxxxx\r\nTimestamp:04:26:09Z","error_codes":[1002012],"timestamp":"2022-11-19
04:26:09Z","trace_id":"2d4f23bfb3174d5cb5a7xxxxxxx","correlation_id":"fe5945b4-b2c2-4814-99xxxxxxxx"}
Connect-AzAccount: ClientSecretCredential authentication failed:
AADSTS700016: Application with identifier
'3e3643c5-90af-4af6-afxxxxxxx' was not found in the directory 'Default
I tried to reproduce the same in my environment I got the same error as below:
To resolve this issue, check whether you are providing correct ClientID as below:
And, In scope the error mention you have missed /.default Make sure to include /.default like below:
"api://xxxxxx/.default";
When I ran the same script along with scope default, I got the Result successfully like below:
Can you try this by adding .default in scope,
"scope" = "api://a193b314b-7854-9aab-bb78-6a50ffxxxxxx/.default"
If it works, see the reference.

How to add a scope and ApplicationURI to Azure AD Application Registration?

I have a powershell script that creates an azure ad app reg. I've been able to create it, add ms graph permissions and also create a secret. This is what I have so far:
$newapp = New-AzADApplication -DisplayName "mynewApp" -AvailableToOtherTenants $false
Write-Output $newapp
# add a certificate / client secret
$appCredentials = New-AzADAppCredential -ApplicationId $newapp.AppId -StartDate $startDate -EndDate $endDate
$identifierUris = #()
$identifierUris += "api://$newapp.AppId"
$webAppUrl = "https://$functionAppName.azurewebsites.net"
# when you add a redirect URI Azure creates a "web" policy.
$redirectUris = #()
$redirectUris += "$webAppUrl"
Update-AzADApplication -ApplicationId $newapp.AppId -ReplyUrl $redirectUris | Out-Null
#Adds MS Graph User.Read permission
Add-AzADAppPermission -ApplicationId $newapp.AppId -ApiId "00000003-0000-0000-c000-000000000000" -PermissionId "e1fe6dd8-ba31-4d61-89e7-88639da4683d"
But now I need to know how to create the application Uri as depicted below, and also how to create the scope.
You can use New-AzureADApplication command with following parameters
To add Identifier URI - Use -IdentifierUris parameter.
To add Scope - Use -Oauth2Permissions parameter.
New-AzureADApplication
[-AvailableToOtherTenants <Boolean>]
-DisplayName <String>
[-IdentifierUris <System.Collections.Generic.List`1[System.String]>]
[-Oauth2Permissions <System.Collections.Generic.List`1[Microsoft.Open.AzureAD.Model.OAuth2Permission]>]
[-ReplyUrls <System.Collections.Generic.List`1[System.String]>]
[-RequiredResourceAccess <System.Collections.Generic.List`1[Microsoft.Open.AzureAD.Model.RequiredResourceAccess]>]
For example you can create OAuth2Permission object like -
$scope = New-Object Microsoft.Open.AzureAD.Model.OAuth2Permission
$scope.Id = New-Guid
$scope.Value = "user_impersonation"
$scope.UserConsentDisplayName = "<value>"
$scope.UserConsentDescription = "<value>"
$scope.AdminConsentDisplayName = "<value>"
$scope.AdminConsentDescription = "<value>"
$scope.IsEnabled = $true
$scope.Type = "User"
Please refer this documentation for details.
Please check below command to create ApplicationId Uri ,
$newapp = New-AzADApplication -DisplayName "mynewApp" -AvailableToOtherTenants $false
$myappId=$newApp.AppId
Set-AzADApplication -ApplicationId $newApp.AppId -IdentifierUris "api://$myappId"
It may take little time to reflect in portal.
but to create scope , we may need to use azure ad module, and create a new id for user impersonation by enabling Oauth2permissions
please check if references can help
SetupApplications ps1
azure-ad-app-registration-create-scopes
Had similar problem with Azure Application Registration scopes. Here is a simplest solution I have with Az Powershell:
$app = Get-AzAdApplication -ApplicationId "app_guid_here"
$permissionScope = New-Object Microsoft.Azure.Powershell.Cmdlets.Resources.MSGraph.Models.ApiV10.MicrosoftGraphPermissionScope
$permissionScope.Id = New-Guid
$permissionScope.AdminConsentDescription = "text_here"
$permissionScope.AdminConsentDisplayName = "text_here"
$permissionScope.IsEnabled = $true
$permissionScope.Type = "Admin" #Or "User"
$permissionScope.UserConsentDescription = "text_here"
$permissionScope.UserConsentDisplayName = "text_here"
$permissionScope.Value = "user_impersonation"
$api = $app.Api
$api.Oauth2PermissionScope = $permissionScope
Update-AzADApplication -ApplicationId $appId -Api $api

Getting the Secret of a Service Prinicpal in YAML Pipeline (Terraform)

I need to do an Invoke-SQLCmd in Terraform - all fine BUT I need to get the Secret for the service principal (Azure) that is being used throughout the build. So I can use this :
Import-Module SQLServer
# Note: the sample assumes that you or your DBA configured the server to accept connections using
# that Service Principal and has granted it access to the database (in this example at least
# the SELECT permission).
$clientid = "enter application id that corresponds to the Service Principal" # Do not confuse with its display name
$tenantid = "enter the tenant ID of the Service Principal"
$secret = "enter the secret associated with the Service Principal"
$request = Invoke-RestMethod -Method POST `
-Uri "https://login.microsoftonline.com/$tenantid/oauth2/token"`
-Body #{ resource="https://database.windows.net/"; grant_type="client_credentials"; client_id=$clientid; client_secret=$secret }`
-ContentType "application/x-www-form-urlencoded"
$access_token = $request.access_token
# Now that we have the token, we use it to connect to the database 'mydb' on server 'myserver'
Invoke-Sqlcmd -ServerInstance myserver.database.windows.net -Database mydb -AccessToken $access_token`
-query 'select * from Table1'
I can get the cliendId and the TenantID quite easily within PowerShell but I cannot get the secret. So how would i get it ? although i am using the same Service Prinical during the build.
As I have already mentioned you can only retrieve a secret value at the time of creation and after that it becomes hidden . So , its recommended to store the created in some secure place or keyvault.
As you can see for testing I used AzureAD Module and the below script :
## Get APP Details
$APP=Get-AzureADApplication -Filter "DisplayName eq 'ansumanterraformtest'"
## ClientID
Write-Host("clientID : ")$APP.AppId
##TenantID
$tenantID=(Get-AzureADTenantDetail).objectId
Write-Host ("TenantID :")$tenantID
## Get Secret
$getsecret=Get-AzureADApplicationPasswordCredential -ObjectId $APP.ObjectId
if($getsecret.value -ne $null){
Write-Host ("Exisitng $get Secret Value: ")$getsecret.Value
}
else{
Write-Host ("Cannot Retrieve Secret!!!!")
}
Output:
So , As a solution we can create a new secret and retrieve if you don't have it stored in anywhere like below:
$end_date = (get-date).Date.AddDays(365)
## Create new Secret
$createsecret = New-AzureADApplicationPasswordCredential -CustomKeyIdentifier "PowershellKey" -ObjectId $APP.ObjectId -EndDate $end_date
## Secret Value
Write-Host ("Secret Value For new Secret :")$createsecret.value
Output:

I would like to give admin consent to API permissions through powershell script

I have a code in Az module of powershell to create appID, app secret and assign API permission. How do I grant admin consent to all the API permissions that I assigned to the AzApp?
...
$context = Get-AzContext
$ResourceAppIdURI = "https://graph.windows.net/"
$token = [Microsoft.Azure.Commands.Common.Authentication.AzureSession]::Instance.AuthenticationFactory.Authenticate($context.Account, $context.Environment, $context.Tenant.Id.ToString(), $null, [Microsoft.Azure.Commands.Common.Authentication.ShowDialog]::Never, $null, $ResourceAppIdURI).AccessToken
$headers = #{ }
$headers.Add("Content-Type", "application/json")
$headers.Add("Accept", "application/json")
$headers.Add("Authorization", "Bearer $($token)")
$objectID = $myApp.ObjectId
$url = "https://graph.windows.net/$tenant/applications/{0}?api-version=1.6" -f $objectID
Write-Host "URL: " $url
$postData = "{`"requiredResourceAccess`":[
{`"resourceAppId`":`"00000003-0000-0000-c000-000000000000`",
`"resourceAccess`":[
{`"id`":`"e1fe6dd8-ba31-4d61-89e7-88639da4683d`",`"type`":`"Scope`"},
{`"id`":`"7ab1d382-f21e-4acd-a863-ba3e13f7da61`",`"type`":`"Role`"},
{`"id`":`"5b567255-7703-4780-807c-7be8301ae99b`",`"type`":`"Role`"},
{`"id`":`"e2a3a72e-5f79-4c64-b1b1-878b674786c9`",`"type`":`"Role`"},
{`"id`":`"df021288-bdef-4463-88db-98f22de89214`",`"type`":`"Role`"}
]
}]
}";
Invoke-RestMethod -Uri $url -Method "PATCH" -Headers $headers -Body $postData
Write-Host "App created..."
Write-Host "AppID: " $myApp.ApplicationId
Write-Host "App Secret: " $secret
Write-Host "TenantID: " $tenant.Id
There is no API exposed by Microsoft to grant admin consent for Azure AD application / service principal. You can vote this post on User Voice.
There is a workaround:
Call Microsoft Graph API Create a delegated permission grant and Grant an appRoleAssignment to a service principal in Powershell.
A sample for your reference:
$context = Get-AzContext
$ResourceAppIdURI = "https://graph.windows.net/"
$ResourceGraphURI = "https://graph.microsoft.com/"
$token = [Microsoft.Azure.Commands.Common.Authentication.AzureSession]::Instance.AuthenticationFactory.Authenticate($context.Account, $context.Environment, $context.Tenant.Id.ToString(), $null, [Microsoft.Azure.Commands.Common.Authentication.ShowDialog]::Never, $null, $ResourceAppIdURI).AccessToken
$graphToken = [Microsoft.Azure.Commands.Common.Authentication.AzureSession]::Instance.AuthenticationFactory.Authenticate($context.Account, $context.Environment, $context.Tenant.Id.ToString(), $null, [Microsoft.Azure.Commands.Common.Authentication.ShowDialog]::Never, $null, $ResourceGraphURI).AccessToken
$clientID = "d154cc56-f1a2-4906-9f26-bfb4756f9c20"
$resourceID = "08a1faff-51c1-4cbb-81c4-1bc11286da76"
$scopes = "Sites.Read.All User.Read User.Read.All User.ReadBasic.All"
$body = #{
clientId = $clientID
consentType = "AllPrincipals"
principalId = $null
resourceId = $resourceID
scope = $scopes
startTime = "2019-10-19T10:37:00Z"
expiryTime = "2020-10-19T10:37:00Z"
}
$apiUrl = "https://graph.microsoft.com/beta/oauth2PermissionGrants"
Invoke-RestMethod -Uri $apiUrl -Headers #{Authorization = "Bearer $($graphToken)" } -Method POST -Body $($body | convertto-json) -ContentType "application/json"
$principalId = "d154cc56-f1a2-4906-9f26-bfb4756f9c20"
$body1 = #{
principalId = $principalId
resourceId = $resourceID
appRoleId = "df021288-bdef-4463-88db-98f22de89214"
}
$apiUrl1 = "https://graph.microsoft.com/beta/servicePrincipals/$($principalId)/appRoleAssignedTo"
Invoke-RestMethod -Uri $apiUrl1 -Headers #{Authorization = "Bearer $($graphToken)" } -Method POST -Body $($body1 | convertto-json) -ContentType "application/json"
For the first call https://graph.microsoft.com/beta/oauth2PermissionGrants:
clientID is the object id of the service principal (not Azure AD application), you can find it using Get-AzADServicePrincipal. You can also find it on Azure Portal - Azure Active Directory - Enterprise Applications, search for the name of your Azure AD application.
resouceID is the object id of Microsoft Graph service principal. You can find under Enterprise applications (search for "00000003-0000-0000-c000-000000000000").
scopes are the delegated permissions you want to grant admin consent.
For the second call https://graph.microsoft.com/beta/servicePrincipals/$($principalId)/appRoleAssignedTo:
principalId is the same as clientID mentioned above.
appRoleId is the application permission id.
Actually, the Azure AD PowerShell module provides a cmdlet equivalent for Application Permissions : New-AzureADServiceAppRoleAssignment.
Even if it's poorly documented, the command adds the requested application permissions (and grant admin consent if you have the right to do so) to your AAD Application (through the service principal).
# If it's not the case, declare your AAD Application as a service principal (Enterprise Application)
$aadappsp = New-AzureADServicePrincipal -AppId "AAD_APPLICATION_ID"
# Id of the application permission (role)
$roleId = "2a8d57a5-4090-4a41-bf1c-3c621d2ccad3" # TermStore.Read.All
# Object Id of the concerned Service Principal (could be Graph or SharePoint for example)
# (Not the Application Id like "00000003-0000-0ff1-ce00-000000000000" for SharePoint)
$aadSpObjectId = "c30e8a24-ff90-464e-aed3-7c39a7bdc280"
# Register the application permission
New-AzureADServiceAppRoleAssignment -ObjectId $aadappsp.ObjectId -Id $roleId -PrincipalId $aadappsp.ObjectId -ResourceId $aadSpObjectId
It's using a dedicated endpoint, so don't be surprised if you have this display once the command correctly executed:
(permissions added through PowerShell appear as "Other permissions granted for...")
To avoid that, you have to first add them through interface or with New-AzureADApplication (to register the permissions as "configured") and New-AzureADServicePrincipal (to grant admin consent properly for your organization).
Sadly, there's no cmdlet for granting admin consent on Delegated Permissions, so the answer provided by #Allen Wu still works in this case (just update the URIs to use v1.0 version instead of beta).

Authorize Azure Function Event Grid Trigger through Azure AD B2C

I have an Azure Event Grid Trigger Inside my Function's App. The Function is subscribed to Event Grid Topic through an Event Subscription. The Function works perfectly and is triggered when I have no Authentication Configured inside the Authentication / Authorization Blade of the Functions App. But when I integrate B2C AD App from the Blade, the topic is not delivered and the function is not triggered. Also, I can see "Unauthorized" Errors inside the Event Subscription. The B2C Flow is required for other HTTP triggers inside the Function App. How can I give exclusive access to the Event Grid so that this message is delivered without the B2C Flow?
You can try below approach:
Enable Event Grid to use your Azure AD Application:
Use the PowerShell script below in order to create a role and service principal in your Azure AD Application. You will need the Tenant ID and Object ID from your Azure AD Application:
Modify the PowerShell script's $myTenantId to use your Azure AD
Tenant ID.
Modify the PowerShell script's $myAzureADApplicationObjectId to use the Object ID of your Azure AD Application.
Run the modified script.
$myTenantId = "<the Tenant Id of your Azure AD Application>"
Connect-AzureAD -TenantId $myTenantId
$myAzureADApplicationObjectId = "<the Object Id of your Azure AD Application>"
$eventGridAppId = "4962773b-9cdb-44cf-a8bf-237846a00ab7"
$eventGridRoleName = "AzureEventGridSecureWebhook"
Function CreateAppRole([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
}
$myApp = Get-AzureADApplication -ObjectId $myAzureADApplicationObjectId
$myAppRoles = $myApp.AppRoles
$eventGridSP = Get-AzureADServicePrincipal -Filter ("appId eq '" + $eventGridAppId + "'")
Write-Host "App Roles before addition of new role.."
Write-Host $myAppRoles
if ($myAppRoles -match $eventGridRoleName)
{
Write-Host "The Azure Event Grid role is already defined.`n"
}
else
{
$myServicePrincipal = Get-AzureADServicePrincipal -Filter ("appId eq '" + $myApp.AppId + "'")
$newRole = CreateAppRole -Name $eventGridRoleName -Description "Azure Event Grid Role"
$myAppRoles.Add($newRole)
Set-AzureADApplication -ObjectId $myApp.ObjectId -AppRoles $myAppRoles
}
if ($eventGridSP -match "Microsoft.EventGrid")
{
Write-Host "The Service principal is already defined.`n"
}
else
{
$eventGridSP = New-AzureADServicePrincipal -AppId $eventGridAppId
}
New-AzureADServiceAppRoleAssignment -Id $myApp.AppRoles[0].Id -ResourceId $myServicePrincipal.ObjectId -ObjectId $eventGridSP.ObjectId -PrincipalId $eventGridSP.ObjectId
Write-Host "My Azure AD Tenant Id: $myTenantId"
Write-Host "My Azure AD Application Id: $($myApp.AppId)"
Write-Host "My Azure AD Application ObjectId: $($myApp.ObjectId)"
Write-Host "My Azure AD Application's Roles: "
Write-Host $myApp.AppRoles
Configure the event subscription :
In the creation flow for your event subscription, select endpoint type 'Web Hook'. Once you've given your endpoint URI (webhook uri of event grid endpoint - https://FUNCTION_DOMAIN/runtime/webhooks/eventgrid?functionName={FUNCTION_NAME}), click on the additional features tab at the top of the create event subscriptions blade.
In the additional features tab, check the box for 'Use AAD authentication' and configure the Tenant ID and Application ID:
Copy the Azure AD Tenant ID from the output of the script and enter
it in the AAD Tenant ID field.
Copy the Azure AD Application ID from the output of the script and
enter it in the AAD Application ID field.
Edit:
For more details about this solution, visit here.

Resources