I have a setup where I have created an app registration and expose an API but I am generating credentials and attempting to hit it but get a 401.
Please note: the API is hosted in Azure running in AKS and it runs under the app registration
my-api-ar
First App (Web API)
- Created this app registration called
my-api-ar
- Application ID Uri of
api://my-api-ar
- Contains a scope of
api://my-api-ar/Api.DevAccess
- I can see under authorized client applications, the ID of my second app
Second App (Messaging Endpoint)
- Created this app registration called
my-sub-ar
- Granted it API Permission to talk to
api://my-api-ar
- Generated a client secret
To generate the token I use this
var clientId = "";
var clientSecret = "";
var tenantId = "";
var clientCredential = new ClientSecretCredential(tenantId, clientId, clientSecret);
var context = new TokenRequestContext([ "api://my-api-ar/.default" ]);
var token = await clientCredential.GetTokenAsync(context);
var baseAddress = ";;
var path = "items";
var client = new HttpClient { BaseAddress = new Uri(baseAddress) };
client.DefaultRequestHeaders.Add("Bearer", token.Token);
var result = await client.GetAsync(path); // Returns 401
Is it related to the scopes? When I try to specify Api.DevAccess as the scope name it errors and states I need to use /.default
I have a setup where I have created an app registration and expose an API but I am generating credentials and attempting to hit it but get a 401.
Please note: the API is hosted in Azure running in AKS and it runs under the app registration
my-api-ar
First App (Web API)
- Created this app registration called
my-api-ar
- Application ID Uri of
api://my-api-ar
- Contains a scope of
api://my-api-ar/Api.DevAccess
- I can see under authorized client applications, the ID of my second app
Second App (Messaging Endpoint)
- Created this app registration called
my-sub-ar
- Granted it API Permission to talk to
api://my-api-ar
- Generated a client secret
To generate the token I use this
var clientId = "";
var clientSecret = "";
var tenantId = "";
var clientCredential = new ClientSecretCredential(tenantId, clientId, clientSecret);
var context = new TokenRequestContext([ "api://my-api-ar/.default" ]);
var token = await clientCredential.GetTokenAsync(context);
var baseAddress = "https://foobar";
var path = "items";
var client = new HttpClient { BaseAddress = new Uri(baseAddress) };
client.DefaultRequestHeaders.Add("Bearer", token.Token);
var result = await client.GetAsync(path); // Returns 401
Is it related to the scopes? When I try to specify Api.DevAccess as the scope name it errors and states I need to use /.default
Share Improve this question edited Apr 2 at 17:36 qkfang 1,7831 silver badge20 bronze badges asked Apr 1 at 10:36 Dr SchizoDr Schizo 4,3967 gold badges45 silver badges88 bronze badges 12 | Show 7 more comments2 Answers
Reset to default 0As mentioned in the comments, delegated permissions only work when a user account is involved in the authentication. In essence, delegated permissions grant a permission for an application to call an API on behalf of a signed in user.
You probably need an app role/app permission. You can go to the App roles tab of the API app registration and add an app role with allowed member type of applications. You can then grant this permission to the client application. Then you acquire the token with the special /.default scope. The permission will be in the "roles" claim inside the token.
Note: ClientSecretCredential
works for only Application type API permissions not delegated. If you want to use delegated API permission, make use of user interactive flow to call API.
- If you want to make use of
ClientSecretCredential
then create App roles instead of scope.
Grant API permissions:
You need to pass scope as api://xxx//.default
while using ClientSecretCredential
.
using Azure.Identity;
using Azure.Core;
class Program
{
static async Task Main(string[] args)
{
var clientId = "ClientID";
var clientSecret = "Secret";
var tenantId = "TenantID";
var clientCredential = new ClientSecretCredential(tenantId, clientId, clientSecret);
var scope = "api://xxx/.default";
var context = new TokenRequestContext(new[] { scope });
try
{
var token = await clientCredential.GetTokenAsync(context);
Console.WriteLine("Access Token:");
Console.WriteLine(token.Token);
}
catch (Exception ex)
{
Console.WriteLine("Error occurred: " + ex.Message);
}
}
}
When you decode the token, you can find roles claim:
Using this access token, you can call your API.
my-api-ar
in AKS – Dr Schizo Commented Apr 1 at 10:56