I'm using IdentityServer4, following the documentation at https://identityserver4.readthedocs.io/en/latest/quickstarts/1_client_credentials.html
But I am getting an invalid_scope error in the client that uses IdentityModel when requesting a token with client credentials.
It's possible I missed some step, but I've reviewed it several times.
The strange thing is that the identity server endpoint shows the following logs:
Invalid scopes requested, {"ClientId": "client", "ClientName": null, "GrantType": "client_credentials", "Scopes": null, "AuthorizationCode": null, "RefreshToken": null, "UserName": null, "AuthenticationContextReferenceClasses": null, "Tenant": null, "IdP": null, "Raw": {"grant_type": "client_credentials", "scope": "api1", "client_id": "client", "client_secret": "***REDACTED***"}, "$type": "TokenRequestValidationLog"}
Isn't strange that Scopes is null and later on scope has the api1 value?
I am using in memory values.
public static class Config
{
public static IEnumerable<IdentityResource> Ids =>
new IdentityResource[]
{
new IdentityResources.OpenId()
};
public static IEnumerable<ApiResource> Apis =>
new List<ApiResource>
{
new ApiResource("api1", "My Api")
};
public static IEnumerable<Client> Clients =>
new List<Client>
{
new Client
{
ClientId = "client",
AllowedGrantTypes = GrantTypes.ClientCredentials,
ClientSecrets =
{
new Secret("secret".Sha256())
},
AllowedScopes = { "api1" }
}
};
}
and
public void ConfigureServices(IServiceCollection services)
{
// uncomment, if you want to add an MVC-based UI
//services.AddControllersWithViews();
var builder =
services
.AddIdentityServer()
.AddInMemoryApiResources(Config.Apis)
.AddInMemoryClients(Config.Clients)
.AddInMemoryIdentityResources(Config.Ids);
// not recommended for production - you need to store your key material somewhere secure
builder.AddDeveloperSigningCredential();
}
public void Configure(IApplicationBuilder app)
{
if (Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
// uncomment if you want to add MVC
//app.UseStaticFiles();
//app.UseRouting();
app.UseIdentityServer();
// uncomment, if you want to add MVC
//app.UseAuthorization();
//app.UseEndpoints(endpoints =>
//{
// endpoints.MapDefaultControllerRoute();
//});
}
I can see the well known configuration, although it does not mention api1 as supported scopes.
This is the client
var client = new HttpClient();
var discovery =
await client.GetDiscoveryDocumentAsync("https://localhost:5001");
if (discovery.IsError)
{
await Console.Out.WriteLineAsync("Discovery error");
return;
}
// request token
var clientCredentialsTokenRequest =
new ClientCredentialsTokenRequest
{
Address = discovery.TokenEndpoint,
ClientId = "client",
ClientSecret = "secret",
Scope = "api1"
};
var tokenResponse =
await client.RequestClientCredentialsTokenAsync(clientCredentialsTokenRequest);
Am I missing any additional thing to have the most basic sample work?
UPDATE 1:
Ok, I have downgraded Identity Server to 3.1.3 and it works as it is. For the version Identity Server 4.0.0 something must have changed. Will investigate there.
Found an issue that pointed me in the right direction. Fixed it by replacing ApiResources with ApiScopes:
public static IEnumerable<ApiScope> Apis =>
new List<ApiScope>
{
new ApiScope("api1", "My Api")
};
and
var builder =
services
.AddIdentityServer()
.AddInMemoryApiScopes(Config.Apis)
//.AddInMemoryApiResources(Config.Apis) //OLD?
.AddInMemoryClients(Config.Clients)
.AddInMemoryIdentityResources(Config.Ids);
I supposed the docs are not yet updated.
I'm still getting an unauthorized when trying to access the protected Api, but that is something else.
I know it's too late, but i want to show you one more solution. Yours ApiResources should match yours ApiScopes since they will be matched later. That is why removing AddInMemoryApiResources solved yours problem. Because you turned off that "matching functionality". Hope it will help somebody.
Startup.cs
services.AddIdentityServer()
.AddDeveloperSigningCredential()
.AddInMemoryPersistedGrants()
.AddInMemoryApiScopes(Config.ApiScopes)
.AddInMemoryIdentityResources(Config.IdentityResources)
.AddInMemoryApiResources(Config.ApiResources)
.AddInMemoryClients(Config.Clients);
Config.cs
public static class Config
{
public static IEnumerable<IdentityResource> IdentityResources =>
new IdentityResource[]
{
new IdentityResources.OpenId()
};
public static IEnumerable<ApiScope> ApiScopes =>
new ApiScope[]
{
new ApiScope("SignalR", "SignalR Chat")
};
public static IEnumerable<ApiResource> ApiResources =>
new List<ApiResource>
{
new ApiResource("SignalR", "SignalR Chat")
};
public static IEnumerable<Client> Clients =>
new Client[]
{
new Client
{
ClientId = "client",
// no interactive user, use the clientid/secret for authentication
AllowedGrantTypes = GrantTypes.ClientCredentials,
// secret for authentication
ClientSecrets =
{
new Secret("secret".Sha256())
},
// scopes that client has access to
AllowedScopes = { "SignalR" }
}
};
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With