Not sure if it's good to start from here. For Azure AD authorization(generating access token), there're several flows, most common used is Auth code flow -- let user sign in, then can used the credential to generate access token with delegated
api permission, token will have scp
claim. Client credential flow -- no need to sign in, generate token with application
api permission on behalf the app itself, token will contain roles
claim). On-behalf-of flow -- used when an API requires to call another API
, both the APIs required an access token).
About the API permission type
, for example Microsoft graph create calendar API, using delegated API permission can update resource for user him/herself. But using application API, application can modify any user's calendar event who are in the target tenant. Since we can set Azure AD to protect our own API
, so we can also create API permissions in Azure AD, choosing exposing delegated API permission or exposing application API permission.
According to the link you shared in the question, you are trying to use On-behalf-of flow because the document is a tutorial for one API calling another API. Then please allow me to make an assumption here. You have a client APP which integrated MSAL so that you can let users sign in and obtain an access token, you used that token to call your own API, your API requires to call another API to get some other information.
Just like what I said, Azure AD can protect our own WEB API. So we can go to Azure AD -> App Registrations -> create an Azure AD app or choose an existing one -> Expose an API -> after create the API, add a scope and name it like Steve_Allowed
, since the assumption is user call API so I create a scope for exposing delegated API. Then in the same Azure AD application -> API permissions -> Add a permission -> My APIs -> choose the AAD app -> Delegated permissions -> choose Steve_Allowed and click Add permissions -> click grant admin consent button beside add api permission button
. Next you also need to create a client secret in Certificates & secrets
blade if you don't have it.
Now we already finished the configurations in Azure AD, let's go to the API application. Just like you know, when you want to call an API protected by Azure AD, you need to add a request header like Authorization: Bearer xxxx
. In our web API we need to integrated Azure AD to validate the request so that it can give you a correct response or a 401 error. So in the API project, add code like below but maybe you already done.
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Identity.Web;
...
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"))
.EnableTokenAcquisitionToCallDownstreamApi()//this 2 lines for using _tokenAcquisition to generate another access token
.AddInMemoryTokenCaches();
builder.Services.AddHttpClient();
...
app.UseAuthentication();
app.UseAuthorization();
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"ClientId": "azure_ad_app_id",
"ClientSecret": "client_secret",
"Domain": "tenant_id",
"TenantId": "tenant_id",
"Audience": "api://client_id"
},
Assume it contained an API which added [Authorize]
attribute with URL is https://localhost:7072/WeatherForecast
, then add the request header. In your API code, you can use code below to get the token in the request header.
StringValues authorizationToken;
HttpContext.Request.Headers.TryGetValue("Authorization", out authorizationToken);
string incomingToken = authorizationToken.ToString().Replace("Bearer ", "");
And here the incoming Token contained the scopeRequiredByApi
you need. But it already validated by the middle, so you don't need to write a method
VerifyUserHasAnyAcceptedScope to validate the token.
Now we have successfully accessed the API and then we need to use on_behalf_of flow to access another API. Since the middleware already did the validation for us, we can directly using _tokenAcquisition
in our code to generate another access token and use it to call another API. So in your API you can have code like below. Please note, since you are trying to call another API, if that API is also managed by yourself, you may need to expose another API, then you can get a new scope. If this API is managed by others, for example the create calendar API, then you need to go to the API document to get the scope Calendars.ReadWrite
. The API provider should give you the scope, and this scope is what you want scopesToAccessDownstreamApi.
private readonly ITokenAcquisition _tokenAcquisition;
private readonly IHttpClientFactory _httpClientFactory;
public WeatherForecastController(ITokenAcquisition tokenAcquisition, IHttpClientFactory httpClientFactory)
{
_tokenAcquisition = tokenAcquisition;
_httpClientFactory = httpClientFactory;
}
[HttpGet(Name = "GetWeatherForecast")]
public async Task<string> GetAsync()
{
var accessToken = await _tokenAcquisition.GetAccessTokenForUserAsync(new string[] { "api://client_id/scopeName" });
var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, "https://localhost:7212/WeatherForecast")
{
Headers =
{
{ HeaderNames.Authorization, "Bearer "+ accessToken}
}
};
var httpClient = _httpClientFactory.CreateClient();
var response = await httpClient.SendAsync(httpRequestMessage);
var res = "";
if (response.StatusCode == HttpStatusCode.OK)
{
res = await response.Content.ReadAsStringAsync();
}
return "hello";
}
===========================Summary==========================
What you want is one API calling another API, if both the APIs are managed by yourself, you'd better to create 2 Azure AD applications and expose API permission in both of them. When you want to call any of the API, you need to set a scope to generate access token for the API. For example you exposed API permission for API 1 which scope should look like api://client_id1/scope_name_for_API1
. Then use it in the request header and call API 1, in API 1 you want to call API 2, then you need to use _tokenAcquisition
to generate with api://client_id2/scope_name_for_API2
for API 2 and call it.