0
votes

I have been following the steps in this post with the exception that my IdentityServer is built with IdentityServer4. https://identityserver.github.io/Documentation/docsv2/overview/simplestOAuth.html

On the IdentityServer I have created the 2 ApiResource, 1 for a CoreWebApi and 1 for a Framework 4.6.2 WebApi.

new ApiResource {
            Name = "WebApi",
            DisplayName = "WebApi Api",
            Description = "WebApi API Access",
            UserClaims = new List<string> {"role"},
            ApiSecrets = new List<Secret> {new Secret("scopeSecret".Sha256())},
            Scopes = new List<Scope> {
                new Scope("WebApi.read"),
                new Scope("WebApi.write")
            }
        },
        new ApiResource {
            Name = "CoreApi",
            DisplayName = "CoreApi API",
            Description = "CoreApi API Access",
            UserClaims = new List<string> {"role"},
            ApiSecrets = new List<Secret> {new Secret("scopeSecret".Sha256())},
            Scopes = new List<Scope> {
                new Scope("CoreApi.read"),
                new Scope("CoreApi.write")
            }
        }

And the Client for my test console to generate the access tokens.

            new Client()
            {
                ClientId = "consoleApp",
                ClientName = "Example Client Credentials Client Application",
                AllowedGrantTypes = GrantTypes.ClientCredentials,
                ClientSecrets = new List<Secret>()
                {
                    new Secret("superSecretPassword".Sha256())
                },
                AllowedScopes = new List<string>(){ "CoreApi.read", "WebApi.read" }
            }

I can request a token for CoreApi

var tokenResponse = await tokenClient.RequestClientCredentialsAsync("CoreApi.read");

Then call my CoreApi with no problems.

I can also get a token for the WebApi

var tokenResponse = await tokenClient.RequestClientCredentialsAsync("WebApi.read");

But calling the WebApi with the token returns "Unauthorized" ?

The CoreWebApi config is as follows:

services.AddMvcCore()
        .AddAuthorization()
        .AddJsonFormatters();

        services.AddAuthentication("Bearer")
            .AddIdentityServerAuthentication(options =>
            {
                options.Authority = "http://localhost:5000";
                options.RequireHttpsMetadata = false;

                options.ApiName = "CoreApi";
            });

And the WebApi config is:

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

        // configure web api
        var config = new HttpConfiguration();
        config.MapHttpAttributeRoutes();

        // require authentication for all controllers
        config.Filters.Add(new AuthorizeAttribute());

        app.UseWebApi(config);

Is there anything obvious I am missing ? Should it be possible to generate an access token in IdentityServer4 and validate using IdentityServer3.AccessTokenValidation? Any help appreciated.

1
Noticed for WebApi with the above config, it was triggering a call to "localhost:5000/connect/accesstokenvalidation". But IdentityServer4 doesn't have this endpoint. Got it to work by changing the ValidationMode to Local. - Danny

1 Answers

0
votes

FYI, I managed to get the ValidationEndpoint to work by updating the config to:

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

After looking through some code on Git I found that if the ClientId was specified it would use the Introspection (/connect/introspect) endpoint instead of a validation endpoint (connect/accesstokenvalidation) that doesn't exist.

****Note Confusingly the ClientId and ClientSecret used are actually the API resource Name and ApiSecrets !