'How to connect ASP.NET Core 6 MVC web application with KeyCloak

I need to use KeyCloak as SSO server, to authorize, first, some Mvc web application and second, some Apis.

I'm at the point I need to configure Keycloak for my WebApp, so I manage to find that link :

enter link description here

but it is not very helpful.

I have Keycloak docker image running, I create my real, client and a user, so everything seems fine for KeyCloak, at least, I think so.

I created a basic ASP.NET Core MVC application and updated the program.cs class to setup as the example in the link so :

using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using System.IdentityModel.Tokens.Jwt;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddControllersWithViews();

builder.Services.AddMvc();

JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();

builder.Services.AddAuthentication(options =>
{
    // Store the session to cookies
    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    // OpenId authentication
    options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
    .AddCookie("Cookies")
    .AddOpenIdConnect(options =>
    {
        // URL of the Keycloak server
        options.Authority = "https://localhost:8080/auth/realms/BrunoRealm";
        // Client configured in the Keycloak
        options.ClientId = "MonApplication";

        // For testing we disable https (should be true for production)
        options.RequireHttpsMetadata = false;
        options.SaveTokens = true;
        options.ClientId = "MonApplication";
        // Client secret shared with Keycloak
        options.ClientSecret = "nrnsK6od01BpzJ0NTzvdC2DLt0ta72zp";
        options.GetClaimsFromUserInfoEndpoint = true;

        // OpenID flow to use
        options.ResponseType = OpenIdConnectResponseType.CodeIdToken;
    }); 

var app = builder.Build();

app.UseAuthentication();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();

app.UseRouting();

app.UseAuthorization();

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

app.Run();

I put an [Authorize] attribute on the privacy method of home controller but when I try to access privacy page, I have an exception talking about SSL :

An unhandled exception occurred while processing the request.

IOException: Cannot determine the frame size or a corrupted frame was received.
System.Net.Security.SslStream.GetFrameSize(ReadOnlySpan buffer)

HttpRequestException: The SSL connection could not be established, see inner exception.

System.Net.Http.ConnectHelper.EstablishSslConnectionAsync(SslClientAuthenticationOptions sslOptions, HttpRequestMessage request, bool async, Stream stream, CancellationToken cancellationToken)

IOException: IDX20804: Unable to retrieve document from: '[PII of type 'System.String' is hidden. For more details, see https://aka.ms/IdentityModel/PII.]'.
Microsoft.IdentityModel.Protocols.HttpDocumentRetriever.GetDocumentAsync(string address, CancellationToken cancel)

InvalidOperationException: IDX20803: Unable to obtain configuration from: '[PII of type 'System.String' is hidden. For more details, see https://aka.ms/IdentityModel/PII.]'.

Microsoft.IdentityModel.Protocols.ConfigurationManager.GetConfigurationAsync(CancellationToken cancel)

Stack Query Cookies Headers Routing
IOException: Cannot determine the frame size or a corrupted frame was received.

System.Net.Security.SslStream.GetFrameSize(ReadOnlySpan buffer)
System.Net.Security.SslStream.ReceiveBlobAsync(TIOAdapter adapter)
System.Threading.Tasks.ValueTask.get_Result()
System.Runtime.CompilerServices.ConfiguredValueTaskAwaitable+ConfiguredValueTaskAwaiter.GetResult()
System.Net.Security.SslStream.ForceAuthenticationAsync(TIOAdapter adapter, bool receiveFirst, byte[] reAuthenticationData, bool isApm)
System.Net.Http.ConnectHelper.EstablishSslConnectionAsync(SslClientAuthenticationOptions sslOptions, HttpRequestMessage request, bool async, Stream stream, CancellationToken cancellationToken)

Show raw exception details
HttpRequestException: The SSL connection could not be established, see inner exception.

System.Net.Http.ConnectHelper.EstablishSslConnectionAsync(SslClientAuthenticationOptions sslOptions, HttpRequestMessage request, bool async, Stream stream, CancellationToken cancellationToken)
System.Threading.Tasks.ValueTask.get_Result()
System.Runtime.CompilerServices.ConfiguredValueTaskAwaitable+ConfiguredValueTaskAwaiter.GetResult()
System.Net.Http.HttpConnectionPool.ConnectAsync(HttpRequestMessage request, bool async, CancellationToken cancellationToken)
System.Threading.Tasks.ValueTask.get_Result()
System.Runtime.CompilerServices.ConfiguredValueTaskAwaitable+ConfiguredValueTaskAwaiter.GetResult()
System.Net.Http.HttpConnectionPool.CreateHttp11ConnectionAsync(HttpRequestMessage request, bool async, CancellationToken cancellationToken)
System.Threading.Tasks.ValueTask.get_Result()
System.Runtime.CompilerServices.ConfiguredValueTaskAwaitable+ConfiguredValueTaskAwaiter.GetResult()
System.Net.Http.HttpConnectionPool.AddHttp11ConnectionAsync(HttpRequestMessage request)
System.Threading.Tasks.TaskCompletionSourceWithCancellation.WaitWithCancellationAsync(CancellationToken cancellationToken)
System.Threading.Tasks.ValueTask.get_Result()
System.Runtime.CompilerServices.ConfiguredValueTaskAwaitable+ConfiguredValueTaskAwaiter.GetResult()
System.Net.Http.HttpConnectionPool.GetHttp11ConnectionAsync(HttpRequestMessage request, bool async, CancellationToken cancellationToken)
System.Threading.Tasks.ValueTask.get_Result()
System.Runtime.CompilerServices.ConfiguredValueTaskAwaitable+ConfiguredValueTaskAwaiter.GetResult()
System.Net.Http.HttpConnectionPool.SendWithVersionDetectionAndRetryAsync(HttpRequestMessage request, bool async, bool doRequestAuth, CancellationToken cancellationToken)
System.Net.Http.DiagnosticsHandler.SendAsyncCore(HttpRequestMessage request, bool async, CancellationToken cancellationToken)
System.Threading.Tasks.ValueTask.get_Result()
System.Runtime.CompilerServices.ConfiguredValueTaskAwaitable+ConfiguredValueTaskAwaiter.GetResult()
System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, bool async, CancellationToken cancellationToken)
System.Net.Http.HttpClient.
g__Core|83_0(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationTokenSource cts, bool disposeCts, CancellationTokenSource pendingRequestsCts, CancellationToken originalCancellationToken)
Microsoft.IdentityModel.Protocols.HttpDocumentRetriever.GetDocumentAsync(string address, CancellationToken cancel)

Show raw exception details
IOException: IDX20804: Unable to retrieve document from: '[PII of type 'System.String' is hidden. For more details, see https://aka.ms/IdentityModel/PII.]'.

Microsoft.IdentityModel.Protocols.HttpDocumentRetriever.GetDocumentAsync(string address, CancellationToken cancel)
Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectConfigurationRetriever.GetAsync(string address, IDocumentRetriever retriever, CancellationToken cancel)
Microsoft.IdentityModel.Protocols.ConfigurationManager.GetConfigurationAsync(CancellationToken cancel)

Show raw exception details
InvalidOperationException: IDX20803: Unable to obtain configuration from: '[PII of type 'System.String' is hidden. For more details, see https://aka.ms/IdentityModel/PII.]'.
Microsoft.IdentityModel.Protocols.ConfigurationManager.GetConfigurationAsync(CancellationToken cancel)
Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler.HandleChallengeAsyncInternal(AuthenticationProperties properties)
Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler.HandleChallengeAsync(AuthenticationProperties properties)
Microsoft.AspNetCore.Authentication.AuthenticationHandler.ChallengeAsync(AuthenticationProperties properties)
Microsoft.AspNetCore.Authentication.AuthenticationService.ChallengeAsync(HttpContext context, string scheme, AuthenticationProperties properties)
Microsoft.AspNetCore.Authorization.Policy.AuthorizationMiddlewareResultHandler.HandleAsync(RequestDelegate next, HttpContext context, AuthorizationPolicy policy, PolicyAuthorizationResult authorizeResult)
Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

I have no idea where to look at. Have I to configure SSL on my docker image. Must I implement a login page but, in that case how to call KeyCloak?

So in short what to do know?



Solution 1:[1]

Keycloak does not support HTTPS on port 8080 (by default). Change https:// to http:// in

options.Authority = "https://localhost:8080/auth/realms/BrunoRealm";

so that it reads

options.Authority = "http://localhost:8080/auth/realms/BrunoRealm";

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 sventorben