powershellazure-climicrosoft-entra-idazure-entra-idazure-application-registration

Expose api on an app registration using a script


I have now for a couple of days tried to expose an api on an app registration through az cli, however with no success. I have so far ended with the following:

$clientid=$(az ad app create --display-name ${appregname} --query appId --output tsv)

az ad app permission add --id $clientid --api 00000003-0000-0000-c000-000000000000 --api-permissions e1fe6dd8-ba31-4d61-89e7-88639da4683d=Scope
    
az ad app update --id $clientid --identifier-uris "api://$clientid"
  
az ad sp create --id $clientid --output tsv

az ad app update --id $clientid --set api=@api.json

This is based on many guide and links - to highlight a few I have tried to follow:

But in all cases and my tries I get errors:

I cannot seem to get an understanding of why, I want to achieve app registrations as explained here: https://intility.github.io/fastapi-azure-auth/single-tenant/azure_setup

After click up and comparing manifests with scripted app services I get two areas not looking the same:

For this I tried the above mentioned links with no success how do I configure api and servicePrincipalLockConfiguration when Az ad app update —-id <id> —set and Az ad sp update —-id <id> —set fails in the above cases?

Update

It seems like the root cause is that I cannot add the 'Microsoft Azure CLI' to the tenant I have. Despite using name or the id 04b07795-8ddb-461a-bbee-02f9e1bf7b46, I cannot find it in the entra tenant:

entra overview

FINALLY

with a lot of help it finally worked, being global admin to insert the application with az ad sp create --id 04b07795-8ddb-461a-bbee-02f9e1bf7b46 and Microsoft Azure CLI showed up in the tenant and now everything works!


Solution

  • Note that: The "Expose an API" permissions are located in api.oauth2PermissionScopes as an array. And az ad app update does not include the oauth2permissions. Refer this SO Thread by A2AdminGuy.

    Hence to create the scope and expose an API make use of below script:

    # Step 1: Create an app registration
    $appregname = "RukCliApp"
    $clientid = $(az ad app create --display-name $appregname --query appId --output tsv)
    
    # Step 2: Add API Permissions (Example: Microsoft Graph API)
    az ad app permission add --id $clientid --api 00000003-0000-0000-c000-000000000000 --api-permissions e1fe6dd8-ba31-4d61-89e7-88639da4683d=Scope 
    
    # Step 3: Add the Identifier URI (for API exposure)
    az ad app update --id $clientid --identifier-uris "api://$clientid"
    
    # Step 4: Create the service principal for the app registration
    az ad sp create --id $clientid --output tsv
    
    # Step 5: Generate a new GUID for your API scope (OAuth2 Permission)
    $scopeGUID = [guid]::NewGuid()
    
    # Step 6: Define the permission scope (OAuth2 Permission)
    $permission = @{
        adminConsentDescription = "Allow the app to access API endpoints"
        adminConsentDisplayName = "web_api"
        id = "$scopeGUID"
        isEnabled = $true
        type = "Admin"
        userConsentDescription = "null"
        userConsentDisplayName = "null"
        value = "web_api"
    }
    
    # Step 7: Retrieve the app's object ID using Azure CLI
    $AppObjId = (az ad app show --id $clientid | ConvertFrom-Json).objectId
    
    # Step 8: Get the access token for Microsoft Graph API using Azure CLI
    $accesstoken = (az account get-access-token --resource "https://graph.microsoft.com/" --query "accessToken" -o tsv)
    
    # Step 9: Prepare the headers for the PATCH request to Microsoft Graph
    $header = @{
        'Content-Type' = 'application/json'
        'Authorization' = 'Bearer ' + $accesstoken
    }
    
    # Step 10: Prepare the request body with the new OAuth2 permission scope
    $bodyaccess = @{
        'api' = @{
            'oauth2PermissionScopes' = @($permission)
        }
    } | ConvertTo-Json -Depth 3
    
    # Step 11: Send the PATCH request to update the app registration with the new permission
    Invoke-RestMethod -Method Patch -Headers $header -Uri "https://graph.microsoft.com/v1.0/applications/$AppObjId" -Body $bodyaccess
    
    # Step 12: Verify the update by checking the OAuth2 permissions
    az ad app show --id $clientid --query "oauth2Permissions"
    

    enter image description here

    Application created with Application ID URI and scope:

    enter image description here

    Note: The az ad app create command in its current form adds a user_impersonation scope to expose the application as an API. Hence to remove the default value you need to remove Api permissions and disable default exposed scope first. Refer this MsDoc

    default_scope=$(az ad app show --id $clientid | jq '.oauth2Permissions[0].isEnabled = false' | jq -r '.oauth2Permissions')
    az ad app update --id $clientid --set oauth2Permissions="$default_scope"
    az ad app update --id $clientid --set oauth2Permissions="[]"
    

    As suggested by @bluuf, you can try using Microsoft Graph PowerShell as applications are created in Entra and it's easy to perform actions.

    Connect-MgGraph -Scopes "Application.ReadWrite.All"
    
    # 1. Create the application
    $appregname = "NewCliRukApp"
    $app = New-MgApplication -DisplayName $appregname
    $clientid = $app.AppId
    
    # 2. Add the Directory.Read.All API permission
    $params = @{
        requiredResourceAccess = @(
            @{
                resourceAppId = "00000003-0000-0000-c000-000000000000"  # Microsoft Graph API Resource App ID
                resourceAccess = @(
                    @{
                        id = "d1a8eac6-2f51-4e0a-961f-1e602db39b89"  # Directory.Read.All Scope ID
                        type = "Scope"  # Scope Permission
                    }
                )
            }
        )
    }
    
    # 3. Update the application with the permissions
    Update-MgApplication -ApplicationId $app.Id -BodyParameter $params
    
    # 4. Create service principal
    $servicePrincipal = New-MgServicePrincipal -AppId $clientid
    
    # 5. Update identifierUris (example)
    $identifierUrisParams = @{
        IdentifierUris = @("api://$clientid")  # Example Identifier URI for the app
    }
    Update-MgApplication -ApplicationId $app.Id -BodyParameter $identifierUrisParams
    
    # 6. Set OAuth2 Permission Scopes 
    $oauth2PermissionScopes = @(
        @{
            AdminConsentDescription = "Allow the application to access api to users"
            AdminConsentDisplayName = "test.read"
            Type = "Admin"
            Value = "test.read"
            Id = [guid]::NewGuid()  # Generate a new GUID for the permission scope
        }
    )
    
    $api = @{
        Oauth2PermissionScopes = $oauth2PermissionScopes
    }
    Update-MgApplication -ApplicationId $app.Id -Api $api
    

    enter image description here

    Application created with Application ID URI and with custom scope:

    enter image description here