From 9f1e9891eccace4453288be8ee1dbcace6c8135f Mon Sep 17 00:00:00 2001 From: Shane Krueger Date: Wed, 7 May 2025 15:03:20 -0400 Subject: [PATCH 1/8] Add capability to enable JwtBearer events --- .../AspNetCore3JwtBearerExtensions.cs | 9 + .../JwtBearerAuthenticationOptions.cs | 17 ++ .../JwtWebSocketAuthenticationService.cs | 185 +++++++++++++++++- src/Tests.ApiApprovals/ApiApprovalTests.cs | 2 + ...GraphQL.AspNetCore3.JwtBearer.approved.txt | 27 +++ src/Tests.ApiApprovals/Tests.ApiTests.csproj | 1 + .../AspNetCore3JwtBearerExtensionsTests.cs | 5 + 7 files changed, 241 insertions(+), 5 deletions(-) create mode 100644 src/GraphQL.AspNetCore3.JwtBearer/JwtBearerAuthenticationOptions.cs create mode 100644 src/Tests.ApiApprovals/GraphQL.AspNetCore3.JwtBearer.approved.txt diff --git a/src/GraphQL.AspNetCore3.JwtBearer/AspNetCore3JwtBearerExtensions.cs b/src/GraphQL.AspNetCore3.JwtBearer/AspNetCore3JwtBearerExtensions.cs index aa73d7a..442e1ef 100644 --- a/src/GraphQL.AspNetCore3.JwtBearer/AspNetCore3JwtBearerExtensions.cs +++ b/src/GraphQL.AspNetCore3.JwtBearer/AspNetCore3JwtBearerExtensions.cs @@ -13,7 +13,16 @@ public static class AspNetCore3JwtBearerExtensions /// Adds JWT bearer authentication to a GraphQL server for WebSocket communications. /// public static IGraphQLBuilder AddJwtBearerAuthentication(this IGraphQLBuilder builder) + => builder.AddJwtBearerAuthentication(options => { }); + + /// + public static IGraphQLBuilder AddJwtBearerAuthentication(this IGraphQLBuilder builder, bool enableJwtEvents) + => builder.AddJwtBearerAuthentication(options => options.EnableJwtEvents = enableJwtEvents); + + /// + public static IGraphQLBuilder AddJwtBearerAuthentication(this IGraphQLBuilder builder, Action configureOptions) { + builder.Services.Configure(configureOptions); builder.AddWebSocketAuthentication(); return builder; } diff --git a/src/GraphQL.AspNetCore3.JwtBearer/JwtBearerAuthenticationOptions.cs b/src/GraphQL.AspNetCore3.JwtBearer/JwtBearerAuthenticationOptions.cs new file mode 100644 index 0000000..89e1ad9 --- /dev/null +++ b/src/GraphQL.AspNetCore3.JwtBearer/JwtBearerAuthenticationOptions.cs @@ -0,0 +1,17 @@ +using Microsoft.AspNetCore.Authentication.JwtBearer; + +namespace GraphQL.AspNetCore3.JwtBearer; + +/// +/// Options for JWT Bearer authentication in GraphQL WebSocket connections. +/// +public class JwtBearerAuthenticationOptions +{ + /// + /// Gets or sets a value indicating whether JWT events should be enabled. + /// When enabled, the will implement + /// , , + /// and events as appropriate. + /// + public bool EnableJwtEvents { get; set; } +} diff --git a/src/GraphQL.AspNetCore3.JwtBearer/JwtWebSocketAuthenticationService.cs b/src/GraphQL.AspNetCore3.JwtBearer/JwtWebSocketAuthenticationService.cs index 6b30f71..bd6693a 100644 --- a/src/GraphQL.AspNetCore3.JwtBearer/JwtWebSocketAuthenticationService.cs +++ b/src/GraphQL.AspNetCore3.JwtBearer/JwtWebSocketAuthenticationService.cs @@ -34,7 +34,9 @@ namespace GraphQL.AspNetCore3.JwtBearer; /// mirroring the format of the 'Authorization' HTTP header. /// /// -/// Events configured in are not raised by this implementation. +/// When JWT events are enabled via , this implementation +/// will raise the , , +/// and events as appropriate. /// /// /// Implementation does not call to log authentication events. @@ -46,16 +48,25 @@ public class JwtWebSocketAuthenticationService : IWebSocketAuthenticationService private readonly IGraphQLSerializer _graphQLSerializer; private readonly IOptionsMonitor _jwtBearerOptionsMonitor; private readonly string[] _defaultAuthenticationSchemes; + private readonly JwtBearerAuthenticationOptions _jwtBearerAuthenticationOptions; + private readonly IAuthenticationSchemeProvider _schemeProvider; /// /// Initializes a new instance of the class. /// - public JwtWebSocketAuthenticationService(IGraphQLSerializer graphQLSerializer, IOptionsMonitor jwtBearerOptionsMonitor, IOptions authenticationOptions) + public JwtWebSocketAuthenticationService( + IGraphQLSerializer graphQLSerializer, + IOptionsMonitor jwtBearerOptionsMonitor, + IOptions authenticationOptions, + IOptions jwtBearerAuthenticationOptions, + IAuthenticationSchemeProvider schemeProvider) { _graphQLSerializer = graphQLSerializer; _jwtBearerOptionsMonitor = jwtBearerOptionsMonitor; var defaultAuthenticationScheme = authenticationOptions.Value.DefaultScheme; _defaultAuthenticationSchemes = defaultAuthenticationScheme != null ? [defaultAuthenticationScheme] : []; + _jwtBearerAuthenticationOptions = jwtBearerAuthenticationOptions.Value; + _schemeProvider = schemeProvider; } /// @@ -79,6 +90,23 @@ public async Task AuthenticateAsync(AuthenticationRequest authenticationRequest) foreach (var scheme in schemes) { var options = _jwtBearerOptionsMonitor.Get(scheme); + // If JWT events are enabled, trigger the MessageReceived event + if (_jwtBearerAuthenticationOptions.EnableJwtEvents) + { + var messageResult = await TriggerMessageReceivedEventAsync(connection.HttpContext, options, token, scheme).ConfigureAwait(false); + if (messageResult.Handled) + { + if (messageResult.Success) + { + connection.HttpContext.User = messageResult.Principal!; + return; + } + continue; + } + + token = messageResult.Token; + } + // follow logic simplified from JwtBearerHandler.HandleAuthenticateAsync, as follows: var tokenValidationParameters = await SetupTokenValidationParametersAsync(options, connection.HttpContext).ConfigureAwait(false); #if NET8_0_OR_GREATER @@ -88,11 +116,35 @@ public async Task AuthenticateAsync(AuthenticationRequest authenticationRequest) var tokenValidationResult = await tokenHandler.ValidateTokenAsync(token, tokenValidationParameters).ConfigureAwait(false); if (tokenValidationResult.IsValid) { var principal = new ClaimsPrincipal(tokenValidationResult.ClaimsIdentity); + + // If JWT events are enabled, trigger the TokenValidated event + if (_jwtBearerAuthenticationOptions.EnableJwtEvents) + { + var validatedResult = await TriggerTokenValidatedEventAsync(connection.HttpContext, options, principal, tokenValidationResult.SecurityToken, scheme).ConfigureAwait(false); + if (validatedResult.Handled && !validatedResult.Success) + { + continue; + } + + principal = validatedResult.Principal ?? principal; + } + // set the ClaimsPrincipal for the HttpContext; authentication will take place against this object connection.HttpContext.User = principal; return; } - } catch { + } catch (Exception ex) { + // If JWT events are enabled, trigger the AuthenticationFailed event + if (_jwtBearerAuthenticationOptions.EnableJwtEvents) + { + var failedResult = await TriggerAuthenticationFailedEventAsync(connection.HttpContext, options, ex, scheme).ConfigureAwait(false); + if (failedResult.Handled && failedResult.Success) + { + connection.HttpContext.User = failedResult.Principal!; + return; + } + } + // no errors during authentication should throw an exception // specifically, attempting to validate an invalid JWT token may result in an exception } @@ -105,11 +157,35 @@ public async Task AuthenticateAsync(AuthenticationRequest authenticationRequest) foreach (var validator in options.SecurityTokenValidators) { if (validator.CanReadToken(token)) { try { - var principal = validator.ValidateToken(token, tokenValidationParameters, out _); + var principal = validator.ValidateToken(token, tokenValidationParameters, out var securityToken); + + // If JWT events are enabled, trigger the TokenValidated event + if (_jwtBearerAuthenticationOptions.EnableJwtEvents) + { + var validatedResult = await TriggerTokenValidatedEventAsync(connection.HttpContext, options, principal, securityToken, scheme).ConfigureAwait(false); + if (validatedResult.Handled && !validatedResult.Success) + { + continue; + } + + principal = validatedResult.Principal ?? principal; + } + // set the ClaimsPrincipal for the HttpContext; authentication will take place against this object connection.HttpContext.User = principal; return; - } catch { + } catch (Exception ex) { + // If JWT events are enabled, trigger the AuthenticationFailed event + if (_jwtBearerAuthenticationOptions.EnableJwtEvents) + { + var failedResult = await TriggerAuthenticationFailedEventAsync(connection.HttpContext, options, ex, scheme).ConfigureAwait(false); + if (failedResult.Handled && failedResult.Success) + { + connection.HttpContext.User = failedResult.Principal!; + return; + } + } + // no errors during authentication should throw an exception // specifically, attempting to validate an invalid JWT token will result in an exception } @@ -149,6 +225,105 @@ private static async ValueTask SetupTokenValidationPa return tokenValidationParameters; } + private async Task TriggerMessageReceivedEventAsync(HttpContext httpContext, JwtBearerOptions options, string token, string schemeName) + { + var scheme = await _schemeProvider.GetSchemeAsync(schemeName) + ?? throw new InvalidOperationException($"Authentication scheme '{schemeName}' not found."); + + var messageReceivedContext = new MessageReceivedContext(httpContext, scheme, options) + { + Token = token + }; + + if (options.Events != null && options.Events.MessageReceived != null) + { + await options.Events.MessageReceived(messageReceivedContext).ConfigureAwait(false); + } + + var result = new EventResult { Token = messageReceivedContext.Token }; + + // If the event provided a principal, use it directly + if (messageReceivedContext.Result?.Succeeded == true) + { + result.Handled = true; + result.Success = true; + result.Principal = messageReceivedContext.Principal; + } + + return result; + } + + private async Task TriggerTokenValidatedEventAsync(HttpContext httpContext, JwtBearerOptions options, ClaimsPrincipal principal, SecurityToken securityToken, string schemeName) + { + var scheme = await _schemeProvider.GetSchemeAsync(schemeName) + ?? throw new InvalidOperationException($"Authentication scheme '{schemeName}' not found."); + + var tokenValidatedContext = new TokenValidatedContext(httpContext, scheme, options) + { + Principal = principal, + SecurityToken = securityToken + }; + + if (options.Events != null && options.Events.TokenValidated != null) + { + await options.Events.TokenValidated(tokenValidatedContext).ConfigureAwait(false); + } + + var result = new EventResult(); + + // If the event failed or replaced the principal + if (tokenValidatedContext.Result != null) + { + result.Handled = true; + result.Success = tokenValidatedContext.Result.Succeeded; + if (tokenValidatedContext.Result.Succeeded) + { + result.Principal = tokenValidatedContext.Principal; + } + } + + return result; + } + + private async Task TriggerAuthenticationFailedEventAsync(HttpContext httpContext, JwtBearerOptions options, Exception exception, string schemeName) + { + var scheme = await _schemeProvider.GetSchemeAsync(schemeName) + ?? throw new InvalidOperationException($"Authentication scheme '{schemeName}' not found."); + + var authenticationFailedContext = new AuthenticationFailedContext(httpContext, scheme, options) + { + Exception = exception + }; + + if (options.Events != null && options.Events.AuthenticationFailed != null) + { + await options.Events.AuthenticationFailed(authenticationFailedContext).ConfigureAwait(false); + } + + var result = new EventResult(); + + // If the event handled the exception and succeeded + if (authenticationFailedContext.Result != null) + { + result.Handled = true; + result.Success = authenticationFailedContext.Result.Succeeded; + if (authenticationFailedContext.Result.Succeeded) + { + result.Principal = authenticationFailedContext.Principal; + } + } + + return result; + } + + private sealed class EventResult + { + public bool Handled { get; set; } + public bool Success { get; set; } + public ClaimsPrincipal? Principal { get; set; } + public string Token { get; set; } = string.Empty; + } + #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member public sealed class AuthPayload { diff --git a/src/Tests.ApiApprovals/ApiApprovalTests.cs b/src/Tests.ApiApprovals/ApiApprovalTests.cs index 9acb29b..2daf149 100644 --- a/src/Tests.ApiApprovals/ApiApprovalTests.cs +++ b/src/Tests.ApiApprovals/ApiApprovalTests.cs @@ -1,4 +1,5 @@ using GraphQL.AspNetCore3; +using GraphQL.AspNetCore3.JwtBearer; using PublicApiGenerator; using Shouldly; using Xunit; @@ -12,6 +13,7 @@ public class ApiApprovalTests { [Theory] [InlineData(typeof(GraphQLHttpMiddleware))] + [InlineData(typeof(JwtWebSocketAuthenticationService))] public void PublicApi(Type type) { string publicApi = type.Assembly.GeneratePublicApi(new ApiGeneratorOptions { diff --git a/src/Tests.ApiApprovals/GraphQL.AspNetCore3.JwtBearer.approved.txt b/src/Tests.ApiApprovals/GraphQL.AspNetCore3.JwtBearer.approved.txt new file mode 100644 index 0000000..96587a5 --- /dev/null +++ b/src/Tests.ApiApprovals/GraphQL.AspNetCore3.JwtBearer.approved.txt @@ -0,0 +1,27 @@ +namespace GraphQL.AspNetCore3.JwtBearer +{ + public class JwtBearerAuthenticationOptions + { + public JwtBearerAuthenticationOptions() { } + public bool EnableJwtEvents { get; set; } + } + public class JwtWebSocketAuthenticationService : GraphQL.AspNetCore3.WebSockets.IWebSocketAuthenticationService + { + public JwtWebSocketAuthenticationService(GraphQL.IGraphQLSerializer graphQLSerializer, Microsoft.Extensions.Options.IOptionsMonitor jwtBearerOptionsMonitor, Microsoft.Extensions.Options.IOptions authenticationOptions, Microsoft.Extensions.Options.IOptions jwtBearerAuthenticationOptions, Microsoft.AspNetCore.Authentication.IAuthenticationSchemeProvider schemeProvider) { } + public System.Threading.Tasks.Task AuthenticateAsync(GraphQL.AspNetCore3.WebSockets.AuthenticationRequest authenticationRequest) { } + public sealed class AuthPayload + { + public AuthPayload() { } + public string? Authorization { get; set; } + } + } +} +namespace GraphQL +{ + public static class AspNetCore3JwtBearerExtensions + { + public static GraphQL.DI.IGraphQLBuilder AddJwtBearerAuthentication(this GraphQL.DI.IGraphQLBuilder builder) { } + public static GraphQL.DI.IGraphQLBuilder AddJwtBearerAuthentication(this GraphQL.DI.IGraphQLBuilder builder, System.Action configureOptions) { } + public static GraphQL.DI.IGraphQLBuilder AddJwtBearerAuthentication(this GraphQL.DI.IGraphQLBuilder builder, bool enableJwtEvents) { } + } +} diff --git a/src/Tests.ApiApprovals/Tests.ApiTests.csproj b/src/Tests.ApiApprovals/Tests.ApiTests.csproj index fcbb7d5..86c37e7 100644 --- a/src/Tests.ApiApprovals/Tests.ApiTests.csproj +++ b/src/Tests.ApiApprovals/Tests.ApiTests.csproj @@ -16,6 +16,7 @@ + diff --git a/src/Tests/JwtBearer/AspNetCore3JwtBearerExtensionsTests.cs b/src/Tests/JwtBearer/AspNetCore3JwtBearerExtensionsTests.cs index 2686cc0..c7c653c 100644 --- a/src/Tests/JwtBearer/AspNetCore3JwtBearerExtensionsTests.cs +++ b/src/Tests/JwtBearer/AspNetCore3JwtBearerExtensionsTests.cs @@ -25,6 +25,11 @@ public void AddJwtBearerAuthentication_ShouldAddJwtWebSocketAuthenticationServic ServiceLifetime.Singleton, false)) .Returns(serviceRegisterMock.Object); + + // Setup the Configure method to accept any Action + serviceRegisterMock + .Setup(x => x.Configure(It.IsAny>())) + .Returns(serviceRegisterMock.Object); // Act var result = graphQLBuilderMock.Object.AddJwtBearerAuthentication(); From 8bad37b504779aba31bea25dd927c4cfbb46e304 Mon Sep 17 00:00:00 2001 From: Shane Krueger Date: Wed, 7 May 2025 15:13:01 -0400 Subject: [PATCH 2/8] fix comment --- .../JwtBearerAuthenticationOptions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/GraphQL.AspNetCore3.JwtBearer/JwtBearerAuthenticationOptions.cs b/src/GraphQL.AspNetCore3.JwtBearer/JwtBearerAuthenticationOptions.cs index 89e1ad9..05e953f 100644 --- a/src/GraphQL.AspNetCore3.JwtBearer/JwtBearerAuthenticationOptions.cs +++ b/src/GraphQL.AspNetCore3.JwtBearer/JwtBearerAuthenticationOptions.cs @@ -9,7 +9,7 @@ public class JwtBearerAuthenticationOptions { /// /// Gets or sets a value indicating whether JWT events should be enabled. - /// When enabled, the will implement + /// When enabled, the will raise the /// , , /// and events as appropriate. /// From 94c07fbac9b4354d67794bc845926206e8c2483a Mon Sep 17 00:00:00 2001 From: Shane Krueger Date: Wed, 7 May 2025 15:13:39 -0400 Subject: [PATCH 3/8] update formatting --- .../JwtWebSocketAuthenticationService.cs | 82 ++++++++----------- 1 file changed, 32 insertions(+), 50 deletions(-) diff --git a/src/GraphQL.AspNetCore3.JwtBearer/JwtWebSocketAuthenticationService.cs b/src/GraphQL.AspNetCore3.JwtBearer/JwtWebSocketAuthenticationService.cs index bd6693a..89f5130 100644 --- a/src/GraphQL.AspNetCore3.JwtBearer/JwtWebSocketAuthenticationService.cs +++ b/src/GraphQL.AspNetCore3.JwtBearer/JwtWebSocketAuthenticationService.cs @@ -91,19 +91,16 @@ public async Task AuthenticateAsync(AuthenticationRequest authenticationRequest) var options = _jwtBearerOptionsMonitor.Get(scheme); // If JWT events are enabled, trigger the MessageReceived event - if (_jwtBearerAuthenticationOptions.EnableJwtEvents) - { + if (_jwtBearerAuthenticationOptions.EnableJwtEvents) { var messageResult = await TriggerMessageReceivedEventAsync(connection.HttpContext, options, token, scheme).ConfigureAwait(false); - if (messageResult.Handled) - { - if (messageResult.Success) - { + if (messageResult.Handled) { + if (messageResult.Success) { connection.HttpContext.User = messageResult.Principal!; return; } continue; } - + token = messageResult.Token; } @@ -158,34 +155,30 @@ public async Task AuthenticateAsync(AuthenticationRequest authenticationRequest) if (validator.CanReadToken(token)) { try { var principal = validator.ValidateToken(token, tokenValidationParameters, out var securityToken); - + // If JWT events are enabled, trigger the TokenValidated event - if (_jwtBearerAuthenticationOptions.EnableJwtEvents) - { + if (_jwtBearerAuthenticationOptions.EnableJwtEvents) { var validatedResult = await TriggerTokenValidatedEventAsync(connection.HttpContext, options, principal, securityToken, scheme).ConfigureAwait(false); - if (validatedResult.Handled && !validatedResult.Success) - { + if (validatedResult.Handled && !validatedResult.Success) { continue; } - + principal = validatedResult.Principal ?? principal; } - + // set the ClaimsPrincipal for the HttpContext; authentication will take place against this object connection.HttpContext.User = principal; return; } catch (Exception ex) { // If JWT events are enabled, trigger the AuthenticationFailed event - if (_jwtBearerAuthenticationOptions.EnableJwtEvents) - { + if (_jwtBearerAuthenticationOptions.EnableJwtEvents) { var failedResult = await TriggerAuthenticationFailedEventAsync(connection.HttpContext, options, ex, scheme).ConfigureAwait(false); - if (failedResult.Handled && failedResult.Success) - { + if (failedResult.Handled && failedResult.Success) { connection.HttpContext.User = failedResult.Principal!; return; } } - + // no errors during authentication should throw an exception // specifically, attempting to validate an invalid JWT token will result in an exception } @@ -229,22 +222,19 @@ private async Task TriggerMessageReceivedEventAsync(HttpContext htt { var scheme = await _schemeProvider.GetSchemeAsync(schemeName) ?? throw new InvalidOperationException($"Authentication scheme '{schemeName}' not found."); - - var messageReceivedContext = new MessageReceivedContext(httpContext, scheme, options) - { + + var messageReceivedContext = new MessageReceivedContext(httpContext, scheme, options) { Token = token }; - if (options.Events != null && options.Events.MessageReceived != null) - { + if (options.Events != null && options.Events.MessageReceived != null) { await options.Events.MessageReceived(messageReceivedContext).ConfigureAwait(false); } - + var result = new EventResult { Token = messageReceivedContext.Token }; - + // If the event provided a principal, use it directly - if (messageReceivedContext.Result?.Succeeded == true) - { + if (messageReceivedContext.Result?.Succeeded == true) { result.Handled = true; result.Success = true; result.Principal = messageReceivedContext.Principal; @@ -257,27 +247,23 @@ private async Task TriggerTokenValidatedEventAsync(HttpContext http { var scheme = await _schemeProvider.GetSchemeAsync(schemeName) ?? throw new InvalidOperationException($"Authentication scheme '{schemeName}' not found."); - - var tokenValidatedContext = new TokenValidatedContext(httpContext, scheme, options) - { + + var tokenValidatedContext = new TokenValidatedContext(httpContext, scheme, options) { Principal = principal, SecurityToken = securityToken }; - if (options.Events != null && options.Events.TokenValidated != null) - { + if (options.Events != null && options.Events.TokenValidated != null) { await options.Events.TokenValidated(tokenValidatedContext).ConfigureAwait(false); } - + var result = new EventResult(); - + // If the event failed or replaced the principal - if (tokenValidatedContext.Result != null) - { + if (tokenValidatedContext.Result != null) { result.Handled = true; result.Success = tokenValidatedContext.Result.Succeeded; - if (tokenValidatedContext.Result.Succeeded) - { + if (tokenValidatedContext.Result.Succeeded) { result.Principal = tokenValidatedContext.Principal; } } @@ -289,26 +275,22 @@ private async Task TriggerAuthenticationFailedEventAsync(HttpContex { var scheme = await _schemeProvider.GetSchemeAsync(schemeName) ?? throw new InvalidOperationException($"Authentication scheme '{schemeName}' not found."); - - var authenticationFailedContext = new AuthenticationFailedContext(httpContext, scheme, options) - { + + var authenticationFailedContext = new AuthenticationFailedContext(httpContext, scheme, options) { Exception = exception }; - if (options.Events != null && options.Events.AuthenticationFailed != null) - { + if (options.Events != null && options.Events.AuthenticationFailed != null) { await options.Events.AuthenticationFailed(authenticationFailedContext).ConfigureAwait(false); } - + var result = new EventResult(); - + // If the event handled the exception and succeeded - if (authenticationFailedContext.Result != null) - { + if (authenticationFailedContext.Result != null) { result.Handled = true; result.Success = authenticationFailedContext.Result.Succeeded; - if (authenticationFailedContext.Result.Succeeded) - { + if (authenticationFailedContext.Result.Succeeded) { result.Principal = authenticationFailedContext.Principal; } } From b3ecb394d06ebd32da8ed634fd98038a887f3e58 Mon Sep 17 00:00:00 2001 From: Shane Krueger Date: Wed, 7 May 2025 16:24:44 -0400 Subject: [PATCH 4/8] update --- src/Tests/JwtBearer/AspNetCore3JwtBearerExtensionsTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Tests/JwtBearer/AspNetCore3JwtBearerExtensionsTests.cs b/src/Tests/JwtBearer/AspNetCore3JwtBearerExtensionsTests.cs index c7c653c..0015b93 100644 --- a/src/Tests/JwtBearer/AspNetCore3JwtBearerExtensionsTests.cs +++ b/src/Tests/JwtBearer/AspNetCore3JwtBearerExtensionsTests.cs @@ -25,7 +25,7 @@ public void AddJwtBearerAuthentication_ShouldAddJwtWebSocketAuthenticationServic ServiceLifetime.Singleton, false)) .Returns(serviceRegisterMock.Object); - + // Setup the Configure method to accept any Action serviceRegisterMock .Setup(x => x.Configure(It.IsAny>())) From 1a640b56429f126e3dac76205263b9550e1aa49f Mon Sep 17 00:00:00 2001 From: Shane Krueger Date: Wed, 7 May 2025 16:28:51 -0400 Subject: [PATCH 5/8] delete net core 3.1 / 5.0 testing --- src/Tests/JwtBearer/JwtWebSocketAuthenticationServiceTests.cs | 2 +- src/Tests/Tests.csproj | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Tests/JwtBearer/JwtWebSocketAuthenticationServiceTests.cs b/src/Tests/JwtBearer/JwtWebSocketAuthenticationServiceTests.cs index f71f1be..670de68 100644 --- a/src/Tests/JwtBearer/JwtWebSocketAuthenticationServiceTests.cs +++ b/src/Tests/JwtBearer/JwtWebSocketAuthenticationServiceTests.cs @@ -253,7 +253,7 @@ private TestServer CreateTestServer(bool defaultScheme = true, bool customScheme services.AddGraphQL(b => b .AddSchema(_schema) .AddSystemTextJson() - .AddJwtBearerAuthentication() + .AddJwtBearerAuthentication(true) ); }) .Configure(app => { diff --git a/src/Tests/Tests.csproj b/src/Tests/Tests.csproj index 6da495c..912602c 100644 --- a/src/Tests/Tests.csproj +++ b/src/Tests/Tests.csproj @@ -1,10 +1,10 @@ - netcoreapp2.1;netcoreapp3.1;net5.0;net6.0;net8.0 + netcoreapp2.1;net6.0;net8.0 - net48;netcoreapp2.1;netcoreapp3.1;net5.0;net6.0;net8.0 + net48;netcoreapp2.1;net6.0;net8.0 From 4f88d25df2e9b37dd736144f2fa8ce24592797d9 Mon Sep 17 00:00:00 2001 From: Shane Krueger Date: Wed, 7 May 2025 16:29:19 -0400 Subject: [PATCH 6/8] update --- src/Tests/Tests.csproj | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/src/Tests/Tests.csproj b/src/Tests/Tests.csproj index 912602c..e2f2106 100644 --- a/src/Tests/Tests.csproj +++ b/src/Tests/Tests.csproj @@ -75,22 +75,6 @@ 6.0.* - - - 5.0.* - - - 5.0.* - - - - - 3.1.* - - - 3.1.* - - 2.1.* From 033f8dfbe201fe8db144fd1f1cf9ae3de9851ff1 Mon Sep 17 00:00:00 2001 From: Shane Krueger Date: Wed, 7 May 2025 16:34:55 -0400 Subject: [PATCH 7/8] update --- .github/workflows/test.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f094b51..d2fdbff 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -26,8 +26,6 @@ jobs: with: dotnet-version: | 2.1.x - 3.1.x - 5.0.x 6.0.x 8.0.x source-url: https://nuget.pkg.github.com/Shane32/index.json From 92a648673d45caf59c42aab5d8da08f288144b7b Mon Sep 17 00:00:00 2001 From: Shane Krueger Date: Wed, 7 May 2025 16:40:52 -0400 Subject: [PATCH 8/8] update --- .github/workflows/test.yml | 2 ++ src/Tests/Tests.csproj | 20 ++++++++++++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d2fdbff..f094b51 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -26,6 +26,8 @@ jobs: with: dotnet-version: | 2.1.x + 3.1.x + 5.0.x 6.0.x 8.0.x source-url: https://nuget.pkg.github.com/Shane32/index.json diff --git a/src/Tests/Tests.csproj b/src/Tests/Tests.csproj index e2f2106..fbd5ab5 100644 --- a/src/Tests/Tests.csproj +++ b/src/Tests/Tests.csproj @@ -1,10 +1,10 @@ - netcoreapp2.1;net6.0;net8.0 + net6.0;net8.0 - net48;netcoreapp2.1;net6.0;net8.0 + net48;netcoreapp2.1;netcoreapp3.1;net5.0;net6.0;net8.0 @@ -75,6 +75,22 @@ 6.0.* + + + 5.0.* + + + 5.0.* + + + + + 3.1.* + + + 3.1.* + + 2.1.*