Reputation: 685
Net core application and react. I have react app which calls my middle tier api and middle tier api calls down stream api. I have registered three apps in azure ad. I have made all the configurations. In middle tier API I am validating the token recieved from react app and trying to get token for downstream api as below.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddTransient<DownStreamAPIService>();
services.AddHttpClient();
services.AddOptions();
var azureAd = Configuration.GetSection("AzureAd").Get<AzureAd>();
IdentityModelEventSource.ShowPII = true;
services.AddMicrosoftIdentityWebApiAuthentication(Configuration)
.EnableTokenAcquisitionToCallDownstreamApi()
.AddInMemoryTokenCaches();
services.AddAuthentication(x =>
{
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.SaveToken = true;
options.RequireHttpsMetadata = true;
options.Authority = $"{azureAd.Instance}/{azureAd.TenantId}/v2.0";
options.Audience = $"{azureAd.ClientId}";
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuer = true,
ValidateIssuerSigningKey = false,
ValidateActor = false
};
});
services.AddCors(options =>
{
options.AddPolicy(
"CorsPolicy",
builder =>
{
builder
.WithOrigins("https://localhost:3000")
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials();
});
});
}
Below is DownStreamAPIService class
public async Task<JArray> GetApiDataAsync()
{
var client = _clientFactory.CreateClient();
// user_impersonation access_as_user access_as_application .default
var scope = _configuration["DownStreamAPI:ScopeForAccessToken"];
var accessToken = await _tokenAcquisition.GetAccessTokenForUserAsync(new[] { scope }).ConfigureAwait(false);
client.BaseAddress = new Uri(_configuration["DownStreamAPI:ApiBaseAddress"]);
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var response = await client.GetAsync("weatherforecast").ConfigureAwait(false);
if (response.IsSuccessStatusCode)
{
var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
var data = JArray.Parse(responseContent);
return data;
}
throw new ApplicationException($"Status code: {response.StatusCode}, Error: {response.ReasonPhrase}");
}
Below is appsettings.json file
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"Domain": "mydomain.onmicrosoft.com",
"TenantId": "c5fff990-0e0a-4bf6-9c04-79ab98e05931",
"ClientId": "43dg8b3c-8743-4d6e-84b4-00fe04d93222"
},
"WebOriginUrl": "https://localhost:3000",
"DownStreamAPI": {
"ScopeForAccessToken": "api://723fac69-4038-4e16-92cc-3f57b7cc2381/access_downstream_api_as_user",
"ApiBaseAddress": "https://localhost:44316"
}
When I run the app I get below error
Scheme already exists: Bearer
In my middle tier app I am validating the token and trying to obtain new token for downstream API. i am just confused weather validating token required in middle tier api or not. I am using on behalf of flow. Can soneone help if there is anything wrong in this design. Any help would be appreciated. Thanks
Upvotes: 1
Views: 4767
Reputation: 23111
When we use the AddMicrosoftIdentityWebApiAuthentication
to configure Azure AD, the project will use Bearer
scheme to do auth. We do not need to configure it again. For more details, please refer to here and here. So please remove the code
services.AddAuthentication(x =>
{
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.SaveToken = true;
options.RequireHttpsMetadata = true;
options.Authority = $"{azureAd.Instance}/{azureAd.TenantId}/v2.0";
options.Audience = $"{azureAd.ClientId}";
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuer = true,
ValidateIssuerSigningKey = false,
ValidateActor = false
};
});
if you want to validate the token, you can use the following code
services.Configure<JwtBearerOptions>(JwtBearerDefaults.AuthenticationScheme, options =>
{
options.SaveToken = true;
options.RequireHttpsMetadata = true;
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateAudience = true,
ValidAudiences = new string[] { "872ebcec-c24a-4399-835a-201cdaf7d68b", "api://872ebcec-c24a-4399-835a-201cdaf7d68b" },
ValidateLifetime = true,
ValidateIssuer = true,
ValidateIssuerSigningKey = false,
ValidateActor = false,
ValidIssuers = new string[] { "https://sts.windows.net/{tenantId}", "https://login.microsoftonline.com/{tenantId}/v2.0" }
};
});
Upvotes: 3