Search code examples
c#asp.net.netasp.net-coreopenid

OpenIdDict: Interactive user consent is required. AuthenticationScheme: OpenIddict.Server.AspNetCore was forbidden


I have Server and Webassembly Client project, the client is hosted on the server. My project uses OpenIDDict auth. Suddenly, when I trying get to the client, I get error: Interactive user consent is required

My Program.cs:

using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Notes.Web.Server;
using Notes.Web.Server.Logging;
using Notes.Web.Server.Models;
using Notes.Web.Server.Models.Data;
using static OpenIddict.Abstractions.OpenIddictConstants;

#region WebApplication Builder

var builder = WebApplication.CreateBuilder(new WebApplicationOptions
{
    WebRootPath = "WebRoot",
    Args = args
});
builder.WebHost.ConfigureLogging(loggingBuilder =>
{
    loggingBuilder.ClearProviders();
    loggingBuilder.AddPrettyConsoleLogger();
});
builder.Services.AddHostedService<OAuthWorker>();

#endregion

#region Razor and MVC Setup

builder.Services.AddMvc();
builder.Services.AddRazorPages().AddRazorRuntimeCompilation();

#endregion

#region Database Setup

builder.Services.AddDbContext<PrettyNotesApplicationDBContext>(options =>
{
    //options.UseInMemoryDatabase("Server=(localdb)\\mssqllocaldb;Database=TestDB;Trusted_Connection=True;");
    options.UseSqlServer("****");
    options.UseOpenIddict();
}); 

#endregion

#region Identity Setup

builder.Services.AddIdentity<PNUser, IdentityRole>(options =>
{
    options.Password.RequiredLength = 8;
    options.Password.RequireNonAlphanumeric = false;
    options.Password.RequireDigit = true;
}).AddEntityFrameworkStores<PrettyNotesApplicationDBContext>().AddDefaultTokenProviders();

builder.Services.Configure<IdentityOptions>(options =>
{
    options.ClaimsIdentity.UserNameClaimType = Claims.Name;
    options.ClaimsIdentity.UserIdClaimType = Claims.Subject;
    options.ClaimsIdentity.RoleClaimType = Claims.Role;
});

builder.Services.PostConfigure<CookieAuthenticationOptions>(IdentityConstants.ApplicationScheme,
    opt =>
    {
        opt.LoginPath = "/auth/login";
        opt.LogoutPath = "/auth/logout";
    });

#endregion

#region OpenIdDict Setup

builder.Services.AddOpenIddict().AddCore(options =>
{
    options.UseEntityFrameworkCore().UseDbContext<PrettyNotesApplicationDBContext>();
}).AddServer(options =>
{
    options.SetAuthorizationEndpointUris("/connect/authorize")
        .SetLogoutEndpointUris("/connect/logout")
        .SetTokenEndpointUris("/connect/token")
        .SetUserinfoEndpointUris("/connect/userinfo");
    options.RegisterScopes(Scopes.Email, Scopes.Profile, Scopes.Roles, Scopes.OpenId);
    options.AddDevelopmentEncryptionCertificate().AddDevelopmentSigningCertificate();
    options.AllowAuthorizationCodeFlow()
        .AllowRefreshTokenFlow();
    options.UseAspNetCore()
        .EnableAuthorizationEndpointPassthrough()
        .EnableLogoutEndpointPassthrough()
        .EnableStatusCodePagesIntegration()
        .EnableTokenEndpointPassthrough();
}).AddValidation(options =>
{
    options.UseLocalServer();
    options.UseAspNetCore();
});

#endregion

builder.Services.AddRemoteAuthentication<RemoteAuthenticationState, RemoteUserAccount, OidcProviderOptions>();
builder.Services.AddScoped<AuthenticationStateProvider, RemoteAuthenticationService>()
    .AddScoped<SignOutSessionStateManager>()
    .AddTransient<IAccessTokenProvider, AccessTokenProvider>()
    .AddTransient<Microsoft.JSInterop.IJSRuntime, JSRuntime>();

var app = builder.Build();

if (app.Environment.IsDevelopment()) app.UseDeveloperExceptionPage();

app.UseRouting();

app.UseStaticFiles();
app.UseHttpsRedirection();
app.UseBlazorFrameworkFiles();

app.UseAuthentication();
app.UseAuthorization();

app.UseEndpoints(endpoints =>
{
    endpoints.MapControllers();
    endpoints.MapRazorPages();
    endpoints.MapFallbackToController("/client/{**segment}", "Index", "Client");
    endpoints.MapControllerRoute("Default", "{controller=Home}/{action=Index}/{id?}");
});

app.Run();

After starting application and accessing Client, I get next error:

[Information] - [0] - [OpenIddict.Server.OpenIddictServerDispatcher] - [2022-02-06] - [20:34:46]
        The authorization response was successfully returned to 'https://localhost:7000/client/security/oauth/login-callback' using the query response mode: {
  "error": "consent_required",
  "error_description": "Interactive user consent is required.",
  "error_uri": "https://documentation.openiddict.com/errors/ID2015",
  "state": "25b73e28b98140ae9f0b88267828fd68"
}.
[Information] - [13] - [OpenIddict.Server.AspNetCore.OpenIddictServerAspNetCoreHandler] - [2022-02-06] - [20:34:46]
        AuthenticationScheme: OpenIddict.Server.AspNetCore was forbidden.

What does this error means and how to solve it?


Solution

  • I guess you are seeding your DB with application details for auth. In OpenIddictApplicationDescriptor there is a field ConsentType which must be set to ConsentTypes.Implicit. It usually happens after library upgrade. E.g. I'm using code like this:

    
        private static async Task SeedApplications(IServiceScope scope, CancellationToken cancellationToken)
        {
          var manager = scope.ServiceProvider.GetRequiredService<OpenIddictApplicationManager<OpenIddictEntityFrameworkCoreApplication>>();
          var applications = new[] { CreateNativeClient(), CreateWebClient() };
          foreach (var client in applications)
          {
            if (await manager.FindByClientIdAsync(client.ClientId, cancellationToken) == null)
            {
              await manager.CreateAsync(client, cancellationToken);
            }
          }
        }
    
    

    and in CreateWebClient you are setting:

    
        return new OpenIddictApplicationDescriptor {
          ClientId = clientId,
          DisplayName = "Web Client",
          RedirectUris = {...},
          Permissions = {...},
          Type = OpenIddictConstants.ClientTypes.Public,
          ConsentType = ConsentTypes.Implicit // <-- this must be set
        };