Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Identity Server invalid scope in example from the documentation with version 4.0.0

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.

like image 527
diegosasw Avatar asked Oct 19 '25 10:10

diegosasw


2 Answers

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.

like image 165
diegosasw Avatar answered Oct 22 '25 05:10

diegosasw


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" }
            }
        };
}
like image 32
Ignatella Avatar answered Oct 22 '25 04:10

Ignatella