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)
Note: When you Expose an API and add a scope, it is considered as delegated API permission.
In the First application, I added scope like below:
When I grant the API permissions, it is granted as delegated:
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
When decoded the access token in jwt.ms, you can see the scp claim and the aud is the ClientID of the First app:
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:
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:
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:
The app role will be granted as Application type API permission:
Now I generated the access token again with client app:
When decoded the role claim is displayed:
Therefore, you cannot use service principal authentication when delegated API permissions are involved. Either user app roles or prefer user interactive flow.