asp.netazureblazoropenid-connectopeniddict

Why is my Blazor Web App throwing a SocketException when authenticating with OpenIddict when deployed to Azure App Service?


I have a Blazor Web App running with Interactive Server Render Mode, and an ID Provider built using OpenIddict. The Blazor App is configured to use the Microsoft OpenIdConnectHandler, essentially following this guide: https://damienbod.com/2024/04/15/implement-a-secure-blazor-web-application-using-openid-connect-and-security-headers/

When I run the two apps locally everything works as expected.

However when I deploy them into Azure, I am redirected to the Login page (on the IDP) successfully, but then on successful authentication I end up in an infinite loop between /signin-oidc on the Blazor app, and the authorize endpoint on the IDP.

When I look at the logs produced, this seems to be the only exception, even though it looks like OpenIddict has successfully handled the token request:

Category: Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler EventId: 17 SpanId: d04c97209a4248cf TraceId: f1015c14eb411718858a680b84fb7145 ParentId: 0000000000000000 RequestId: 80000052-0001-e700-b63f-84710c7967bb RequestPath: /signin-oidc Exception occurred while processing message. Exception: System.Threading.Tasks.TaskCanceledException: The operation was canceled.
  ---> System.Threading.Tasks.TaskCanceledException: The operation was canceled.
  ---> System.IO.IOException: Unable to read data from the transport connection: The I/O operation has been aborted because of either a thread exit or an application request..
  ---> System.Net.Sockets.SocketException (995): The I/O operation has been aborted because of either a thread exit or an application request.
    --- End of inner exception stack trace ---
    at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.ThrowException(SocketError error, CancellationToken cancellationToken)
    at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.System.Threading.Tasks.Sources.IValueTaskSource<System.Int32>.GetResult(Int16 token)
    at System.Net.Security.SslStream.EnsureFullTlsFrameAsync[TIOAdapter](CancellationToken cancellationToken, Int32 estimatedSize)
    at System.Runtime.CompilerServices.PoolingAsyncValueTaskMethodBuilder`1.StateMachineBox`1.System.Threading.Tasks.Sources.IValueTaskSource<TResult>.GetResult(Int16 token)
    at System.Net.Security.SslStream.ReadAsyncInternal[TIOAdapter](Memory`1 buffer, CancellationToken cancellationToken)
    at System.Runtime.CompilerServices.PoolingAsyncValueTaskMethodBuilder`1.StateMachineBox`1.System.Threading.Tasks.Sources.IValueTaskSource<TResult>.GetResult(Int16 token)
    at System.Net.Http.HttpConnection.SendAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
    --- End of inner exception stack trace ---
    at System.Net.Http.HttpConnection.SendAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
    at System.Net.Http.HttpConnectionPool.SendWithVersionDetectionAndRetryAsync(HttpRequestMessage request, Boolean async, Boolean doRequestAuth, CancellationToken cancellationToken)
    at System.Net.Http.DiagnosticsHandler.SendAsyncCore(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
    at System.Net.Http.Metrics.MetricsHandler.SendAsyncWithMetrics(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
    at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
    at System.Net.Http.HttpClient.<SendAsync>g__Core|83_0(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationTokenSource cts, Boolean disposeCts, CancellationTokenSource pendingRequestsCts, CancellationToken originalCancellationToken)
    --- End of inner exception stack trace ---
    at System.Net.Http.HttpClient.HandleFailure(Exception e, Boolean telemetryStarted, HttpResponseMessage response, CancellationTokenSource cts, CancellationToken cancellationToken, CancellationTokenSource pendingRequestsCts)
    at System.Net.Http.HttpClient.<SendAsync>g__Core|83_0(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationTokenSource cts, Boolean disposeCts, CancellationTokenSource pendingRequestsCts, CancellationToken originalCancellationToken)
    at Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler.RedeemAuthorizationCodeAsync(OpenIdConnectMessage tokenEndpointRequest)
    at Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler.HandleRemoteAuthenticateAsync() 

However, now I am not sure if this is the actual error or whether this just happens when I cancel the request.

I have tried cloning this repo https://github.com/damienbod/BlazorServerOidc and changing the config to use my IDP and then deploying that into Azure, and this works as expected.

I then add to this all of my pages and components, leaving the configuration the same, but I get the same problem.

Given that a) I have a number of other apps that work (SPA's running React) b) it works locally with Blazor c) my "template" unmodified Blazor app works - why would I be getting this problem?


Solution

  • I found that AddIdentity adds a bunch of cookies and auth schemas to the app, and I think this was interfering with what I was trying to do. However, since I still needed some of the services that are added by Identity, I changed it to AddIdentityCore and configured the EF Core stores, etc. and it now works.