Search code examples
azurejwtazure-climicrosoft-entra-id

Authorized Client Applications not working with azure-cli


I have an App Registration (AppId: 00000000-1111-1111-1111-000000000000) with an exposed scope at api://00000000-1111-1111-1111-000000000000/MyData.Read.All.

I can use azure-cli to access this API, logging with my user with:

az login `
    --allow-no-subscriptions `
    --scope 'api://00000000-1111-1111-1111-000000000000/MyData.Read.All'
$accessToken = az account get-access-token `
    --scope 'api://00000000-1111-1111-1111-000000000000/MyData.Read.All' `
    --query accessToken --output tsv

I want to use this API through a Client App, so I registered a second application (AppId: 00000000-2222-2222-2222-000000000000), but can't use it:

az login `
    --allow-no-subscriptions `
    --tenant '00000000-0000-0000-0000-000000000000' `
    --service-principal -u "00000000-2222-2222-2222-000000000000" -p "****" `
    --query accessToken `
    --output tsv
# I can't obtain the below token with the normal exposed scope at "MyData.Read.All"
$accessToken = az account get-access-token `
    --scope 'api://00000000-1111-1111-1111-000000000000/.default' `
    --query accessToken --output tsv

When I make API calls with this token I'm receiving 401 (Unauthorized) codes.

Suprisingly enough, I can't request the token using the exposed scope api://00000000-1111-1111-1111-000000000000/MyData.Read.All if I'm using the Service Principal.

It forces me to use the /.default prefix, even when the Client App is included in the "Authorized client applications" part of the API.

Client credential flows must have a scope value with /.default suffixed to the resource identifier (application ID URI)

Solution

  • Note: When you Expose an API and add a scope, it is considered as delegated API permission.

    • Delegated API permissions work with only user interactive flow.
    • And it does not work with Service principal authentication.
    • For Service principal authentication it needs application type API permissions not delegated API permissions.

    In the First application, I added scope like below:

    enter image description here

    When I grant the API permissions, it is granted as delegated:

    enter image description here

    I tried to generate the access token with az login (user interactive flow):

    az login --tenant TenantID --allow-no-subscriptions --scope 'api://xxx/MyData.Read.All'
    
    $accessToken = az account get-access-token `
        --scope 'api://xx/MyData.Read.All' `
        --query accessToken --output tsv
    

    enter image description here

    When decoded the access token in jwt.ms, you can see the scp claim and the aud is the ClientID of the First app:

    enter image description here

    And hence you are able to call the APIs with this token.

    Now I created a client app and in the first application added the client app as Authorized client applications:

    enter image description here

    I tried to generate access token through a Client App:

    az login `
        --allow-no-subscriptions `
        --tenant 'tenantID ' `
        --service-principal -u "ClientID" -p Secret `
        --query accessToken `
        --output tsv
    
    $accessToken = az account get-access-token `
        --scope 'api://xxx/.default' `
        --query accessToken --output tsv
    

    When decoded you can see there is no scp/role claim which must contain MyData.Read.All Api permission:

    enter image description here

    The error 401 is due to access token do not contain any scp/role claim and hence you are not able to call the API.

    To resolve the error, you need to create app role in your first application as service principal authentication/Client credential flow works only with Application type API permission.

    Hence, I created an app role:

    enter image description here

    The app role will be granted as Application type API permission:

    enter image description here

    Now I generated the access token again with client app:

    enter image description here

    When decoded the role claim is displayed:

    enter image description here

    Therefore, you cannot use service principal authentication when delegated API permissions are involved. Either user app roles or prefer user interactive flow.