I am getting "code challenge required" when using IdentityServer4
Solution 1
I am pretty much sure that you are using version 4.0
or above. Let me know if I am correct?
In version 4.0
and above, the code flow + PKCE
is used by default, as this is more secure than Hybrid flow
according to the documentation.
Here is the link https://identityserver4.readthedocs.io/en/latest/topics/grant_types.html and link to relevant issue on github https://github.com/IdentityServer/IdentityServer4/issues/3728 describing it as a breaking change.
I also struggled with it for about 2 hours when I upgraded IdentityServer4 package to the latest version in one of my projects.
If you want to use Hybrid flow
set RequirePkce
to false
in your client configuration.
"Clients": {
/* Code removed for brevity */
RequirePkce : "false"
}
Solution 2
Got that error today and solved it by switching from:
options.ResponseType = "code id_token";
to
options.ResponseType = "code";
options.UsePkce = true;
Here's my complete client-side options:
options.Authority = "http://localhost:8000";
options.RequireHttpsMetadata = false; // dev only
options.ClientId = "testAPI";
options.ClientSecret = secret;
// code flow + PKCE (PKCE is turned on by default)
options.ResponseType = "code";
options.UsePkce = true;
options.Scope.Clear();
options.Scope.Add("openid");
options.Scope.Add("profile");
options.Scope.Add("offline_access");
options.Scope.Add("testAPI");
options.ClaimActions.MapJsonKey("website", "website");
//options.ResponseMode = "form_post";
//options.CallbackPath = "/signin-oidc";
// keeps id_token smaller
options.GetClaimsFromUserInfoEndpoint = true;
options.SaveTokens = true;
Also, as I'm using IdentityServer on a docker and testing the client on the host, I had to configure an extra redirect Uri to be able to test:
RedirectUris =
{
"http://localhost:5001/signin-oidc",
"http://host.docker.internal:5001/signin-oidc",
"http://notused"
},
I'm basing my implementation on Dominic Baier's samples on GitHub.
Edit: I've come to understand now that for my case the response type could only be "code" because my client configuration is for Authorization Code + PKCE (an OAuth2 flow). You have "Hybrid" configured (an OIDC flow) that supports "code id_token" so although we has received the same error message, the problem was different.
Solution 3
try this : https://github.com/IdentityServer/IdentityServer4/issues/4238
set your RequirePkce as false in the configuration.
Shushan
Updated on June 27, 2022Comments
-
Shushan almost 2 years
I am trying to redirect to IdentityServer for authorization, and getting "code challenge required" in redirect URL.
An error message shows invalid_request with code challenge required, and also my redirect url http://localhost:44367/signin-oidc#error=invalid_request&error_description=code%20challenge%20required&state=CfDJ8Cq6lLUEMhZLqMhFVN
Here is my client configuration:
namespace TestClient { public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.Configure<CookiePolicyOptions>(options => { // This lambda determines whether user consent for non-essential cookies is needed for a given request. options.CheckConsentNeeded = context => true; options.MinimumSameSitePolicy = SameSiteMode.None; }); services.AddControllersWithViews(); ConfigureIdentityServer(services); services.AddCors(); } private void ConfigureIdentityServer(IServiceCollection services) { var builder = services.AddAuthentication(options => SetAuthenticationOptions(options)); services.AddMvcCore() .AddAuthorization(); services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_3_0); builder.AddCookie(); builder.AddOpenIdConnect(options => SetOpenIdConnectOptions(options)); } private void SetAuthenticationOptions(AuthenticationOptions options) { options.DefaultScheme = Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationDefaults.AuthenticationScheme; options.DefaultChallengeScheme = Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectDefaults.AuthenticationScheme; } private void SetOpenIdConnectOptions(OpenIdConnectOptions options) { options.Authority = "https://localhost:44346"; options.ClientId = "TestIdentityServer"; options.RequireHttpsMetadata = false; options.Scope.Add("profile"); options.Scope.Add("openid"); options.Scope.Add("TestIdentityServer"); options.ResponseType = "code id_token"; options.SaveTokens = true; options.ClientSecret = "0b4168e4-2832-48ea-8fc8-7e4686b3620b"; } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Home/Error"); // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. } app.UseHsts(); app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseCors(builder => builder .AllowAnyOrigin() .AllowAnyHeader() .AllowAnyMethod() ); app.UseCookiePolicy(); app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); }); } } }
And here is my IdentityService4 configuration
public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { IdentityModelEventSource.ShowPII = true; services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer( Configuration.GetConnectionString("DefaultConnection"))); services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true) .AddEntityFrameworkStores<ApplicationDbContext>(); services.AddControllersWithViews(); services.AddRazorPages(); services.AddMvc().SetCompatibilityVersion(Microsoft.AspNetCore.Mvc.CompatibilityVersion.Version_3_0); services.Configure<IISOptions>(iis => { iis.AuthenticationDisplayName = "Windows"; iis.AutomaticAuthentication = false; }); var builder = services.AddIdentityServer(options => { options.Events.RaiseErrorEvents = true; options.Events.RaiseInformationEvents = true; options.Events.RaiseFailureEvents = true; options.Events.RaiseSuccessEvents = true; }); // this adds the config data from DB (clients, resources) builder.AddInMemoryIdentityResources(Configuration.GetSection("IdentityResources")); builder.AddInMemoryApiResources(Configuration.GetSection("ApiResources")); builder.AddInMemoryClients(Configuration.GetSection("clients")); services.AddAuthentication(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); app.UseDatabaseErrorPage(); } else { app.UseExceptionHandler("/Home/Error"); // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. } app.UseHsts(); app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); app.UseIdentityServer(); app.UseEndpoints(endpoints => { endpoints.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); endpoints.MapRazorPages(); }); } }
and appsettings.json
"IdentityResources": [ { "Name": "openid", "DisplayName": "Your user identifier", "Required": true, "UserClaims": [ "sub" ] }, { "Name": "profile", "DisplayName": "User profile", "Description": "Your user profile information (first name, last name, etc.)", "Emphasize": true, "UserClaims": [ "name", "family_name", "given_name", "middle_name", "preferred_username", "profile", "picture", "website", "gender", "birthdate", "zoneinfo", "locale", "updated_at" ] } ], "ApiResources": [ { "Name": "TestIdentityServer", "DisplayName": "TestIdentityServer API Services", "Scopes": [ { "Name": "TestIdentityServer", "DisplayName": "TestIdentityServer API Services" } ] } ], "Clients": [ { "ClientId": "TestIdentityServer", "ClientName": "TestIdentityServer Credentials Client", // 511536EF-F270-4058-80CA-1C89C192F69A "ClientSecrets": [ { "Value": "entAuCGhsOQWRYBVx26BCgZxeMt/TqeVZzzpNJ9Ub1M=" } ], "AllowedGrantTypes": [ "hybrid" ], "AllowedScopes": [ "openid", "profile", "TestIdentityServer" ], "RedirectUris": [ "http://localhost:44367/signin-oidc" ], //"FrontChannelLogoutUris": [ "http://localhost:44367/Home/Privacy" ], //"PostLogoutRedirectUris": [ "http://localhost:44367/Home/Privacy" ], "redirect_uri": "http://localhost:44367/signin-oidc" }
-
LuizZ over 3 yearsWelcome to stack overflow. Can you please explain what is in the link? Your answer must remain valid even if the link expires.
-
Terai over 3 yearsyes, in the newer version of IS4 we need to confirm the not use of Pkce in both (the client and the server) config.
-
ryanwebjackson over 2 yearsHow does this solve the problem (why does this work)?