Home > Net >  IdentityServer4 always return 401 Unauthorized or 403 Forbidden
IdentityServer4 always return 401 Unauthorized or 403 Forbidden

Time:01-20

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"
  • Related