Q:

IdentityServer4 - RequestClientCredentialsTokenAsync returning unauthorized_client

Using IdentityServer4, I am getting an unauthorized_client error after updating my code for .net core 3.
My client is set up as follows in IdentityServer:
                new Client
                {
                    ClientId = "testclient",
                    ClientName = "My Test Client",
                    RequireConsent = false,

                    AllowedGrantTypes = GrantTypes.Implicit,

                    ClientSecrets = { new Secret("secret".Sha256()) },

                    RedirectUris = { "https://localhost:50691/signin-oidc" },
                    PostLogoutRedirectUris = { "https://localhost:50691/signout-callback-oidc" },

                    AllowedScopes = new List<string>
                    {
                        IdentityServerConstants.StandardScopes.OpenId, // identity resource
                        "testscope" // api resource
                    }
                },

I am trying to retrieve an access token using the following code in my client application:

            public async Task<TokenResponse> GetAccessTokenAsync(string IdentityServerBaseAddress, string IdentityServerClientId)
            {
                var client = new HttpClient();

                var disco = await client.GetDiscoveryDocumentAsync(IdentityServerBaseAddress);

                if (disco.IsError)
                {
                    Console.WriteLine($"Disco error: {disco.Error}");
                    return null;
                }

                Console.WriteLine($"Token endpoint: {disco.TokenEndpoint}");
                Console.WriteLine();

                // TODO: Get secret from Azure Key Vault
                // request token
                var tokenResponse = await client.RequestClientCredentialsTokenAsync(new ClientCredentialsTokenRequest
                {
                    Address = disco.TokenEndpoint, // "https://localhost:5000/connect/token"

                    ClientId = "testclient", // valid clientid
                    ClientSecret = "secret",
                    Scope = "testscope"
                });

                if (tokenResponse.IsError)
                {
                    Console.WriteLine(tokenResponse.Error);
                    return null;
                }

                return tokenResponse;
            }

tokenResponse.IsError is returning true (hence the method returns null) and Error is set to "unauthorized_client". I am basing this code off the documentation at http://docs.identityserver.io/en/latest/quickstarts/1_client_credentials.html?highlight=requestclientcredentialstokenasync. My clientid is valid and IdentityServer is validating the user upon login for this client. I'm pretty sure the issue is something simple that I'm just not seeing? Any help will be much appreciated.

A:

Since you're using a clientId and ClientSecret, so I think you need to change your Client  config to use GrantTypes.ClientCredentials, not GrantTypes.Implicit.
Change:
AllowedGrantTypes = GrantTypes.Implicit,

To
AllowedGrantTypes = GrantTypes.ClientCredentials,

