I have a problem catching a user role from a JWT token in my API. I added a role to my token and added a policy with the required role, but it's not working as I expected. Every time when I have respon status 403 Forbidden.
IdentityServer site:
new IdentityResource[]
{
new IdentityResources.OpenId(),
new IdentityResources.Profile(),
new IdentityResource(
name: "user",
userClaims: new[] {JwtClaimTypes.Email}),
new IdentityResource(
name: "role",
userClaims: new[] {JwtClaimTypes.Role})
};
new Client()
{
ClientId = "swagger",
ClientName = "Client for Swagger use",
AllowedGrantTypes = GrantTypes.CodeAndClientCredentials,
ClientSecrets = {new Secret("secret".Sha256())},
AllowedScopes = {"api1", "user", "openid", "role"},
AlwaysSendClientClaims = true,
AlwaysIncludeUserClaimsInIdToken = true,
AllowAccessTokensViaBrowser = true,
RedirectUris = {"https://localhost:44376/swagger/oauth2-redirect.html"},
AllowedCorsOrigins = {"https://localhost:44376"}
}
API site:
services.AddAuthorization(optionns =>
{
optionns.AddPolicy("admin", policy =>
{
policy.RequireAuthenticatedUser();
policy.RequireClaim("scope", "api1");
policy.RequireRole("admin");
});
optionns.AddPolicy("ApiScope", policy =>
{
policy.RequireAuthenticatedUser();
policy.RequireClaim("scope", "api1");
});
});
Controller site:
[Authorize(Policy = "admin")]
or
[Authorize(Role= "admin")]
My data from JWT token:
{
"nbf": 1670283035,
"exp": 1670286635,
"iss": "https://localhost:5001",
"aud": "https://localhost:5001/resources",
"client_id": "swagger",
"sub": "1",
"auth_time": 1670282526,
"idp": "local",
"Email": "AliceSmith#email.com",
"role": "admin",
"jti": "D07527BB11C8C4EEFC7A5012ADB38DE9",
"sid": "97828B78D66B3A2C96CAE60F7F1A6D25",
"iat": 1670283035,
"scope": [
"api1",
"user",
"openid",
"role"
],
"amr": [
"pwd"
]
}
Any ideas to resolve this problem? I have already processed hundreds of problems on forums and tutorials and nothing has helped.
Microsoft and OpenID-Connect have different opinions on what the claims should be called.
So, what you need to do in AddOpenIDConnect is to tell ASP.NET Core what the name of the role claim is, typically by adding something like:
options.TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = JwtClaimTypes.Name,
RoleClaimType = JwtClaimTypes.Role
};
The best way to troubleshoot these problems is to look what is actually inside your ClaimsPrincipal User object. It might not always contains the claim you think it should contain.
For more details, see this blog post https://leastprivilege.com/2017/11/15/missing-claims-in-the-asp-net-core-2-openid-connect-handler/
Related
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.
This will work:
services.AddIdentityServer()
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>(options =>
{
options.ApiScopes.Add(new ApiScope("scope1"));
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 = { "scope1" }
});
});
However WebApplication4.Integration can still request the scope WebApplication4.ServerAPI and get a token with it.
Using the following code:
services.AddIdentityServer()
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>(options =>
{
options.ApiScopes.Add(new ApiScope("scope1"));
options.ApiScopes.Add(new ApiScope("scope2"));
options.Clients.Add(new Duende.IdentityServer.Models.Client
{
ClientId = "WebApplication4.Integration",
AllowedGrantTypes = { GrantType.ClientCredentials },
ClientSecrets = { new Secret("MySecretValue".Sha256()) },
AllowedScopes = { "scope1" }
});
});
WebApplication4.Integration can get a token using scopes WebApplication4.ServerAPI and scope1 but not with scope2.
See this issue for more info:
https://github.com/dotnet/aspnetcore/issues/44122
Creating a new Blazor WebAssembly App with Microsoft Visual Studio 2019 Version 16.9.4 with these specifications: Target Framework .NET 5.0, Authentication Type Individual Accounts and ASP.NET Core Hosted:
Gives a Server project with these NuGets at version 5.0.5:
Microsoft.AspNetCore.ApiAuthorization.IdentityServer
Microsoft.AspNetCore.Identity.EntityFrameworkCore
Microsoft.AspNetCore.Identity.UI
Startup.cs contains this code:
services.AddIdentityServer()
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>();
services.AddAuthentication()
.AddIdentityServerJwt();
Reading the blog post ASP.NET Core Authentication with IdentityServer4 from Microsoft I should be able to retrieve a token with a sample request that looks like this:
POST /connect/token HTTP/1.1
Host: localhost:5000
Cache-Control: no-cache
Postman-Token: 958df72b-663c-5638-052a-aed41ba0dbd1
Content-Type: application/x-www-form-urlencoded
grant_type=password&username=Mike%40Contoso.com&password=MikesPassword1!&client_id=myClient&scope=myAPIs
https://devblogs.microsoft.com/aspnet/asp-net-core-authentication-with-identityserver4/
Creating a request that looks like that but for the solution created:
POST /connect/token HTTP/1.1
Host: localhost:44388
Content-Type: application/x-www-form-urlencoded
Content-Length: 153
grant_type=password&username=example%40example.com&password=Password1&client_id=WebApplication4.Client&scope=WebApplication4.ServerAPI%20openid%20profile
This request returns HTTP Status 400 Bad Request with body:
{
"error": "unauthorized_client"
}
I'm pretty sure the values are correct since I got client_id and scope from the request used to sign in to the web application. That flow does not use grant_type=password though. Example request from login:
https://localhost:44388/Identity/Account/Login?ReturnUrl=/connect/authorize/callback?client_id=WebApplication4.Client&redirect_uri=https%3A%2F%2Flocalhost%3A44388%2Fauthentication%2Flogin-callback&response_type=code&scope=WebApplication4.ServerAPI%20openid%20profile&state=12345&code_challenge=12345&code_challenge_method=S256&response_mode=query
Confirmation that the user exists and works:
What am I missing?
TLDR:
Remove this from appsettings.json:
"Clients": {
"WebApplication4.Client": {
"Profile": "IdentityServerSPA"
}
}
Edit Startup.cs:
services.AddIdentityServer()
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>(options =>
{
options.Clients.AddIdentityServerSPA("WebApplication4.Client", builder =>
{
builder.WithRedirectUri("/authentication/login-callback");
builder.WithLogoutRedirectUri("/authentication/logout-callback");
});
//Or Duende.IdentityServer.Models.Client
options.Clients.Add(new IdentityServer4.Models.Client
{
ClientId = "WebApplication4.Integration",
AllowedGrantTypes = { GrantType.ResourceOwnerPassword },
//Use Configuration.GetSection("MySecretValue").Value; to get a value from appsettings.json
ClientSecrets = { new Secret("MySecretValue".Sha256()) },
AllowedScopes = { "WebApplication4.ServerAPI", "openid", "profile" }
});
});
This request will work:
POST /connect/token HTTP/1.1
Host: localhost:44388
Content-Type: application/x-www-form-urlencoded
Content-Length: 168
grant_type=password&username=example%40example.com&password=Password1!&client_id=WebApplication4.Integration&scope=WebApplication4.ServerAPI&client_secret=MySecretValue
Long answer:
I started out with trying to get a better error messages with Logging.
I added the code below to public static IHostBuilder CreateHostBuilder(string[] args) in
Program.cs:
.ConfigureLogging(logging =>
{
logging.ClearProviders();
logging.AddConsole();
})
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/logging/?view=aspnetcore-5.0
When debugging I could then show output from the Server application when I made the request. It looked like this:
info: IdentityServer4.Hosting.IdentityServerMiddleware[0]
Invoking IdentityServer endpoint: IdentityServer4.Endpoints.TokenEndpoint for /connect/token
info: IdentityServer4.Events.DefaultEventService[0]
{
"ClientId": "WebApplication4.Client",
"AuthenticationMethod": "NoSecret",
"Category": "Authentication",
"Name": "Client Authentication Success",
"EventType": "Success",
"Id": 1010,
"ActivityId": "8000000a-0000-8f00-b63f-84710c7967bb",
"TimeStamp": "2021-04-29T11:47:07Z",
"ProcessId": 8436,
"LocalIpAddress": "::1:44388",
"RemoteIpAddress": "::1"
}
fail: IdentityServer4.Validation.TokenRequestValidator[0]
Client not authorized for resource owner flow, check the AllowedGrantTypes setting{ client_id = WebApplication4.Client }, details: {
"ClientId": "WebApplication4.Client",
"ClientName": "WebApplication4.Client",
"GrantType": "password",
"Raw": {
"grant_type": "password",
"username": "example#example.com",
"password": "***REDACTED***",
"client_id": "WebApplication4.Client",
"scope": "WebApplication4.ServerAPI"
}
}
info: IdentityServer4.Events.DefaultEventService[0]
{
"ClientId": "WebApplication4.Client",
"ClientName": "WebApplication4.Client",
"Endpoint": "Token",
"GrantType": "password",
"Error": "unauthorized_client",
"Category": "Token",
"Name": "Token Issued Failure",
"EventType": "Failure",
"Id": 2001,
"ActivityId": "8000000a-0000-8f00-b63f-84710c7967bb",
"TimeStamp": "2021-04-29T11:47:07Z",
"ProcessId": 8436,
"LocalIpAddress": "::1:44388",
"RemoteIpAddress": "::1"
}
The error message to look at is Client not authorized for resource owner flow, check the AllowedGrantTypes setting{ client_id = WebApplication4.Client }.
With this error message I found this Question:
Question about ASP.NET Core 3 Identity / Identity Server / SPA support for Resource Owner Password Grant Type
There I could read
found that the allowed grant type of password was not being added when
the profile is set to IdentityServerSPA.
Looking at appsettings.json the application uses that profile:
"IdentityServer": {
"Clients": {
"WebApplication4.Client": {
"Profile": "IdentityServerSPA"
}
}
},
Looking at Microsoft Application profiles what it actually does is this:
The redirect_uri defaults to /authentication/login-callback.
The post_logout_redirect_uri defaults to
/authentication/logout-callback.
The set of scopes includes the openid, profile, and every scope
defined for the APIs in the app.
The set of allowed OIDC response types is id_token token or each of
them individually (id_token, token).
The allowed response mode is fragment.
https://learn.microsoft.com/en-us/aspnet/core/security/authentication/identity-api-authorization?view=aspnetcore-5.0#application-profiles
Before starting to modify this I visited the URL https://localhost:44388/.well-known/openid-configuration to get the current configuration. It looked like this and specifically says grant_types_supported: ...password:
{
"issuer": "https://localhost:44388",
"jwks_uri": "https://localhost:44388/.well-known/openid-configuration/jwks",
"authorization_endpoint": "https://localhost:44388/connect/authorize",
"token_endpoint": "https://localhost:44388/connect/token",
"userinfo_endpoint": "https://localhost:44388/connect/userinfo",
"end_session_endpoint": "https://localhost:44388/connect/endsession",
"check_session_iframe": "https://localhost:44388/connect/checksession",
"revocation_endpoint": "https://localhost:44388/connect/revocation",
"introspection_endpoint": "https://localhost:44388/connect/introspect",
"device_authorization_endpoint": "https://localhost:44388/connect/deviceauthorization",
"frontchannel_logout_supported": true,
"frontchannel_logout_session_supported": true,
"backchannel_logout_supported": true,
"backchannel_logout_session_supported": true,
"scopes_supported": [
"openid",
"profile",
"WebApplication4.ServerAPI",
"offline_access"
],
"claims_supported": [
"sub",
"name",
"family_name",
"given_name",
"middle_name",
"nickname",
"preferred_username",
"profile",
"picture",
"website",
"gender",
"birthdate",
"zoneinfo",
"locale",
"updated_at"
],
"grant_types_supported": [
"authorization_code",
"client_credentials",
"refresh_token",
"implicit",
"password",
"urn:ietf:params:oauth:grant-type:device_code"
],
"response_types_supported": [
"code",
"token",
"id_token",
"id_token token",
"code id_token",
"code token",
"code id_token token"
],
"response_modes_supported": [
"form_post",
"query",
"fragment"
],
"token_endpoint_auth_methods_supported": [
"client_secret_basic",
"client_secret_post"
],
"id_token_signing_alg_values_supported": [
"RS256"
],
"subject_types_supported": [
"public"
],
"code_challenge_methods_supported": [
"plain",
"S256"
],
"request_parameter_supported": true
}
For some reason IdentityServer Clients can not be configured in code and in appsettings.json. I therefore removed Clients from appsettings.json and added this to Startup.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 IdentityServer4.Models.Client
{
ClientId = "WebApplication4.Integration",
AllowedGrantTypes = { GrantType.ResourceOwnerPassword },
AllowedScopes = { "WebApplication4.ServerAPI", "openid", "profile" }
});
});
Without WithRedirectUri and WithLogoutRedirectUri it did not work, OidcConfigurationController got an exception for ClientRequestParametersProvider.GetClientParameters(HttpContext, clientId); with System.InvalidOperationException: 'Sequence contains no elements'. For some reason this is fixed automatically when using appsettings.json.
I now got the error message when posting to /connect/token:
{
"error": "invalid_client"
}
But I got a much better error in the log:
Invalid client configuration for client WebApplication4.Integration: Client secret is required for password, but no client secret is configured.
Added a secret to Startup.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 IdentityServer4.Models.Client
{
ClientId = "WebApplication4.Integration",
AllowedGrantTypes = { GrantType.ResourceOwnerPassword },
//Use Configuration.GetSection("MySecretValue").Value; to get a value from appsettings.json
ClientSecrets = { new Secret("MySecretValue".Sha256()) },
AllowedScopes = { "WebApplication4.ServerAPI", "openid", "profile" }
});
});
And the request:
POST /connect/token HTTP/1.1
Host: localhost:44388
Content-Type: application/x-www-form-urlencoded
Content-Length: 168
grant_type=password&username=example%40example.com&password=Password1!&client_id=WebApplication4.Integration&scope=WebApplication4.ServerAPI&client_secret=MySecretValue
It finally worked and the normal login flow worked as well!
Hi I am getting the error...
"IdentityServer4.Stores.ValidatingClientStore Invalid client configuration for ... client no allowed grant type specified"
when using a sql database context initially seeded from static data.
If I use the same static data on an AddInMemoryClients context no errors occurs and everything works fine.
Client definition...
new Client
{
ClientId = "GameMvc",
ClientName = "MGame web client",
ClientSecrets = { new Secret("058dddb593be4e149c19e23fd336e2ed".Sha256()) },
AllowRememberConsent = false,
AllowOfflineAccess = true,
UpdateAccessTokenClaimsOnRefresh = true,
AccessTokenLifetime = 180,
AllowedGrantTypes = GrantTypes.Hybrid,
RedirectUris = { "https://localhost:44330/signin-oidc" },
PostLogoutRedirectUris = { "https://localhost:44330/signout-callback-oidc" },
AllowedScopes =
{
"openid",
"profile",
"email",
"address",
"offline_access",
"role",
}
}
Identity server debug output
fail: IdentityServer4.Stores.ValidatingClientStore[0]
Invalid client configuration for client GameMvc: no allowed grant type specified
info: IdentityServer4.Events.DefaultEventService[0]
{
"Name": "Invalid Client Configuration",
"Category": "Error",
"EventType": "Error",
"Id": 3001,
"ClientId": "GameMvc",
"ClientName": "MGame web client",
"Message": "no allowed grant type specified",
"ActivityId": "0HLUGMDSRD0QH:00000007",
"TimeStamp": "2020-03-25T11:56:22Z",
"ProcessId": 22768,
"LocalIpAddress": "::1:44320",
"RemoteIpAddress": "::1"
}
fail: IdentityServer4.Validation.AuthorizeRequestValidator[0]
Unknown client or not enabled: GameMvc
{
"SubjectId": "anonymous",
"RequestedScopes": "",
"Raw": {
"client_id": "GameMvc",
"redirect_uri": "https://localhost:44330/signin-oidc",
"response_type": "code id_token",
"scope": "openid profile email offline_access role experience subscription_level GameApi",
"response_mode": "form_post",
"nonce": "637207341781609343.NzJmYjQ1ZjgtNDI1Yy00ZWY4LWE2YTItOTE0MWUwNTYwNDIwNzQ0NWJjOWEtN2FhNS00M2NlLTlhMmMtMTlkODBhMTliYjdm",
"state": "CfDJ8H3n8sVeRBlPopiMUAsqux6eF3ZksNANFCae20YtpBRAXjP-7HUxq1--kcY8uMuiT1moapzqik0ifGaLVmBiQw2QcRcNLlJCpN50yy2uHy52-ydsbCEGigE81skOlEalX2fMbjOuVRSC5jT4FaE2DFM-wPj8ndbf_VGYQ-FG5avBp9vsSKMW_CdUaUtrbs4nsEmAn1NTZoXIPTXnzBcCKOPwSpCOalpK1i4SbpKFbvN3PAKCNw1zPi-lFM5_W3icVvD_gazWnP3X1jxp_3XzCSoKIf3bKSL6TKuix28SPJZ_-KnKJtWOAUkkTFu20Qr0DQ",
"x-client-SKU": "ID_NETSTANDARD2_0",
"x-client-ver": "5.5.0.0"
}
}
fail: IdentityServer4.Endpoints.AuthorizeEndpoint[0]
Request validation failed
info: IdentityServer4.Endpoints.AuthorizeEndpoint[0]
{
"SubjectId": "anonymous",
"RequestedScopes": "",
"Raw": {
"client_id": "GameMvc",
"redirect_uri": "https://localhost:44330/signin-oidc",
"response_type": "code id_token",
"scope": "openid profile email offline_access role experience subscription_level GameApi",
"response_mode": "form_post",
"nonce": "637207341781609343.NzJmYjQ1ZjgtNDI1Yy00ZWY4LWE2YTItOTE0MWUwNTYwNDIwNzQ0NWJjOWEtN2FhNS00M2NlLTlhMmMtMTlkODBhMTliYjdm",
"state": "CfDJ8H3n8sVeRBlPopiMUAsqux6eF3ZksNANFCae20YtpBRAXjP-7HUxq1--kcY8uMuiT1moapzqik0ifGaLVmBiQw2QcRcNLlJCpN50yy2uHy52-ydsbCEGigE81skOlEalX2fMbjOuVRSC5jT4FaE2DFM-wPj8ndbf_VGYQ-FG5avBp9vsSKMW_CdUaUtrbs4nsEmAn1NTZoXIPTXnzBcCKOPwSpCOalpK1i4SbpKFbvN3PAKCNw1zPi-lFM5_W3icVvD_gazWnP3X1jxp_3XzCSoKIf3bKSL6TKuix28SPJZ_-KnKJtWOAUkkTFu20Qr0DQ",
"x-client-SKU": "ID_NETSTANDARD2_0",
"x-client-ver": "5.5.0.0"
}
}
however using the same client on in memory scenario with AddInMemoryClients it works... see the debug output below..
dbug: IdentityServer4.Validation.AuthorizeRequestValidator[0]
Calling into custom validator: IdentityServer4.Validation.DefaultCustomAuthorizeRequestValidator
dbug: IdentityServer4.Endpoints.AuthorizeEndpoint[0]
ValidatedAuthorizeRequest
{
"ClientId": "GameMvc",
"ClientName": "MGame web client",
"RedirectUri": "https://localhost:44330/signin-oidc",
"AllowedRedirectUris": [
"https://localhost:44330/signin-oidc"
],
"SubjectId": "anonymous",
"ResponseType": "code id_token",
"ResponseMode": "form_post",
"GrantType": "hybrid",
"RequestedScopes": "openid profile email offline_access role experience subscription_level GameApi",
"State": "CfDJ8H3n8sVeRBlPopiMUAsqux7YiGRgIGQOeT0aF9aYMv-a40lLmjS_uEZw_jMeQAgkq7wFGq8mMMekKNm8U6uFL_kruFOX_gYjhJjzRZUKG1aHE0vpcJ0i0zYqd9aTh6elus8MxkP6NaGWszjf0wXSwVNboUdq_7NAvR_b4Pyt0sMkD5LTysTQ4VePtKi-FjDarp5xlRPvQUfiYpZfcyOGi7eqSlHuiVzD83uByMBhJ3cIA6h5n5zDzzotNpwxw_QLQk4A8zN06tgTHhUYTWV-5kxYiX3N84f__eyB3K_TCY94Kbm562BZX4TtfLzJHqJAdg",
"Nonce": "637207668423193165.NjAzZDAwM2UtMjc0Yi00ZTNiLTgyOWYtN2JhYTI5ZTkxNDBlZGJiN2FiZGEtN2ZmYy00OGFkLWE5MGItMzAzNmY3OGM1MGIx",
"SessionId": "",
"Raw": {
"client_id": "GameMvc",
"redirect_uri": "https://localhost:44330/signin-oidc",
"response_type": "code id_token",
"scope": "openid profile email offline_access role experience subscription_level GameApi",
"response_mode": "form_post",
"nonce": "637207668423193165.NjAzZDAwM2UtMjc0Yi00ZTNiLTgyOWYtN2JhYTI5ZTkxNDBlZGJiN2FiZGEtN2ZmYy00OGFkLWE5MGItMzAzNmY3OGM1MGIx",
"state": "CfDJ8H3n8sVeRBlPopiMUAsqux7YiGRgIGQOeT0aF9aYMv-a40lLmjS_uEZw_jMeQAgkq7wFGq8mMMekKNm8U6uFL_kruFOX_gYjhJjzRZUKG1aHE0vpcJ0i0zYqd9aTh6elus8MxkP6NaGWszjf0wXSwVNboUdq_7NAvR_b4Pyt0sMkD5LTysTQ4VePtKi-FjDarp5xlRPvQUfiYpZfcyOGi7eqSlHuiVzD83uByMBhJ3cIA6h5n5zDzzotNpwxw_QLQk4A8zN06tgTHhUYTWV-5kxYiX3N84f__eyB3K_TCY94Kbm562BZX4TtfLzJHqJAdg",
"x-client-SKU": "ID_NETSTANDARD2_0",
"x-client-ver": "5.5.0.0"
}
}
I could check that the data is indeed persisted on the database..
Here below the /.well-known/openid-configuration
/ https://localhost:44320/.well-known/openid-configuration
{
"issuer": "https://localhost:44320",
"jwks_uri": "https://localhost:44320/.well-known/openid-configuration/jwks",
"authorization_endpoint": "https://localhost:44320/connect/authorize",
"token_endpoint": "https://localhost:44320/connect/token",
"userinfo_endpoint": "https://localhost:44320/connect/userinfo",
"end_session_endpoint": "https://localhost:44320/connect/endsession",
"check_session_iframe": "https://localhost:44320/connect/checksession",
"revocation_endpoint": "https://localhost:44320/connect/revocation",
"introspection_endpoint": "https://localhost:44320/connect/introspect",
"device_authorization_endpoint": "https://localhost:44320/connect/deviceauthorization",
"frontchannel_logout_supported": true,
"frontchannel_logout_session_supported": true,
"backchannel_logout_supported": true,
"backchannel_logout_session_supported": true,
"scopes_supported": [
"subscription_level",
"experience",
"role",
"address",
"phone",
"email",
"profile",
"openid",
"GameApiFullAccess",
"GameApiReadWrite",
"GameApiReadOnly",
"GameApi",
"offline_access"
],
"claims_supported": [
"subscription_level",
"experience",
"role",
"address",
"phone_number",
"phone_number_verified",
"email",
"email_verified",
"family_name",
"given_name",
"middle_name",
"nickname",
"preferred_username",
"profile",
"picture",
"website",
"gender",
"name",
"birthdate",
"locale",
"updated_at",
"zoneinfo",
"sub"
],
"grant_types_supported": [
"authorization_code",
"client_credentials",
"refresh_token",
"implicit",
"password",
"urn:ietf:params:oauth:grant-type:device_code"
],
"response_types_supported": [
"code",
"token",
"id_token",
"id_token token",
"code id_token",
"code token",
"code id_token token"
],
"response_modes_supported": [
"form_post",
"query",
"fragment"
],
"token_endpoint_auth_methods_supported": [
"client_secret_basic",
"client_secret_post"
],
"id_token_signing_alg_values_supported": [
"RS256"
],
"subject_types_supported": [
"public"
],
"code_challenge_methods_supported": [
"plain",
"S256"
],
"request_parameter_supported": true
}
Finally I had cached the error
The error is produced if...
builder.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking) for ConfigurationDbContext
So the desired option for Identity Server dbContext is QueryTrackingBehavior.TrackAll
BR
For me, I had created a new client and there was a missing configuration in
configuration.ClientGrantTypes table.
So I inserted a new ClientGrantType:
INSERT INTO configuration.ClientGrantTypes (GrantType, ClientId) VALUES ('authorization_code', YOURCLIENTID)
I am currently working on an API. The tokens are returned from an IdentityServer4.
I am trying to get back the sub id which is the id of the currently authorized user from the token claim. I can see it in the Claim here.
{
"nbf": 1512632838,
"exp": 1512636438,
"iss": "http://localhost:5000",
"aud": [
"http://localhost:5000/resources",
"testapi"
],
"client_id": "ServiceAccountAccess",
"sub": "21248582",
"auth_time": 1512632823,
"idp": "local",
"name": "TestUser",
"resource_id": "21260601",
"xena_fiscal_id": "21875",
"fiscal_name": "My company",
"picture_url": "/Content/images/avatar-company-xena.jpg",
"application_id": "16140911",
"scope": [
"openid",
"profile",
"testapi"
],
"amr": [
"password"
]
}
My API call is quite simple
[Authorize]
public async Task<ActionResult> ChangeFiscal([FromBody] long fiscalId)
{
var name = User.Claims.Where(c => c.Type == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier")
.Select(c => c.Value).SingleOrDefault();
}
What i cant understand is why sub or subject is being turned into
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier"
I can see from the api that its done it to quite a few of the claims
{
"nbf": 1512653706,
"exp": 1512657306,
"iss": "http://localhost:5000",
"aud": [
"http://localhost:5000/resources",
"testapi"
],
"client_id": "ServiceAccountAccess",
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier": "21248582",
"auth_time": 1512652100,
"http://schemas.microsoft.com/identity/claims/identityprovider": "local",
"name": "TestUser",
"supporter": "21248582",
"http://schemas.microsoft.com/claims/authnmethodsreferences": "password",
"resource_id": "21527443",
"xena_fiscal_id": "21876",
"fiscal_name": "this",
"picture_url": "/Content/images/avatar-company-xena.jpg",
"scope": [
"openid",
"profile",
"testapi"
]
}
Its taken an hour to figure out that the Microsoft JWT handler turns these standard claims into Microsoft proprietary ones.
By adding the following line to the startup Configure method i was able to turn off this annoying "feature"
JwtSecurityTokenHandler.InboundClaimTypeMap.Clear()
I am trying to connect a native mobile app(xamarin) to Identity Server. I had initially set the flow to be implicit, and I was told its incorrect. Hence I changed it Authorization Code flow.
Here is how my client definition looks like
new Client
{
ClientId = "Xamarin",
ClientName = "Xamarin Client",
AllowedGrantTypes = GrantTypes.Code,
AllowAccessTokensViaBrowser = true,
RedirectUris = { "http://xx.xx.xx.xx/signin-oidc" },
PostLogoutRedirectUris = { "http://xx.xx.xx.xx/signin-oidc" },
AllowedCorsOrigins = { "http://xx.xx.xx.xx" },
AllowedScopes =
{
StandardScopes.OpenId.Name,
StandardScopes.Profile.Name,
"api1"
},
RequireConsent = false
}
And from my xamarin app, this is how I connect to the identity server.
void LoginButton_Clicked(object sender, EventArgs e)
{
StartFlow("token", "api1");
}
public void StartFlow(string responseType, string scope)
{
var authorizeRequest =
new AuthorizeRequest("http://xx.xx.xx.xx/connect/authorize");
var dic = new Dictionary<string, string>();
dic.Add("client_id", "Xamarin");
dic.Add("response_type", responseType);
dic.Add("scope", scope);
dic.Add("redirect_uri", "http://xx.xx.xx.xx/signin-oidc");
dic.Add("nonce", Guid.NewGuid().ToString("N"));
_currentCSRFToken = Guid.NewGuid().ToString("N");
dic.Add("state", _currentCSRFToken);
var authorizeUri = authorizeRequest.Create(dic);
webLogin.Source = authorizeUri;
webLogin.IsVisible = true;
}
I get the the error "unauthorized_client" in the mobile app, and in my logs in server is shows:
fail: IdentityServer4.Validation.AuthorizeRequestValidator[0]
Invalid grant type for client: implicit
{
"ClientId": "Xamarin",
"ClientName": "Xamarin Client",
"RedirectUri": "http://xx.xx.xx.xx/signin-oidc",
"AllowedRedirectUris": [
"http://xx.xx.xx.xx/signin-oidc"
],
"SubjectId": "anonymous",
"ResponseType": "token",
"ResponseMode": "fragment",
"GrantType": "implicit",
"RequestedScopes": "",
"State": "5c53c5e5bbe44c0f8c5d4b401df0938e",
"Raw": {
"client_id": "Xamarin",
"response_type": "token",
"scope": "api1",
"redirect_uri": "http://xx.xx.xx.xx/signin-oidc",
"nonce": "49f21e8873d744bea76f6f00ebae3eb4",
"state": "5c53c5e5bbe44c0f8c5d4b401df0938e"
}
}
fail: IdentityServer4.Endpoints.AuthorizeEndpoint[0]
Request validation failed
info: IdentityServer4.Endpoints.AuthorizeEndpoint[0]
{
"ClientId": "Xamarin",
"ClientName": "Xamarin Client",
"RedirectUri": "http://xx.xx.xx.xx/signin-oidc",
"AllowedRedirectUris": [
"http://xx.xx.xx.xx/signin-oidc"
],
"SubjectId": "anonymous",
"ResponseType": "token",
"ResponseMode": "fragment",
"GrantType": "implicit",
"RequestedScopes": "",
"State": "5c53c5e5bbe44c0f8c5d4b401df0938e",
"Raw": {
"client_id": "Xamarin",
"response_type": "token",
"scope": "api1",
"redirect_uri": "http://xx.xx.xx.xx/signin-oidc",
"nonce": "49f21e8873d744bea76f6f00ebae3eb4",
"state": "5c53c5e5bbe44c0f8c5d4b401df0938e"
}
}
But if you check my code I do not have a implict flow for this client type. And I have double checked my database to ensure that it is authorization_code. I appreciate if someone could help me fixing this.
It does not look as though idsrv4 supports code, code token nor code id_token token as response_type at the moment - only code id_token. At least the current demo site fails when trying the test client and a /authorize request using the server.code client.
The only working client I found related to authorization code was with a Hybrid setup (code id_token / server.hybrid):
https://demo.identityserver.io/connect/authorize?
client_id=server.hybrid&
response_type=code id_token&
response_mode=fragment&
redirect_uri=https://notused&
scope=openid api&
state=1&
nonce=2
Not sure why that is, as it's already in the list of supported_response_types in the discovery document. Maybe Dominic/Brock can fill in.
"response_types_supported": [
"code",
"token",
"id_token",
"id_token token",
"code id_token",
"code token",
"code id_token token"
],
Non working code flow auth request (unsupported_response_type):
https://demo.identityserver.io/connect/authorize?
client_id=server.code&
response_type=code&
response_mode=fragment&
redirect_uri=https://notused&
scope=openid api&
state=1&
nonce=2