1

I have already a working identity server 4 in a .net core application.

namespace IdentityServer
{
    public class Config
    {
        public static IEnumerable<ApiResource> GetApiResources()
        {
            return new List<ApiResource>
            {
                new ApiResource("myresourceapi", "My Resource API")
                {
                    Scopes = {new Scope("apiscope")}
                }
            };
        }

        public static IEnumerable<Client> GetClients()
        {
            return new[]
            {
                // for public api
                new Client
                {
                    ClientId = "secret_client_id",
                    AllowedGrantTypes = GrantTypes.ClientCredentials,
                    ClientSecrets =
                    {
                        new Secret("secret".Sha256())
                    },
                    AllowedScopes = { "apiscope" }
                }
            };
        }
    }
}

namespace IdentityServer
{
    public class Startup
    {
        // This method gets called by the runtime. Use this method to add services to the container.
        // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddIdentityServer()
            .AddDeveloperSigningCredential()
            .AddOperationalStore(options =>
            {
                options.EnableTokenCleanup = true;
                options.TokenCleanupInterval = 30; // interval in seconds
             })
            .AddInMemoryApiResources(Config.GetApiResources())
            .AddInMemoryClients(Config.GetClients());
        }

        // 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.UseIdentityServer();
            app.UseRouting();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapGet("/", async context =>
                {
                    await context.Response.WriteAsync("Hello World!");
                });
            });
        }
    }
}

The problem is that now I need to make authenticated requests to a .net 4.6 web api2 (not core). And the IdentityServer4.AccessTokenValidation package doesn't work for that. According to this question (https://stackoverflow.com/questions/41992272/is-it-possible-to-use-identity-server-4-running-on-net-core-with-a-webapi-app-r) all I have to do is to use the same package that was used for Identity server 3(IdentityServer3.AccessTokenValidation). This is the code i have implemented in the webapi 2

using IdentityServer3.AccessTokenValidation;
using Microsoft.Owin;
using Owin;
using Microsoft.Owin.Host.SystemWeb;
using IdentityModel.Extensions;
using System.Web.Http;

[assembly: OwinStartup(typeof(WebApplication10.Startup))]

namespace WebApplication10
{
    public partial class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            app.UseIdentityServerBearerTokenAuthentication(new IdentityServerBearerTokenAuthenticationOptions
            {
                Authority = "https://localhost:44357",

                // For access to the introspection endpoint
                ClientId = "secret_client_id",
                ClientSecret = "secret".ToSha256(),
                RequiredScopes = new[] { "apiscope" }
            });

        }
    }
}

namespace WebApplication10.Controllers
{
    public class ValuesController : ApiController
    {
        [Authorize]
        // GET api/values
        public IEnumerable<string> Get()
        {
            return new string[] { "value1", "value2" };
        }
    }
}

The status i get all the time is 401 Unauthorized. Am i doing something wrong? Any help with this? Thanks.

srv8
  • 53
  • 9
  • Did you check identityserver4 logs? They are pretty verbose and will guide you to the correct solution of the issue. https://identityserver4.readthedocs.io/en/latest/topics/logging.html. – Alessandro R Apr 28 '20 at 06:23

2 Answers2

3

Without logs can't be sure what is issue in your case, but here is couple of fixes I made to make it work:

  1. On Statup.cs class of IdentityServer project
    • Change AccessTokenJwtType to JWT, default value on IdentityServer4 is at+jwt but .Net Framework Api (OWIN/Katana) requires JWT.
    • Add /resources aud by setting EmitLegacyResourceAudienceClaim to true, this is removed on IdentityServer4.

You can verify the access_token on https://jwt.ms/ by checking "typ" and "aud" .

var builder = services.AddIdentityServer(                
                options =>
                {
                    options.AccessTokenJwtType = "JWT"; 
                    options.EmitLegacyResourceAudienceClaim = true;
                });
  1. On Statup.cs class of .Net Framework Api project, set ValidationMode to ValidationMode.Local, custom access token validation endpoint used by this method is removed on IdentityServer4.
app.UseIdentityServerBearerTokenAuthentication(new IdentityServerBearerTokenAuthenticationOptions
            {
                Authority = "https://localhost:44357",

                // For access to the introspection endpoint
                ClientId = "secret_client_id",
                ClientSecret = "secret".ToSha256(),
                RequiredScopes = new[] { "apiscope" },
                ValidationMode = ValidationMode.Local,
            });

I have sample working implementation here

I strongly suggest you to gather logs on API, this helps to find the actual issue in your case and finding the fix. here is a sample to turn on OWIN log on Api.

nahidf
  • 2,260
  • 1
  • 15
  • 22
0

You can follow the sample from CrossVersionIntegrationTests .

Identity server 4 doesn't have the connect/accesstokenvalidation endpoint . So in identity server4 app , you can modify your ApiResource to add the ApiSecret :

new ApiResource("api1", "My API"){  ApiSecrets = new List<Secret> {new Secret("scopeSecret".Sha256())}}

And in your web api , config the IdentityServerBearerTokenAuthenticationOptions like :

app.UseIdentityServerBearerTokenAuthentication(new IdentityServerBearerTokenAuthenticationOptions
{
    Authority = "http://localhost:5000",
    ValidationMode = ValidationMode.ValidationEndpoint,
    ClientId = "api1",
    ClientSecret = "scopeSecret",
    RequiredScopes = new[] { "api1" }
});

ClientId & ClientSecret are both from your ApiResource .

Nan Yu
  • 26,101
  • 9
  • 68
  • 148
  • Hello thanks for you response,the way that worked for me was by editing the Identity server 4 config as you said with one more change at the config.cs IEnumerable GetClients() by adding the new api resource (api1) as an AllowedScopes = { "apiscope","api1" } – srv8 Apr 28 '20 at 22:25
  • I just use api1 as code sample , you are using `myresourceapi` then use it – Nan Yu Apr 29 '20 at 01:36