error:invalid_scope - IdentityServer Flow.ClientCredential - oauth-2.0

I'm having a Client in my IdentityServer3
new Client
{
ClientName = "Client Credentials Flow Client",
Enabled = true,
ClientId = "clientcredentials.reference",
Flow = Flows.ClientCredentials,
ClientSecrets = new List<Secret>
{
new Secret("secret".Sha256()),
},
AllowedScopes = new List<string>()
{
"read",
"write"
}
}
I hosted the Token Service in my local IIS and I tried to ping the Token using Postman, but it given an error {"error":"invalid_scope"}
Host URL:
https://localhost:5775/core/connect/token
Header:
Content-Type:application/x-www-form-urlencoded
Body:
grant_type=client_credentials
&cliend_id=clientcredentials.reference
&client_secret=secret
Note: I'm using pure IdentityServer3 package not Thinktecture

Check the Scopes "read" and "write" in Scopes declaration
new Scope
{
Name = "read",
DisplayName = "Read data",
Type = ScopeType.Resource,
Emphasize = false,
ScopeSecrets = new List<Secret>
{
new Secret("secret".Sha256())
}
},
new Scope
{
Name = "write",
DisplayName = "Write data",
Type = ScopeType.Resource,
Emphasize = true,
ScopeSecrets = new List<Secret>
{
new Secret("secret".Sha256())
}
}
I think its missed... Check it once...

Related

How to configure Identity Server with NSwag API using IIdentityServerBuilder's .AddApiAuthorization()?

I'd like to create an authentication/authorization flow of sorts using Identity Server to have a user authorize themselves in my Swagger API so that they may access endpoints marked with the [Authorize] attribute. This is the current flow I have:
I have Swagger set up with the NSwag middleware with the OAuth2 security scheme:
services.AddMvcCore().AddApiExplorer();
services.AddOpenApiDocument(settings =>
{
settings.Title = "MyProject Services";
settings.Version = "1.0";
settings.AddSecurity("oauth2", new NSwag.OpenApiSecurityScheme
{
Type = NSwag.OpenApiSecuritySchemeType.OAuth2,
Flow = NSwag.OpenApiOAuth2Flow.AccessCode,
AuthorizationUrl = "/connect/authorize",
TokenUrl = "/connect/token",
Scopes = new Dictionary<string, string>
{
{ "MyProjectServicesAPI", "API Access" }
}
});
settings.OperationProcessors.Add(new AspNetCoreOperationSecurityScopeProcessor("oauth2"));
});
And the OAuth2 client settings in Configure():
app.UseOpenApi();
app.UseSwaggerUi3(options =>
{
options.OAuth2Client = new NSwag.AspNetCore.OAuth2ClientSettings
{
ClientId = "MyProjectAPI",
ClientSecret = "mysecret",
UsePkceWithAuthorizationCodeGrant = true
};
});
After a user selects the scope and authorizes, they get redirected to my Identity Server Login Page I scaffolded and from there they can login. Once they put in their credentials and press, 'Login', they then get redirected back to the Swagger API. So far so good. Now this is where I start to have trouble cause I would like to later add policies so a user must have a specific claim to access an endpoint, but right now, I'm not able to see any of my user's claims in the JWT Bearer token that's in the request header when I access and endpoint. The only information I get about my user is in the 'sub' which is their GUID. I'd like to be able to get their username, email, and role(s) as well.
This is what I have setup for Identity Server so far (and where I'm currently stuck):
Under ConfigureServices():
services.AddIdentityServer()
.AddDeveloperSigningCredential()
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>(options =>
{
options.IdentityResources = new IdentityResourceCollection
{
new IdentityResources.OpenId(),
new IdentityResources.Profile(),
new IdentityResources.Email(),
new IdentityResource
{
Name = "roles",
DisplayName = "roles",
UserClaims = new List<string> { JwtClaimTypes.Role }
},
new IdentityResource
{
Name = "basicInfo",
DisplayName = "basic info",
UserClaims = new List<string> {
JwtClaimTypes.PreferredUserName
}
}
};
options.Clients = new ClientCollection
{
new Client
{
ClientId = "MyProjectAPI",
ClientName = "My Project Services API",
ClientSecrets = { new Secret("mysecret".Sha256()) },
AllowedGrantTypes = GrantTypes.Code,
AllowAccessTokensViaBrowser = true,
RedirectUris = { "https://localhost:44319/swagger/oauth2-redirect.html" },
PostLogoutRedirectUris = { "https://localhost:44319/Identity/Account/Logout" },
AllowedScopes = {
"basicInfo",
"roles",
"MyProjectServicesAPI",
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
IdentityServerConstants.StandardScopes.Email,
RequirePkce = true,
RequireConsent = false
}
};
});
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddIdentityServerJwt()
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters()
{
ValidateIssuer = true
};
});
And then in the pipeline:
app.UseIdentityServer();
app.UseAuthentication();
app.UseAuthorization();
I recently got this error that's being thrown from Identity Server's OidcConfigurationController:
'Can't determine the type for the client 'MyProject''
I'm putting the Authorization Code type for the AllowedGrantTypes in my client so I'm not quite sure why it's throwing that error.
Do I need to be adding the claims to the Bearer token myself? If I'm including the scopes, why aren't those claims showing up? Thank you in advance for any assistance.
EDIT #1: I did resolve the error I was receiving from the OidcConfigurationController. I will add the JWT Bearer token only shows the 'MyProjectServicesAPI" scope and nothing else. However, my oidc discovery doc shows all of them?
I think I was able to partially solve my problem. So I didn't have Identity Server's Profile Service set up to grab my user's ID so it could grab the identity claims.
ProfileService.cs:
private readonly UserManager<ApplicationUser> _userManager;
public ProfileService(UserManager<ApplicationUser> userManager)
{
_userManager = userManager;
}
// Add custom claims to access token.
public async Task GetProfileDataAsync(ProfileDataRequestContext context)
{
context.IssuedClaims.AddRange(context.Subject.Claims);
var user = await _userManager.GetUserAsync(context.Subject);
var roles = await _userManager.GetRolesAsync(user);
var claims = new List<Claim>
{
new Claim(JwtClaimTypes.Email, user.Email),
new Claim(JwtClaimTypes.PreferredUserName, user.UserName),
};
foreach (var claim in claims)
{
context.IssuedClaims.Add(claim);
}
foreach (var role in roles)
{
context.IssuedClaims.Add(new Claim(JwtClaimTypes.Role, role));
}
}
public async Task IsActiveAsync(IsActiveContext context)
{
var user = await _userManager.GetUserAsync(context.Subject);
context.IsActive = (user != null) && user.LockoutEnabled;
}
And then back in Startup.cs:
services.AddIdentityServer()
.AddDeveloperSigningCredential()
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>(options =>
{
....
})
.AddProfileService<ProfileService>();
And that's it! Order does matter as I did have AddProfileService() before my AddApiAuthorization() and that didn't work. All of my scopes still aren't showing in my JWT token, so I will need to revisit that, even though the right claims are being pulled from those Identity resources.

How set swagger client claims with identityServer4

I'm protecting a .NET Core Web API with an access token issued by an IDS4.
It works and I added some claims in the client configuration, as follows:
// ... other code
new Client
{
ClientId = "apiclient",
AllowedGrantTypes = GrantTypes.ClientCredentials,
ClientSecrets = {
new Secret("mysupersecret".Sha256())
},
AllowedScopes = {
"joinot",
JwtClaimTypes.Role,
},
Claims = new List<Claim>() { new Claim("role", "WonderWoman"), new Claim("VatId", "123abc") },
},
// ... other code
These are the claims that I see in the webapi.
I found what I added with the prefix "client_".
For testing purposes I'm using swagger and I have this config for it:
new Client {
ClientId = "swagger_api_client",
ClientName = "Swagger API Client",
AllowedGrantTypes = GrantTypes.Implicit,
AllowAccessTokensViaBrowser = true,
RedirectUris = {"http://localhost:57303/swagger/oauth2-redirect.html"},
AllowedScopes = {
"joinot",
JwtClaimTypes.Role,
},
Claims = new List<Claim>() { new Claim("role", "ManOfSteel"), new Claim("VatId", "abc123") },
RequireConsent = false
},
This means that I have to authenticate with an interactive user and than I can call the webapi.
When I do it, the claims I found in the webapi are not as I expected.
"client_role" and "client_VatId" are not in the list.
How can I insert the claims for both the console and the swagger client?
You can set AlwaysSendClientClaims to true :
Claims = new List<Claim>() { new Claim("role", "WonderWoman"), new Claim("VatId", "123abc") },
AlwaysSendClientClaims =true,
If set, the client claims will be sent for every flow. If not, only for client credentials flow (default is false) . So your console application which use client credential flow would work even not set that property.
Reference document : http://docs.identityserver.io/en/latest/reference/client.html

IdentityServer 3 not validating secret, "invalid_client" response: Implicit flow, revocation endpoint

I'm using oidc-client in my SPA application against IdentityServer3, using implicit flow.
Revoking my reference token on sign out is not working.
I have set revokeAccessTokenOnSignout: true and client_secret to a dummy secret, and I see the request being sent out. However I'm getting a "400 bad request invalid client" response.
Here's the request being sent:
And here's the response:
{"error":"invalid_client"}
And here's the IdentityServer config:
new Client
{
ClientName = "Client Name",
ClientId = "myclientid",
ClientSecrets = new List<Secret>
{
new Secret("secret".Sha256())
},
AccessTokenType = AccessTokenType.Reference,
Flow = Flows.Implicit,
RequireConsent = false,
RedirectUris = new List<string>
{
...
},
AllowedCorsOrigins = new List<string>
{
...
},
PostLogoutRedirectUris = new List<string>
{
...
},
AllowedScopes = new List<string>
{
...
} //.. allowed
}, //..new client
Any ideas what I might be doing wrong?

error:invalid_client - IdentityServer Flow.ClientCredential

I'm having a Client in my IdentityServer3
new Client
{
ClientName = "Client Credentials Flow Client with Client Certificate",
ClientId = "certclient",
ClientSecrets = new List<Secret>
{
new Secret
{
Value = "61B754C541BBCFC6A45A9E9EC5E47D8702B78C29",
Type = Constants.SecretTypes.X509CertificateThumbprint,
}
},
Flow = Flows.ClientCredentials,
AllowedScopes = new List<string>
{
"read",
"write"
},
}
I hosted the Token Service in my local IIS and I tried to ping the Token using Postman, but it given an error {"error":"invalid_client"}
Host URL:
https://localhost:5775/core/connect/token
Header:
Content-Type:application/x-www-form-urlencoded
Authorization:Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Body:
grant_type=client_credentials
&cliend_id=certclient
&client_secret=61B754C541BBCFC6A45A9E9EC5E47D8702B78C29
Note: I'm using pure IdentityServer3 package not Thinktecture

IdentityServer 3 and ASP.NET Identity: how to get user information

I'm using IdentityServer 3 with ASP.NET Identity as its user store. I have followed this article to set up IdentityServer and my client is an ASP MVC web application. I'm able to login from my client, but I don't understand how to get user information on the client side. On the server side Im using:
var scopes = new Scope[]
{
StandardScopes.OpenId,
StandardScopes.Email,
new Scope
{
Name = "roles",
Claims = new List<ScopeClaim>
{
new ScopeClaim("role")
}
}
};
var clients = new Client[]
{
new Client
{
ClientId = "mvc-demo",
ClientName = "MVC Demo Client",
Flow = Flows.Implicit,
RedirectUris = new List<string>
{
"http://localhost:16652/"
},
AllowedScopes = new List<string>
{
"openid", "email", "roles"
}
}
};
var factory = new IdentityServerServiceFactory().Configure(connectionString);
factory.UseInMemoryClients(clients);
factory.UseInMemoryScopes(scopes);
And on the client side:
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
AuthenticationType = "oidc",
SignInAsAuthenticationType = "cookies",
Authority = "https://localhost:44305/",
ClientId = "mvc-demo",
RedirectUri = "http://localhost:16652/",
ResponseType = "id_token token",
Scope = "openid email roles",
Notifications = new OpenIdConnectAuthenticationNotifications
{
SecurityTokenValidated = n =>
{
var id = n.AuthenticationTicket.Identity;
var email = id.FindFirst(Constants.ClaimTypes.Email);
var roles = id.FindAll(Constants.ClaimTypes.Role);
// create new identity and set name and role claim type
var nid = new ClaimsIdentity(
id.AuthenticationType,
Constants.ClaimTypes.Email,
Constants.ClaimTypes.Role);
nid.AddClaim(email);
nid.AddClaims(roles);
// add some other app specific claim
//nid.AddClaim(new Claim("app_specific", "some data"));
n.AuthenticationTicket = new AuthenticationTicket(
nid,
n.AuthenticationTicket.Properties);
return Task.FromResult(0);
}
}
But I cant get the information about users email for example.
I managed to send claims to my client application this way:
var scopes = new Scope[]
{
StandardScopes.OpenId,
new Scope
{
Name = "roles",
Type = ScopeType.Identity,
Claims = new List<ScopeClaim>
{
new ScopeClaim("role")
}
},
new Scope
{
Name = "email",
Type = ScopeType.Identity,
Claims = new List<ScopeClaim>
{
new ScopeClaim(Constants.ClaimTypes.Email)
}
}
};
var clients = new Client[]
{
new Client
{
ClientId = "mvc-demo",
ClientName = "MVC Demo Client",
Flow = Flows.Implicit,
RedirectUris = new List<string>
{
"http://localhost:16652/"
},
AllowedScopes = new List<string>
{
"openid", "email", "roles"
}
}
};
And on the client side, I needed to turn off claims transformation, to fetch them correctly, like this(in OWIN startup class):
AntiForgeryConfig.UniqueClaimTypeIdentifier = Constants.ClaimTypes.Subject;
JwtSecurityTokenHandler.InboundClaimTypeMap = new Dictionary<string, string>();

Resources