I have a Blazor WebAssembly App
created with Microsoft Visual Studio
with these specifications: Target Framework .NET 6.0
, Authentication Type Individual Accounts
and ASP.NET Core Hosted
:
Using this answer I have been able to add Client Credentials flow
https://stackoverflow.com/a/67324222/3850405
I removed this from appsettings.json
:
"Clients": {
"WebApplication4.Client": {
"Profile": "IdentityServerSPA"
}
}
Edit Startup.cs
or Program.cs
:
services.AddIdentityServer()
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>(options =>
{
options.Clients.AddIdentityServerSPA("WebApplication4.Client", builder =>
{
builder.WithRedirectUri("/authentication/login-callback");
builder.WithLogoutRedirectUri("/authentication/logout-callback");
});
options.Clients.Add(new Duende.IdentityServer.Models.Client
{
ClientId = "WebApplication4.Integration",
AllowedGrantTypes = { GrantType.ClientCredentials },
ClientSecrets = { new Secret("MySecretValue".Sha256()) },
AllowedScopes = { "WebApplication4.ServerAPI"}
});
});
This request will work:
POST /connect/token HTTP/1.1
Host: localhost:44397
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials&client_id=WebApplication4.Integration&client_secret=MySecretValue&scope=WebApplication4.ServerAPI
However I want this client to have its own AllowedScopes
. If I then change AllowedScopes = { "WebApplication4.ServerAPI"}
to AllowedScopes = { "WebApplication4.IntegrationAPI"}
and of course modifying the request.
Server then responds with:
{
"error": "invalid_scope"
}
If I look at logging I get the following history:
info: Duende.IdentityServer.Hosting.IdentityServerMiddleware[0]
Invoking IdentityServer endpoint: Duende.IdentityServer.Endpoints.TokenEndpoint for /connect/token
info: Duende.IdentityServer.Events.DefaultEventService[0]
{
"ClientId": "WebApplication4.Integration",
"AuthenticationMethod": "SharedSecret",
"Category": "Authentication",
"Name": "Client Authentication Success",
"EventType": "Success",
"Id": 1010,
"ActivityId": "80000009-0014-d600-b63f-84710c7967bb",
"TimeStamp": "2022-09-22T09:30:31Z",
"ProcessId": 17768,
"LocalIpAddress": "::1:44397",
"RemoteIpAddress": "::1"
}
fail: Duende.IdentityServer.Validation.DefaultResourceValidator[0]
Scope WebApplication4.IntegrationAPI not found in store or not supported by requested resource indicators.
fail: Duende.IdentityServer.Validation.TokenRequestValidator[0]
Invalid scopes requested, {
"ClientId": "WebApplication4.Integration",
"GrantType": "client_credentials",
"AuthorizationCode": "********",
"RefreshToken": "********",
"Raw": {
"grant_type": "client_credentials",
"client_id": "WebApplication4.Integration",
"client_secret": "***REDACTED***",
"scope": "WebApplication4.IntegrationAPI"
}
}
info: Duende.IdentityServer.Events.DefaultEventService[0]
{
"ClientId": "WebApplication4.Integration",
"Endpoint": "Token",
"GrantType": "client_credentials",
"Error": "invalid_scope",
"Category": "Token",
"Name": "Token Issued Failure",
"EventType": "Failure",
"Id": 2001,
"ActivityId": "80000009-0014-d600-b63f-84710c7967bb",
"TimeStamp": "2022-09-22T09:30:31Z",
"ProcessId": 17768,
"LocalIpAddress": "::1:44397",
"RemoteIpAddress": "::1"
}
What I take with me is this:
Scope WebApplication4.IntegrationAPI not found in store or not supported by requested resource indicators.
I then looked at these guides:
https://github.com/IdentityServer/IdentityServer4/issues/4632#issuecomment-654685880
https://docs.duendesoftware.com/identityserver/v5/quickstarts/1_client_credentials/
I therefore added this code:
public static class Config
{
public static IEnumerable<ApiScope> ApiScopes =>
new List<ApiScope>
{
new ApiScope("WebApplication4.IntegrationAPI", "Integration API")
};
}
and
services.AddIdentityServer()
.AddInMemoryApiScopes(Config.ApiScopes)
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>(options =>...
This still gave me the same error.
I then added a new list with clients:
public static IEnumerable<Duende.IdentityServer.Models.Client> Clients =>
new List<Duende.IdentityServer.Models.Client>
{
new Duende.IdentityServer.Models.Client
{
ClientId = "WebApplication4.Integration",
AllowedGrantTypes = { GrantType.ClientCredentials },
ClientSecrets = { new Secret("MySecretValue".Sha256()) },
AllowedScopes = { "WebApplication4.IntegrationAPI" },
}
};
Removed the old client from AddApiAuthorization
and used this code instead:
services.AddIdentityServer()
.AddInMemoryApiScopes(Config.ApiScopes)
.AddInMemoryClients(Config.Clients)
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>(options => ...
This gave me a new error when requesting a token:
{
"error": "invalid_client"
}
Logs:
info: Duende.IdentityServer.Hosting.IdentityServerMiddleware[0]
Invoking IdentityServer endpoint: Duende.IdentityServer.Endpoints.TokenEndpoint for /connect/token
info: Duende.IdentityServer.Events.DefaultEventService[0]
{
"ClientId": "WebApplication4.Integration",
"Category": "Authentication",
"Name": "Client Authentication Failure",
"EventType": "Failure",
"Id": 1011,
"Message": "Unknown client",
"ActivityId": "8000000a-0016-e700-b63f-84710c7967bb",
"TimeStamp": "2022-09-22T09:54:08Z",
"ProcessId": 10676,
"LocalIpAddress": "::1:44397",
"RemoteIpAddress": "::1"
}
fail: Duende.IdentityServer.Validation.ClientSecretValidator[0]
No client with id 'WebApplication4.Integration' found. aborting
If I look at https://localhost:44397/.well-known/openid-configuration I only see WebApplication4.ServerAPI
in scopes_supported
no matter the configuration.
I want to do it like this so that I can add a policy like this later:
services.AddAuthorization(options =>
{
options.AddPolicy("IntegrationApiScope", policy =>
{
policy.RequireAuthenticatedUser();
policy.RequireClaim("scope", "WebApplication4.IntegrationAPI");
});
});
Meaning that I only want Client Credentials flow to get the scope WebApplication4.IntegrationAPI
and I don't want Authorization Code Grant, normal login flow via (authorization_code
), to have this scope.