9

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.

Thomas
  • 24,234
  • 6
  • 81
  • 125
user2503078
  • 737
  • 1
  • 8
  • 24

5 Answers5

10

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
A2AdminGuy
  • 101
  • 1
  • 5
  • This is now the correct answer! Thanks - helped a lot. For others finding this - note the singular 'Permission' in 'oauth2PermissionScopes' (instead of the old 'oauth2permissions' plural). Got caught on this one – Joel Nation Aug 03 '22 at 06:47
5

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 oauth2Permissions=@oauth2-permissions.json
    
Thomas
  • 24,234
  • 6
  • 81
  • 125
  • Hi, this looks promising. However, this line $DEFAULT_SCOPE=$(az ad app show --id $appId | jq '.oauth2Permissions[0].isEnabled = false' | jq -r '.oauth2Permissions') Fails with jq : The term 'jq' is not recognized as the name of a cmdlet, function, script file, or .... I'll see if there's another way. – user2503078 Jun 30 '20 at 22:52
  • Are you running on windows or linux ? `jq` is a json query package for bash/shell https://stedolan.github.io/jq/ – Thomas Jun 30 '20 at 23:08
  • Running on windows. I'm looking for an equivalent – user2503078 Jun 30 '20 at 23:20
  • if you use powershell `ConvertTo-Json` and `ConvertFrom-Json`, it should do the trick ? – Thomas Jun 30 '20 at 23:38
  • If I know what to change, am i simply setting IsEnabled to false in the OAuthPermissions and then passing that JSON (the entire thing) back in the set? I can isolate the JSON block with this command : az ad app list --display-name $appName --query [].oauth2Permissions[0] – user2503078 Jun 30 '20 at 23:54
  • yeah it is to disable the default scope before creating a new one – Thomas Jul 01 '20 at 00:46
  • Hi, can you shoot me what the DEFAULT_SCOPE looks like from the original code? I assumed it was either the entire app or the oauth2permissions block but nothing works. I get deserialize errors like this "Unable to build a model: Cannot deserialize as [OAuth2Permission] an object of type , DeserializationError: Cannot deserialize as [OAuth2Permission] an object of type . Looked in the docs but it doesn't come close to telling anyone. Have you run this code successfully? – user2503078 Jul 01 '20 at 12:57
3

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
2

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 oauth2Permissions=@oauth2Permissionsold.json

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 oauth2Permissions=@oauth2Permissionsnew.json

Write-Host " - Updated scopes (oauth2Permissions) for App Registration: $appId"`
user2503078
  • 737
  • 1
  • 8
  • 24
2

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"
Jaime Still
  • 1,949
  • 20
  • 31
  • 2
    This was helpful but worth noting that content of the api property must include all that's required. So, if run against an existing app reg that already has permission scopes errors will be raised if those scopes are not first disabled – Rob Bowman Mar 03 '23 at 16:14
  • @RobBowman good to know, thanks for the heads up. I've been purely using this in the context of generating new app registrations. – Jaime Still Mar 03 '23 at 16:59