Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Net8 Azure SignalR OIDC authentication #255

Open
njannink opened this issue Feb 20, 2024 · 9 comments
Open

Net8 Azure SignalR OIDC authentication #255

njannink opened this issue Feb 20, 2024 · 9 comments

Comments

@njannink
Copy link

What is the current suggested way to do OIDC authentication over Azure SignalR using AspNetCore 8?

As soon as I switch to Azure SignalR in my Blazor Server app the HttpContextAccessor.HttpContext becomes null so I can no longer access the cookies.

@vicancy
Copy link
Contributor

vicancy commented Feb 20, 2024

Could you share with me a minimum reproable project, for example, where do you consume cookies, where HttpContextAccessor.HttpContext is called? When using Azure SignalR, Azure SignalR SDK reads UserPrincipal data from HttpContext after the authentication middleware and reconstruct the HttpContext.

@njannink
Copy link
Author

https://github.com/njannink/BlazorServerAppOidcWithHub/tree/main

See here an example project.

Fill in your OIDC + Azure SignalR details in the BlazorWebAppOidc/Program.cs file. If you then login and try to connect to the chat hub you get the following error:

System.IO.InvalidDataException: Invalid negotiation response received.
 ---> System.Text.Json.JsonReaderException: '<' is an invalid start of a value. LineNumber: 0 | BytePositionInLine: 0.
   at System.Text.Json.ThrowHelper.ThrowJsonReaderException(Utf8JsonReader& json, ExceptionResource resource, Byte nextByte, ReadOnlySpan`1 bytes)
   at System.Text.Json.Utf8JsonReader.ConsumeValue(Byte marker)
   at System.Text.Json.Utf8JsonReader.ReadFirstToken(Byte first)
   at System.Text.Json.Utf8JsonReader.ReadSingleSegment()
   at System.Text.Json.Utf8JsonReader.Read()
   at Microsoft.AspNetCore.Internal.SystemTextJsonExtensions.CheckRead(Utf8JsonReader& reader)
   at Microsoft.AspNetCore.Http.Connections.NegotiateProtocol.ParseResponse(ReadOnlySpan`1 content)
   --- End of inner exception stack trace ---
   at Microsoft.AspNetCore.Http.Connections.NegotiateProtocol.ParseResponse(ReadOnlySpan`1 content)
   at Microsoft.AspNetCore.Http.Connections.Client.HttpConnection.NegotiateAsync(Uri url, HttpClient httpClient, ILogger logger, CancellationToken cancellationToken)
   at Microsoft.AspNetCore.Http.Connections.Client.HttpConnection.GetNegotiationResponseAsync(Uri uri, CancellationToken cancellationToken)
   at Microsoft.AspNetCore.Http.Connections.Client.HttpConnection.SelectAndStartTransport(TransferFormat transferFormat, CancellationToken cancellationToken)
   at Microsoft.AspNetCore.Http.Connections.Client.HttpConnection.StartAsyncCore(TransferFormat transferFormat, CancellationToken cancellationToken)
   at Microsoft.AspNetCore.Http.Connections.Client.HttpConnection.StartAsync(TransferFormat transferFormat, CancellationToken cancellationToken)
   at Microsoft.AspNetCore.Http.Connections.Client.HttpConnectionFactory.ConnectAsync(EndPoint endPoint, CancellationToken cancellationToken)
   at Microsoft.AspNetCore.Http.Connections.Client.HttpConnectionFactory.ConnectAsync(EndPoint endPoint, CancellationToken cancellationToken)
   at Microsoft.AspNetCore.SignalR.Client.HubConnection.StartAsyncCore(CancellationToken cancellationToken)
   at Microsoft.AspNetCore.SignalR.Client.HubConnection.StartAsyncInner(CancellationToken cancellationToken)
   at Microsoft.AspNetCore.SignalR.Client.HubConnection.StartAsync(CancellationToken cancellationToken)
   at BlazorWebAppOidc.Client.Pages.Chat.OnInitializedAsync() in D:\Projects\blazor\BlazorServerAppOidcWithHub\BlazorWebAppOidc.Client\Pages\Chat.razor:line 43
   at Microsoft.AspNetCore.Components.ComponentBase.RunInitAndSetParametersAsync()
   at Microsoft.AspNetCore.Components.RenderTree.Renderer.GetErrorHandledTask(Task taskToHandle, ComponentState owningComponentState)
Microsoft.AspNetCore.Components.Server.Circuits.CircuitHost: Error: Unhandled exception in circuit '80pb6dJz85Pl8JrsLdYsB0wQ26jpH6Mi-79i_fPlXZg'.

@vicancy
Copy link
Contributor

vicancy commented Feb 22, 2024

Hi @njannink, I met the same issue when commenting out AddAzureSignalR part. So I believe this is a general issue when integrating SignalR into the OIDC auth workflow with Blazor WebAssembly. The chat tab works if I manually Login before click (The same applies to AddAzureSignalR). I tried a JS client and see the detailed error in the Network tab as:
image

Created a PR for the JS client here (which shows more error details in the browser): njannink/BlazorServerAppOidcWithHub#1

@njannink
Copy link
Author

Its actually now Blazor WebAssembly, but Blazor Server. In the App.razor the render-mode is InteractiveServer. In blazor webassembly it was working fine, but switching to Blazor WebAssemly is too much work for us at this moment

@njannink
Copy link
Author

So to fix it you have to do somehting with CORS policies?

@vicancy
Copy link
Contributor

vicancy commented Feb 23, 2024

Is it to change the SignalR connection logic to only connect when authorized better?

Hi @davidfowl do we have any best practice guidance on such scenario for SignalR working with OIDC?

@davidfowl
Copy link
Member

Is it to change the SignalR connection logic to only connect when authorized better?

Yes, this is the solution with any interactive logic scenario.

@njannink
Copy link
Author

I just used the simple OIDC sample to create this project. But indeed you should hide the Chat page untill you are authenticated. But the original question remains. What is the recommended way to connect to authenticated (Azure) SignalR when using Blazor Server?
There are some examples to get the access_token from the HttpContext on the HttpContextAccessor:

https://github.com/dotnet/blazor-samples/blob/main/8.0/BlazorWebAppOidcBff/BlazorWebAppOidc/ServerWeatherForecaster.cs

But as soon as you start using Azure SignalR in combination with Blazor the HttpContextAccessor can no longer be used.

@vicancy
Copy link
Contributor

vicancy commented Feb 27, 2024

What is the recommended way to connect to authenticated (Azure) SignalR when using Blazor Server?

Not sure if I understand the question correctly. When Add(Azure)SignalR is put below Auth middleware it leverages the normal auth workflow and you could apply [Authorize] attribute to the hub: https://learn.microsoft.com/aspnet/core/signalr/authn-and-authz?view=aspnetcore-8.0#authorize-users-to-access-hubs-and-hub-methods. When using AzureSignalR, unauthorized users are denied in SignalR negotiate step. Inside the Hub you could use Context.GetHttpContext() to get the reconstructed HttpContext.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants