I am new to IdentityServer4. I have created a IdentityServer4 client, a scope at the IdentityServer4 running at https://localhost:44311/. I secured a sample Weather API using IdentityServer4. When I run Program.cs
, I receive an Authorization token. I set this token using client.SetBearerToken(tokenResponse.AccessToken);
but when I send GET request to API using await client.GetAsync($"https://localhost:44315/weatherforecast");
, I receive 401 Unauthorized or 403 Forbidden. What am I missing? Here is code:
Startup.cs
namespace weatherapi
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication("Bearer")
.AddIdentityServerAuthentication("Bearer", options =>
{
options.ApiName = "weatherapi";
options.Authority = "https://localhost:44311/";
});
services.AddControllers();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
}
WeatherForecastController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
namespace weatherapi.Controllers
{
[ApiController]
[Route("[controller]")]
[Authorize]
public class WeatherForecastController : ControllerBase
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
private readonly ILogger<WeatherForecastController> _logger;
public WeatherForecastController(ILogger<WeatherForecastController> logger)
{
_logger = logger;
}
[HttpGet]
public IEnumerable<WeatherForecast> Get()
{
var rng = new Random();
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = rng.Next(-20, 55),
Summary = Summaries[rng.Next(Summaries.Length)]
})
.ToArray();
}
}
}
Program.cs
using IdentityModel.Client;
using System.Text;
await SampleWeather();
//await SampleAdminApi();
async Task SampleWeather()
{
using var client = new HttpClient();
var tokenResponse = await client.RequestClientCredentialsTokenAsync(new ClientCredentialsTokenRequest
{
Address = "https://localhost:44311/connect/token",
ClientId = "weatherapi",
ClientSecret = "weatherapi",
Scope = "weatherapi_scope",
GrantType = "client_credentials"
});
if (tokenResponse.IsError)
{
throw new Exception("Unable to get token", tokenResponse.Exception);
}
client.SetBearerToken(tokenResponse.AccessToken);
var response = await client.GetAsync($"https://localhost:44315/weatherforecast");
var content = await response.Content.ReadAsStringAsync();
Console.ReadLine();
}
CodePudding user response:
As it seems to be a plain API, I would replace AddIdentityServerAuthentication with AddJwtBearer (see this page)
I would also set this flag to true inside AddJWtBearer
opt.IncludeErrorDetails = true;
Because then you would get some more details in the WWW-Authenticate header that you get back when you get a 401 error, like this:
HTTP/1.1 401 Unauthorized
Date: Sun, 02 Aug 2020 11:19:06 GMT
WWW-Authenticate: Bearer error="invalid_token", error_description="The signature is invalid"