Unknown client or client not enabled Identity Server 4 - c#

I have been getting this error and i have searched for answer online and almost all of them has been talking about requesturis and i have double checked to make sure that my uris are configured properly. I did not find any clue about it. Any thoughts.
Identity Server 4 settings:-
public static IEnumerable<Client> GetClients()
{
return new List<Client>()
{
new Client
{
ClientName="KtsWeb App",
ClientId="ktswebclient",
AllowedGrantTypes= GrantTypes.Hybrid,
AccessTokenType = AccessTokenType.Reference,
RedirectUris = new List<string>()
{
"https://localhost:44355/signin-oidc" //Client URL Address
},
AllowedScopes =
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile
}
}
};
}
Client settings:-
services.AddAuthentication(options =>
{
options.DefaultScheme = "Cookies";
options.DefaultChallengeScheme = "oidc";
}).AddCookie("Cookies",
(options) =>
{
options.AccessDeniedPath = "/Authorization/AccessDenied";
})
.AddOpenIdConnect("oidc", options =>
{
options.SignInScheme = "Cookies";
options.Authority = "https://localhost:44380"; //Identity Server URL Address
options.ClientId = "ktswebclient";
options.ResponseType = "code id_token";
options.Scope.Add("openid");
options.Scope.Add("profile");
options.SaveTokens = true;
});

You should always check the identity server logs it would have given you a clear error message probably unsupported grant type.
You have created a hybrid client but forgot to add the secret.
new Client
{
ClientId = "mvc",
ClientName = "MVC Client",
AllowedGrantTypes = GrantTypes.Hybrid,
ClientSecrets =
{
new Secret("secret".Sha256())
},
RedirectUris = { "http://localhost:5002/signin-oidc" },
PostLogoutRedirectUris = { "http://localhost:5002/signout-callback-oidc" },
AllowedScopes =
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
"api1"
},
AllowOfflineAccess = true
}
};
Your code isnt supplying the secret
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
services.AddAuthentication(options =>
{
options.DefaultScheme = "Cookies";
options.DefaultChallengeScheme = "oidc";
})
.AddCookie("Cookies")
.AddOpenIdConnect("oidc", options =>
{
options.SignInScheme = "Cookies";
options.Authority = "http://localhost:5000";
options.RequireHttpsMetadata = false;
options.ClientId = "mvc";
options.ClientSecret = "secret";
options.ResponseType = "code id_token";
options.SaveTokens = true;
options.GetClaimsFromUserInfoEndpoint = true;
options.Scope.Add("api1");
options.Scope.Add("offline_access");
options.ClaimActions.MapJsonKey("website", "website");
});

Related

Why is it not possible to set options in IdentityServer?

I have been tried to apply several kind of setting on Startup.cs as shown ob the given link:
https://identityserver4.readthedocs.io/en/latest/quickstarts/2_interactive_aspnetcore.html
But unfortunately I cannot set the base url for Authority parameter when I check on the following url:
https://my-pc-id:8085/_configuration/MyApp.WebUI
It seems to be weird, because if we cannot set this parameter, why there is such an option on this config?
using System.IdentityModel.Tokens.Jwt;
// ...
JwtSecurityTokenHandler.DefaultMapInboundClaims = false;
services.AddAuthentication(options =>
{
options.DefaultScheme = "Cookies";
options.DefaultChallengeScheme = "oidc";
})
.AddCookie("Cookies")
.AddOpenIdConnect("oidc", options =>
{
options.Authority = "my-pc-id:8085";
options.ClientId = "mvc";
options.ClientSecret = "secret";
options.ResponseType = "code";
options.SaveTokens = true;
});
Change the Authority property like so:
// base-address of your identityserver
.Authority = "https://my-pc-id:8085/_configuration/MyApp.WebUI";

Infinite redirects between Identity Server and Website

I've got the following client set up in IdentityServer:
internal class Clients
{
public static IEnumerable<Client> Get()
{
return new List<Client>
{
new Client
{
ClientId = "Client",
ClientName = "Client",
ClientSecrets = new List<Secret> {new Secret("blablabla".Sha256())},
AllowedGrantTypes = GrantTypes.Code,
RedirectUris = { Startup.Configuration.GetValue<string>("Clients", "https://localhost:5002") + "/signin-oidc" },
PostLogoutRedirectUris = { Startup.Configuration.GetValue<string>("Clients", "https://localhost:5002") + "/signout-oidc" },
AllowedScopes = new List<string>
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
"roles",
"Business-to-Business-users",
"reporting-urls"
},
RequirePkce = true,
AllowPlainTextPkce = false,
AllowAccessTokensViaBrowser = true
}
};
}
}
I'm trying to modify the mvc client to login to the above identity server. In startup.cs I modified cllientID, ClientSecret and Authority to match the client settings. This is my ConfigureServices():
services.AddAuthentication(options =>
{
options.DefaultScheme = "cookie";
options.DefaultChallengeScheme = "oidc";
options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
})
.AddCookie("cookie")
.AddOpenIdConnect("oidc", options =>
{
options.Authority = Configuration.GetValue<string>("IdentityHost", "https://localhost:5000");
options.ClientId = "Client";
options.ClientSecret = "blablabla";
options.RequireHttpsMetadata = false;
options.GetClaimsFromUserInfoEndpoint = true;
options.ResponseType = "code";
options.UsePkce = true;
options.ResponseMode = "query";
options.Scope.Add("roles");
options.Scope.Add("Business-to-Business-users");
options.Scope.Add("reporting-urls");
options.RequireHttpsMetadata = false;
options.ClaimActions.MapUniqueJsonKey("role", "role");
options.ClaimActions.MapUniqueJsonKey("Business-to-Business-user", "Business-to-Business-user");
options.ClaimActions.MapUniqueJsonKey("reporting-url", "reporting-url");
options.TokenValidationParameters = new TokenValidationParameters
{
RoleClaimType = "role",
};
});
first I got a bug that he needs https but instead uses http. So I added the following code to my Configure:
app.Use((context, next) => {
context.Request.Scheme = "https";
return next();
});
Now that this error was solved, I ran into a different one.
As soon as I'm trying to login to my client, I got the following error in my browser (Opera): "ERR_TOO_MANY_REDIRECTS".
Does anyone have an idea how I can proceed? Both Identity and the client are seperate docker containers.

Exception: Correlation failed. Unknown location (Azure AD B2C)

I have an ASP.NET Core 2.2 application with the following configuration:
And this is my Startup.cs class
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddAuthentication(options =>
{
options.DefaultScheme = "Cookies";
options.DefaultChallengeScheme = "oidc";
})
.AddCookie("Cookies")
.AddOpenIdConnect("oidc", options =>
{
options.SignInScheme = "Cookies";
options.Authority = $"{ Configuration.GetValue<string>("AzureAdB2C:Instance") }/{ Configuration.GetValue<string>("AzureAdB2C:Tenant") }/{ Configuration.GetValue<string>("AzureAdB2C:SignUpSignInPolicyId") }/v2.0";
options.ClientId = Configuration.GetValue<string>("AzureAdB2C:ClientId");
options.ResponseType = "code id_token";
options.SaveTokens = true;
options.ClientSecret = Configuration.GetValue<string>("AzureAdB2C:ClientSecret");
});
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}
When I run this the B2C login page pops-up, however once I enter the credentials I get the error below. URL is redirected to https://localhost:xxxx/signin-oidc
How can I solve this problem?
This is the similar issue, the same error occurred when external login is canceled and redirects to the source application. You could use OnRemoteFailure to handle the exception.
AddOpenIdConnect("oidc", options => {
// ...
options.Events = new OpenIdConnectEvents
{
OnRemoteFailure = ctx =>
{
ctx.Response.Redirect("/error?FailureMessage=" + UrlEncoder.Default.Encode(ctx.Failure.Message));
ctx.HandleResponse();
return Task.FromResult(0);
}
};
});

Authenticating an ASP.NET Core WebAPI using an ASP.NET Core MVC with Azure AD

I have two web applications: one ASP.NET Core MVC Website and one ASP.NET Core Web API (using ASP.NET Core 2.1).
I authenticate the users in the website using Azure AD. When I pass the access_token from the website to the API (using the Authorization header with "Bearer access_token"); I have this error:
Microsoft.IdentityModel.Tokens.SecurityTokenInvalidSignatureException:
IDX10503: Signature validation failed. Keys tried:
'Microsoft.IdentityModel.Tokens.X509SecurityKey , KeyId: ... '.
I don't understand why.
Here is the configuration of the Website:
services.AddAuthentication(o =>
{
o.DefaultChallengeScheme = "aad";
o.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
o.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
})
.AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, o =>
{
o.Authority = azureAdsettings.Authority;
o.Audience = azureAdsettings.ClientId;
})
.AddCookie()
.AddOpenIdConnect("aad", o =>
{
o.Authority = azureAdsettings.Authority;
o.AuthenticationMethod = OpenIdConnectRedirectBehavior.RedirectGet;
o.ClientId = azureAdsettings.ClientId;
o.ClientSecret = azureAdsettings.ClientSecret;
o.ResponseType = OpenIdConnectResponseType.CodeIdToken;
o.SaveTokens = true;
o.TokenValidationParameters = new TokenValidationParameters
{
ValidIssuer = azureAdsettings.Authority
};
o.Events = new OpenIdConnectEvents
{
OnTicketReceived = ctx =>
{
return Task.CompletedTask;
},
OnAuthorizationCodeReceived = async ctx =>
{
TokenProvider tokenProvider = (TokenProvider)ctx.HttpContext.RequestServices.GetRequiredService<ITokenProvider>();
await tokenProvider.AcquireTokenByAuthorizationCodeAsync(ctx);
},
OnAuthenticationFailed = context =>
{
context.Response.Redirect("/Error");
context.HandleResponse(); // Suppress the exception
return Task.CompletedTask;
},
};
});
And here is the configuration of the API:
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options =>
{
options.Authority = this.Configuration["AzureAd:Authority"];
options.Audience = this.Configuration["AzureAd:ClientId"];
options.TokenValidationParameters.ValidateIssuer = true;
options.TokenValidationParameters.IssuerValidator = ValidateIssuer;
});
The azureAdsettings object is exaclty the same in both appsettings.json.
The authentication on the website seems to work nicely. I can get the authorization code and retreive access token.

Identityserver4 and API in single project

I have an IdentityServer4 asp.net-core host setup for Resource Owner Password Grant using JWT Bearer tokens and an API in a separate asp.net-core host which has my API and two Angular clients.
The Authentication and Authorization is working from my two Angular clients to my API.
Now I need to expose an API in the IdentityServer4 host so I can create users from one of the Angular clients.
I have copied my Authentication and Authorization setup from my API over to my IdentityServer4 host, however, I cannot get it to Authenticate.
In the below code, within the API, I can set a breakpoint on the jwt.Authority... line and the first call will trigger this breakpoint in my API but not in the IdentityServer4 host.
Authentication
services.AddAuthentication(IdentityServerAuthenticationDefaults.AuthenticationScheme)
.AddJwtBearer(jwt =>
{
jwt.Authority = config.Authentication.Authority; //Breakpoint here
jwt.RequireHttpsMetadata = config.Authentication.RequireHttpsMetadata;
jwt.Audience = Common.Authorization.Settings.ServerApiName;
});
Authorization
I'm not sure if it's relevant, but I'm using role based authorization, the following is the setup for this.
var authPolicyBuilder = new AuthorizationPolicyBuilder()
.RequireRole(Common.Authorization.Settings.ServerApiRoleBasePolicyName)
.Build();
services.AddMvc(options =>
{
options.Filters.Add(new AuthorizeFilter(authPolicyBuilder));
...
services.AddAuthorization(options =>
{
options.AddPolicy(Common.Authorization.Settings.ServerApiSetupClientAdminRolePolicyName, policy =>
{
policy.RequireClaim("role", Common.Authorization.Settings.ServerApiSetupClientAdminRolePolicyName);
I've extracted the following from my logging:
What I see is that in the non-working case, I never get to the point of invoking the JWT validation (#3 in the working logs).
This is just a tiny extract of my logs, I can share them in entirety if needs be.
Working
1 Request starting HTTP/1.1 GET http://localhost:5100/packages/
(SourceContext:Microsoft.AspNetCore.Hosting.Internal.WebHost)
2 Connection id "0HLC8PLQH2NRU" started.
(SourceContext:Microsoft.AspNetCore.Server.Kestrel)
3 Request starting HTTP/1.1 GET http://localhost:5000/.well-known/openid-configuration
(SourceContext:Microsoft.AspNetCore.Hosting.Internal.WebHost)
--Truncated--
Not Working
1 Request starting HTTP/1.1 GET http://localhost:5000/users
(SourceContext:Microsoft.AspNetCore.Hosting.Internal.WebHost)
--Truncated--
Clients
new Client
{
ClientId = "setup_app",
ClientName = "Setup App",
AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,
AccessTokenType = AccessTokenType.Jwt,
AccessTokenLifetime = 3600,
IdentityTokenLifetime = 3600,
UpdateAccessTokenClaimsOnRefresh = true,
SlidingRefreshTokenLifetime = 3600,
AllowOfflineAccess = false,
RefreshTokenExpiration = TokenExpiration.Absolute,
RefreshTokenUsage = TokenUsage.OneTimeOnly,
AlwaysSendClientClaims = true,
Enabled = true,
RequireConsent = false,
AlwaysIncludeUserClaimsInIdToken = true,
AllowedCorsOrigins = { config.CorsOriginSetupClient },
ClientSecrets =
{
new Secret(Common.Authorization.Settings.ServerApiSetupClientSecret.Sha256())
},
AllowedScopes =
{
Common.Authorization.Settings.ServerApiName,
}
},
new Client
{
ClientId = "client_app",
ClientName = "Client App",
AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,
AccessTokenType = AccessTokenType.Jwt,
AccessTokenLifetime = 3600,
IdentityTokenLifetime = 3600,
UpdateAccessTokenClaimsOnRefresh = true,
SlidingRefreshTokenLifetime = 3600,
AllowOfflineAccess = false,
RefreshTokenExpiration = TokenExpiration.Absolute,
RefreshTokenUsage = TokenUsage.OneTimeOnly,
AlwaysSendClientClaims = true,
Enabled = true,
RequireConsent = false,
AlwaysIncludeUserClaimsInIdToken = true,
AllowedCorsOrigins = { config.CorsOriginSetupClient },
ClientSecrets =
{
new Secret(Common.Authorization.Settings.ServerApiAppClientSecret.Sha256())
},
AllowedScopes =
{
Common.Authorization.Settings.ServerApiName,
}
}
IdentityResources
return new List<IdentityResource>
{
new IdentityResources.OpenId(),
new IdentityResources.Profile(),
new IdentityResource(Common.Authorization.Settings.ServerApiScopeName, new []{
"role",
Common.Authorization.Settings.ServerApiSetupClientAdminRolePolicyName,
Common.Authorization.Settings.ServerApiAppClientAdminRolePolicyName,
Common.Authorization.Settings.ServerApiAppClientUserRolePolicyName,
}),
};
User
var adminUser = new ApplicationUser
{
UserName = "admin",
Email = "admin#noreply",
};
adminUser.Claims = new List<IdentityUserClaim>
{
new IdentityUserClaim(new Claim(JwtClaimTypes.PreferredUserName, adminUser.UserName)),
new IdentityUserClaim(new Claim(JwtClaimTypes.Email, adminUser.Email)),
new IdentityUserClaim(new Claim("role", Common.Authorization.Settings.ServerApiSetupClientAdminRolePolicyName)),
new IdentityUserClaim(new Claim("role", Common.Authorization.Settings.ServerApiRoleBasePolicyName)),
new IdentityUserClaim(new Claim("profileImage", $"https://robohash.org/{Convert.ToBase64String(System.Security.Cryptography.MD5.Create().ComputeHash(System.Text.Encoding.UTF8.GetBytes(adminUser.UserName)))}?set=set2"))
};
adminUser.AddRole(Common.Authorization.Settings.ServerApiSetupClientAdminRolePolicyName);
API
new ApiResource(Common.Authorization.Settings.ServerApiName, "Server API"){
ApiSecrets =
{
new Secret(Common.Authorization.Settings.ServerApiAppClientSecret.Sha256())
},
},
Look up here https://github.com/IdentityServer/IdentityServer4.Samples
Seems like it should be like:
Authentication:
services.AddAuthentication("Bearer")
.AddIdentityServerAuthentication(options =>
{
options.Authority = config.Authentication.Authority;
options.RequireHttpsMetadata = false;
options.ApiName = ServerApiName;
options.ApiSecret = ServerApiAppClientSecret;
});
Or with JWT you can try like:
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options =>
{
options.Authority = config.Authentication.Authority;
options.RequireHttpsMetadata = false;
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateAudience = true,
ValidAudiences = new[]
{
$"{config.Authentication.Authority}/resources",
ServerApiName
},
};
});
Also, you will able to add authorization policy, like:
Authorization:
services.AddMvc(opt =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.RequireScope("api").Build();
opt.Filters.Add(new AuthorizeFilter(policy));
})
There is a MS out of the box service designed to add support for local APIs
First in IDS4 startup.cs, ConfigureServices add
services.AddLocalApiAuthentication();
Then in IDS4 config.cs in your client declaration
AllowedScopes = {
IdentityServerConstants.LocalApi.ScopeName, <<<< ---- This is for IDS4 Api access
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
IdentityServerConstants.StandardScopes.Email
...
Still in config add the new scope to ApiScopes
new ApiScope(IdentityServerConstants.LocalApi.ScopeName)
Note
IdentityServerConstants.LocalApi.ScopeName resolves to 'IdentityServerApi'
Now in your shiny new Api located in the IDS4 project add the authorize tag to your api endpoint
[Authorize(IdentityServerConstants.LocalApi.PolicyName)]
[HttpGet]
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
Finally you need to request this new scope in your Client
Scope = "openid sig1 api1 profile email offline_access company IdentityServerApi",
Thats it
I think this could help, it's included in the community samples.

Categories

Resources