How to create scope using Azure CLI (az ad app)

6.5k Views Asked by At

Using the Azure CLI 2.x, I cannot find a way to "add a Scope" under the expose an API section in Azure AD Portal.

enter image description here

What I do see is if I pass the --identifier-uris when the app is created, the APP ID URI and a Scope get automatically set:

    `az ad app create --display-name "$appName" --identifier-uris "https://$tenantDomain/$appName" --reply-urls "$replyUrl" --oauth2-allow-implicit-flow true`

enter image description here

Not what I expected nor what I want

So, I removed --identifier-urls from the create command and added the scope I wanted in manually. then I see via manifest what I'm looking for under OAuth2Permissions as shown below. Can I put this in manifest.json with a new guid and insert it somehow?

enter image description here

What CLI command supports the explicit support to define a Scope? Then Adding a Client application I would need to select the defined Scope, how is this referenced?

Documentation is very sparse, IMO. This reference is very helpful but nothing in here talks about adding scopes and clients. https://learn.microsoft.com/en-us/cli/azure/ad?view=azure-cli-latest. Any help towards samples or documentation much appreciated.

6

There are 6 best solutions below

0
user2503078 On BEST ANSWER

With help from the thread above, and a ton of trial-n-error plus a pretty useful link, I was able to work out the CLI script to add scope using a windows environment. PowerShell is not happy with 'jq' on windows and use of the back-tick had to be removed to get things working. Now I need to solve adding preAuthorizedApplication with the CLI.

$userAccessScopeApi = '{
    "lang": null,
    "origin": "Application",        
    "adminConsentDescription": "Access CP Debug desc",
    "adminConsentDisplayName": "Access CP Debug",
    "id": "--- replaced in scripts ---",
    "isEnabled": true,
    "type": "Admin",
    "userConsentDescription": null,
    "userConsentDisplayName": null,
    "value": "Access"
}' | ConvertTo-Json | ConvertFrom-Json
`

Write-Host " -  1 read oauth2permissions"
#(az ad app show  --id $appid)
$appjson = (az ad app list --display-name $appName)         
$app = $appjson | ConvertFrom-Json
$oauth2Permissions = $app.oauth2Permissions
$oauth2Permissions[0].isEnabled = 'false'

$oauth2Permissionsjson = ConvertTo-Json -InputObject @($oauth2Permissions) 

Write-Host " -  2 disable oauth2Permission in Azure App Registration"
$oauth2Permissionsjson | Out-File -FilePath .\oauth2Permissionsold.json
az ad app update --id $appId --set [email protected]

Write-Host " -  3 delete the default oauth2Permission"
az ad app update --id $appId --set oauth2Permissions='[]'

Write-Host " -  4 add the new scope required add the new oauth2Permissions values"
$oauth2PermissionsApiNew = $userAccessScopeApi | ConvertFrom-Json
$oauth2PermissionsApiNew[0].id = New-Guid
$oauth2PermissionsApiNew = ConvertTo-Json -InputObject @($oauth2PermissionsApiNew) 

# Write-Host "new oauth2permissions : " + $oauth2PermissionsApiNew" 
$oauth2PermissionsApiNew | Out-File -FilePath .\oauth2Permissionsnew.json
az ad app update --id $appId --set [email protected]

Write-Host " - Updated scopes (oauth2Permissions) for App Registration: $appId"`
7
Thomas On

From this article Azure CLI: Create an Azure AD application for an API that exposes OAuth2 Permissions

You can use the az ad app update command (see documentation)

You can then set an application’s property by using the optional parameter –set

  1. Create a oauth2-permissions.json containing the permission:

    [
      {
        "adminConsentDescription": "Access CP Debug Desc",
        "adminConsentDisplayName": "Access CP Debug",
        "id": "85b8f1a0-0733-47dd-9af4-cb7221dbcb73",
        "isEnabled": true,
        "type": "Admin",
        "userConsentDescription": null,
        "userConsentDisplayName": null,
        "value": "Access"
      }
    ]
    
  2. Run this script, it will create the app, disable the existing scope and add the new scope:

    # Create the app registration
    APP_REG=$(az ad app create --display-name myapi --identifier-uris https://myapi)
    
    # Get the app id
    APP_ID=$(echo $APP_REG | jq -r '.appId')
    
    # disable default exposed scope
    DEFAULT_SCOPE=$(az ad app show --id $APP_ID | jq '.oauth2Permissions[0].isEnabled = false' | jq -r '.oauth2Permissions')
    az ad app update --id $APP_ID --set oauth2Permissions="$DEFAULT_SCOPE"
    
    # Create new scopes from file 'oath2-permissions'
    az ad app update --id $APP_ID --set [email protected]
    
2
A2AdminGuy On

As of 7/29/22 the latest Azure CLI command "az ad app update" does not include the oauth2permissions anymore. If you try the above, you will bang you head and hopefully find this post. The new location of these permissions on the app regs are located at api.oauth2PermissionScopes as an array.

In order to get around this I used a combination of a few items from this post and had to get creative as the Azure docs are also still incorrect.

It still stands true that if you have an existing API exposed, you have to disable it to modify the scopes. If you have a fresh app registration you can apply this direct without issue. Hopefully this helps someone like me that has automations that are now broken due to the changes to how apps are registered and the manifest changes. If you don't know about changes to app registrations, I recommend you review. If you got this far though, I assume you already did.

# Add API Read Scope: 
$scopeGUID = [guid]::NewGuid()
$scopeJSONHash = @{
    adminConsentDescription="$apiName on $svrAppRegName"
    adminConsentDisplayName="$apiName on $svrAppRegName" 
    id="$scopeGUID"
    isEnabled=$true
    type="User"
    userConsentDescription="$apiName on $svrAppRegName"
    userConsentDisplayName="$apiName on $svrAppRegName"
    value="$apiName"
}
$azAppOID = (az ad app show --id $serverApplicationId | ConvertFrom-JSON).id
$accesstoken = (Get-AzAccessToken -Resource "https://graph.microsoft.com/").Token
$header = @{
    'Content-Type' = 'application/json'
    'Authorization' = 'Bearer ' + $accesstoken
}
$bodyAPIAccess = @{
    'api' = @{
        'oauth2PermissionScopes' = @($scopeJSONHash)
    }
}|ConvertTo-Json -d 3

#You can try az rest, I used Invoke-RestMethod though.
#$graphURL="https://graph.microsoft.com/v1.0/applications/$azAppOID" 
#az rest --method PATCH --uri $graphurl --headers $header --body $bodyAPIAccess

Invoke-RestMethod -Method Patch -Uri "https://graph.microsoft.com/v1.0/applications/$azAppOID" -Headers $header -Body $bodyAPIAccess
1
Kelvis Zangrossi On

As A2AdminGuy mentioned, it is not possible to update the oauth2Permissions direct anymore, but you can still use az ad app update.

  1. Execute the command az ad app show --id $appClientId and you will see that the oauth2PermissionScopes is inside the api now:
"api": {
    "acceptMappedClaims": null,
    "knownClientApplications": [],
    "oauth2PermissionScopes": [],
    "preAuthorizedApplications": [],
    "requestedAccessTokenVersion": null
}
  1. You need to update the api property to be able to set the oauth2PermissionScopes:
$apiScopeId = [guid]::NewGuid().Guid
$apiScopeJson = @{
    requestedAccessTokenVersion = 2
    oauth2PermissionScopes      = @(
        @{
            adminConsentDescription = "$AppName on $EnvironmentAbbrev"
            adminConsentDisplayName = "$AppName on $EnvironmentAbbrev"
            id                      = "$apiScopeId"
            isEnabled               = $true
            type                    = "User"
            userConsentDescription  = "$AppName on $EnvironmentAbbrev"
            userConsentDisplayName  = "$AppName on $EnvironmentAbbrev"
            value                   = "authenticate"
        }
    )
} | ConvertTo-Json -d 4 -Compress

$apiUpdateBody = $apiScopeJson | ConvertTo-Json -d 4

az ad app update --id $apiClientId --set api=$apiUpdateBody --verbose

The --verbose parameter can be removed, but interestingly, the update command is a PATH request to the graph API.

Since it is a PATH request, you don't always need to send the whole api property, you can do two requests to update different properties and the previous one will not be affected.

  1. This is how you can update a SPA redirectUris:
$appSpaJson = @{
    redirectUris = @("http://localhost:3000")
} | ConvertTo-Json -d 3 -Compress
    
$appUpdateBody = $appSpaJson | ConvertTo-Json -d 4

az ad app update --id $appClientId --set spa=$appUpdateBody
3
Jaime Still On

Here's the approach I ended up with in bash on WSL Ubuntu, in the event it's useful for anyone else:

# replace all <value> blocks with your own value

# create app registration and extract appId
clientid=$(az ad app create \
    --display-name <name> \
    --query appId \
    --output tsv)

# generate a UUID for the scope
uuid=$(uuidgen)

# set the API object as a JSON object
api=$(echo '{
    "acceptMappedClaims": null,
    "knownClientApplications": [],
    "oauth2PermissionScopes": [{
        "adminConsentDescription": "<description>",
        "adminConsentDisplayName": "<name>",
        "id": "'$uuid'",
        "isEnabled": true,
        "type": "User",
        "userConsentDescription": "<description>",
        "userConsentDisplayName": "<name>",
        "value": "<value>"
    }],
    "preAuthorizedApplications": [],
    "requestedAccessTokenVersion": 2
}' | jq .)

# Update app registration with App ID URL and api object
az ad app update \
    --id $clientid \
    --identifier-uris api://$clientid \
    --set api="$api"
0
Mark On

Here is the command that worked for me:

az ad app update --id ... --set [email protected]

And the contents of payload.json:

{
  "oauth2PermissionScopes": [
    {
      "adminConsentDescription": "Authenticate",
      "adminConsentDisplayName": "Authenticate",
      "id": "3c8d0da4-8000-49ab-b406-e2d601a12900",
      "isEnabled": true,
      "type": "User",
      "value": "Authenticate"
    }
  ]
}

As an aside, before I wrote this answer, I tried many different strategies based on the varied answers to this question, but here's a list of things that didn't work for me:

  • az update --id ... --set api.oauth2PermissionScopes=...: despite the documentation claiming this notation might work, I could not find a way to set nested properties.
  • az update --id ... --set api='{"oauth2PermissionScopes":[...]}': this is likely some type of shell quoting issues, but the @-file reference was the only way I could get the payload to take.
  • az update -id ... --set oauth2Permissions=...: I believe this strategy conflates the name of this property in the app manifest with the name of the property in the underlying MS Graph API call request body.

That being said, understanding that the --set flag is for setting the top-level properties (again, I never got nesting to work) of a request body to a PATCH call was the key for me. And since it's a PATCH, sending partial bodies is fine and won't blow away existing settings. For example, even though I believe there's flag for this, you can do:

az update -id ... --set displayName=blah

In the end, I find the az ad app update --set command to provide a tiny but of sugar over a direct API call with az rest.