From ca432b3c88145e10491123407066dcc756680842 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mehmet=20Can=20Karag=C3=B6z?= Date: Wed, 4 Nov 2026 11:45:20 +0300 Subject: [PATCH 1/2] fix(blazor): Prevent file URI origin resolution on Linux --- .../Infrastructure/UAuthRequestClient.cs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/client/CodeBeam.UltimateAuth.Client.Blazor/Infrastructure/UAuthRequestClient.cs b/src/client/CodeBeam.UltimateAuth.Client.Blazor/Infrastructure/UAuthRequestClient.cs index 8d4aa3cb..eee577e8 100644 --- a/src/client/CodeBeam.UltimateAuth.Client.Blazor/Infrastructure/UAuthRequestClient.cs +++ b/src/client/CodeBeam.UltimateAuth.Client.Blazor/Infrastructure/UAuthRequestClient.cs @@ -149,10 +149,12 @@ public async Task TryAndCommitAsync(string tryEndpoint, { var basePath = _options.Endpoints.BasePath; - if (Uri.TryCreate(basePath, UriKind.Absolute, out var uri)) - return uri.GetLeftPart(UriPartial.Authority); + if (!Uri.TryCreate(basePath, UriKind.Absolute, out var uri)) + return null; - // Relative BasePath: JS automatically uses the current origin. - return null; + if (uri.Scheme != Uri.UriSchemeHttp && uri.Scheme != Uri.UriSchemeHttps) + return null; + + return uri.GetLeftPart(UriPartial.Authority); } } From cfe9d4f158b62c878f5f8b497f69a1dce7ba2c75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mehmet=20Can=20Karag=C3=B6z?= Date: Wed, 4 Nov 2026 11:57:00 +0300 Subject: [PATCH 2/2] Add Tests --- .../Client/Blazor/UAuthRequestClientTests.cs | 41 +++++++++++++++++-- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/tests/CodeBeam.UltimateAuth.Tests.Unit/Client/Blazor/UAuthRequestClientTests.cs b/tests/CodeBeam.UltimateAuth.Tests.Unit/Client/Blazor/UAuthRequestClientTests.cs index d2257ae3..821df048 100644 --- a/tests/CodeBeam.UltimateAuth.Tests.Unit/Client/Blazor/UAuthRequestClientTests.cs +++ b/tests/CodeBeam.UltimateAuth.Tests.Unit/Client/Blazor/UAuthRequestClientTests.cs @@ -24,14 +24,17 @@ public UAuthRequestClientTests() .Returns(Task.CompletedTask); } - private UAuthRequestClient CreateSut(UAuthClientProfile profile = UAuthClientProfile.BlazorWasm) + private UAuthRequestClient CreateSut(UAuthClientProfile profile = UAuthClientProfile.BlazorWasm, string? basePath = null) { - var options = Options.Create(new UAuthClientOptions + var options = new UAuthClientOptions { ClientProfile = profile - }); + }; + + if (basePath is not null) + options.Endpoints.BasePath = basePath; - return new UAuthRequestClient(JSInterop.JSRuntime, _bootstrapper.Object, options); + return new UAuthRequestClient(JSInterop.JSRuntime, _bootstrapper.Object, Options.Create(options)); } [Fact] @@ -178,6 +181,36 @@ public async Task ObservedLogoutReturnsHttpRejectionRatherThanSubmittingAnUnobse Assert.Equal("logout", GetProperty(invocation.Arguments.Single()!, "mode")); } + [Theory] + [InlineData("/auth", null)] + [InlineData("auth", null)] + [InlineData("https://example.com/auth", "https://example.com")] + [InlineData("http://localhost:5000/auth", "http://localhost:5000")] + public async Task SendFormAsync_ResolvesTrustedOriginCorrectly(string basePath, string? expectedOrigin) + { + // Arrange + JSInterop + .Setup("uauth.post", _ => true) + .SetResult(CreateTransportResult(200)); + + var sut = CreateSut(basePath: basePath); + + // Act + await sut.SendFormAsync("/auth/validate"); + + // Assert + var invocation = JSInterop.Invocations + .Single(x => x.Identifier == "uauth.post"); + + var options = invocation.Arguments.Single()!; + + GetProperty(options, "url") + .Should().Be("/auth/validate"); + + GetProperty(options, "trustedOrigin") + .Should().Be(expectedOrigin); + } + private sealed class TestTryResult { }