Search code examples
identityserver4

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.


Solution

  • 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.