diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8f75fcaa..e2dfa5ba 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,9 @@
# Unreleased
+# JWT.Extensions.AspNetCore 11.0.0-beta3
+
+- Converted to use the event model to allow dependency injection with custom event classes.
+
# JWT 11.0.0-beta2, JWT.Extensions.AspNetCore 11.0.0-beta2, JWT.Extensions.DependencyInjection 3.0.0-beta2
- Replaced .NET 7 with .NET 8 whenever applicable
diff --git a/src/JWT.Extensions.AspNetCore/FailedTicketContext.cs b/src/JWT.Extensions.AspNetCore/FailedTicketContext.cs
new file mode 100644
index 00000000..0c7952f2
--- /dev/null
+++ b/src/JWT.Extensions.AspNetCore/FailedTicketContext.cs
@@ -0,0 +1,25 @@
+using System;
+using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.Logging;
+
+namespace JWT.Extensions.AspNetCore
+{
+ public class FailedTicketContext
+ {
+ public FailedTicketContext(ILogger logger, Exception exception, HttpContext context, JwtAuthenticationOptions options)
+ {
+ this.Logger = logger;
+ this.Exception = exception;
+ this.Context = context;
+ this.Options = options;
+ }
+
+ public ILogger Logger { get; }
+
+ public Exception Exception { get; }
+
+ public HttpContext Context { get; }
+
+ public JwtAuthenticationOptions Options { get; }
+ }
+}
diff --git a/src/JWT.Extensions.AspNetCore/JWT.Extensions.AspNetCore.csproj b/src/JWT.Extensions.AspNetCore/JWT.Extensions.AspNetCore.csproj
index 80287262..107bbfc1 100644
--- a/src/JWT.Extensions.AspNetCore/JWT.Extensions.AspNetCore.csproj
+++ b/src/JWT.Extensions.AspNetCore/JWT.Extensions.AspNetCore.csproj
@@ -10,7 +10,7 @@
Alexander Batishchev
jwt;json;asp.net;asp.net core;.net core;authorization
MIT
- 11.0.0-beta2
+ 11.0.0-beta3
11.0.0.0
11.0.0.0
JWT.Extensions.AspNetCore
diff --git a/src/JWT.Extensions.AspNetCore/JwtAuthenticationEvents.cs b/src/JWT.Extensions.AspNetCore/JwtAuthenticationEvents.cs
new file mode 100644
index 00000000..0bd72781
--- /dev/null
+++ b/src/JWT.Extensions.AspNetCore/JwtAuthenticationEvents.cs
@@ -0,0 +1,87 @@
+using System;
+using Microsoft.AspNetCore.Authentication;
+using Microsoft.Extensions.Logging;
+using Microsoft.Net.Http.Headers;
+
+namespace JWT.Extensions.AspNetCore
+{
+ public class JwtAuthenticationEvents
+ {
+ private static readonly Action _logMissingHeader;
+ private static readonly Action _logIncorrectScheme;
+ private static readonly Action _logEmptyHeader;
+ private static readonly Action _logSuccessfulTicket;
+ private static readonly Action _logFailedTicket;
+
+ static JwtAuthenticationEvents()
+ {
+ _logMissingHeader = LoggerMessage.Define(
+ LogLevel.Information,
+ 10,
+ $"Header {nameof(HeaderNames.Authorization)} is empty, returning none");
+
+ _logIncorrectScheme = LoggerMessage.Define(
+ LogLevel.Information,
+ 11,
+ $"Header {nameof(HeaderNames.Authorization)} scheme is {{ActualScheme}}, expected {{ExpectedScheme}}, returning none");
+
+ _logEmptyHeader = LoggerMessage.Define(
+ LogLevel.Information,
+ 12,
+ $"Token in header {nameof(HeaderNames.Authorization)} is empty, returning none");
+
+ _logSuccessfulTicket = LoggerMessage.Define(
+ LogLevel.Information,
+ 1,
+ "Successfully decoded JWT, returning success");
+
+ _logFailedTicket = LoggerMessage.Define(
+ LogLevel.Information,
+ 2,
+ "Error decoding JWT: {0}, returning failure");
+ }
+
+ public Func OnMissingHeader { get; set; } =
+ logger =>
+ {
+ _logMissingHeader(logger, null);
+ return AuthenticateResult.NoResult();
+ };
+
+ public Func OnIncorrectScheme { get; set; } =
+ (logger, actualScheme, expectedScheme) =>
+ {
+ _logIncorrectScheme(logger, actualScheme, expectedScheme, null);
+ return AuthenticateResult.NoResult();
+ };
+
+ public Func OnEmptyHeader { get; set; } = (logger, header) =>
+ {
+ _logEmptyHeader(logger, null);
+ return AuthenticateResult.NoResult();
+ };
+
+ public Func OnSuccessfulTicket { get; set; } = context =>
+ {
+ _logSuccessfulTicket(context.Logger, null);
+ return AuthenticateResult.Success(context.Ticket);
+ };
+
+ public Func OnFailedTicket { get; set; } = context =>
+ {
+ _logFailedTicket(context.Logger, context.Exception.Message, context.Exception);
+ return AuthenticateResult.Fail(context.Exception);
+ };
+
+ public virtual AuthenticateResult SuccessfulTicket(SuccessfulTicketContext context) => OnSuccessfulTicket(context);
+
+ public virtual AuthenticateResult FailedTicket(FailedTicketContext context) => OnFailedTicket(context);
+
+ public virtual AuthenticateResult EmptyHeader(ILogger logger, string header) => OnEmptyHeader(logger, header);
+
+ public virtual AuthenticateResult IncorrectScheme(ILogger logger, string actualScheme, string expectedScheme) => OnIncorrectScheme(logger, actualScheme, expectedScheme);
+
+ public virtual AuthenticateResult MissingHeader(ILogger logger) => OnMissingHeader(logger);
+
+ }
+}
diff --git a/src/JWT.Extensions.AspNetCore/JwtAuthenticationHandler.cs b/src/JWT.Extensions.AspNetCore/JwtAuthenticationHandler.cs
index 7adc64af..68ac1e0d 100644
--- a/src/JWT.Extensions.AspNetCore/JwtAuthenticationHandler.cs
+++ b/src/JWT.Extensions.AspNetCore/JwtAuthenticationHandler.cs
@@ -12,44 +12,10 @@ namespace JWT.Extensions.AspNetCore
{
public sealed class JwtAuthenticationHandler : AuthenticationHandler
{
- private static readonly Action _logMissingHeader;
- private static readonly Action _logIncorrectScheme;
- private static readonly Action _logEmptyHeader;
- private static readonly Action _logSuccessfulTicket;
- private static readonly Action _logFailedTicket;
-
private readonly IJwtDecoder _jwtDecoder;
private readonly IIdentityFactory _identityFactory;
private readonly ITicketFactory _ticketFactory;
- static JwtAuthenticationHandler()
- {
- _logMissingHeader = LoggerMessage.Define(
- LogLevel.Information,
- 10,
- $"Header {nameof(HeaderNames.Authorization)} is empty, returning none");
-
- _logIncorrectScheme = LoggerMessage.Define(
- LogLevel.Information,
- 11,
- $"Header {nameof(HeaderNames.Authorization)} scheme is {{0}}, expected {{1}}, returning none");
-
- _logEmptyHeader = LoggerMessage.Define(
- LogLevel.Information,
- 12,
- $"Token in header {nameof(HeaderNames.Authorization)} is empty, returning none");
-
- _logSuccessfulTicket = LoggerMessage.Define(
- LogLevel.Information,
- 1,
- "Successfully decoded JWT, returning success");
-
- _logFailedTicket = LoggerMessage.Define(
- LogLevel.Information,
- 2,
- "Error decoding JWT: {0}, returning failure");
- }
-
public JwtAuthenticationHandler(
IJwtDecoder jwtDecoder,
IIdentityFactory identityFactory,
@@ -65,36 +31,6 @@ public JwtAuthenticationHandler(
_ticketFactory = ticketFactory;
}
- public static AuthenticateResult OnMissingHeader(ILogger logger)
- {
- _logMissingHeader(logger, null);
- return AuthenticateResult.NoResult();
- }
-
- public static AuthenticateResult OnIncorrectScheme(ILogger logger, string actualScheme, string expectedScheme)
- {
- _logIncorrectScheme(logger, actualScheme, expectedScheme, null);
- return AuthenticateResult.NoResult();
- }
-
- public static AuthenticateResult OnEmptyHeader(ILogger logger, string header)
- {
- _logEmptyHeader(logger, null);
- return AuthenticateResult.NoResult();
- }
-
- public static AuthenticateResult OnSuccessfulTicket(ILogger logger, AuthenticationTicket ticket)
- {
- _logSuccessfulTicket(logger, null);
- return AuthenticateResult.Success(ticket);
- }
-
- public static AuthenticateResult OnFailedTicket(ILogger logger, Exception ex)
- {
- _logFailedTicket(logger, ex.Message, ex);
- return AuthenticateResult.Fail(ex);
- }
-
protected override Task HandleAuthenticateAsync()
{
var header = this.Context.Request.Headers[HeaderNames.Authorization];
@@ -105,14 +41,14 @@ protected override Task HandleAuthenticateAsync()
private AuthenticateResult GetAuthenticationResult(string header)
{
if (String.IsNullOrEmpty(header))
- return this.Options.OnMissingHeader(this.Logger);
+ return this.Events.MissingHeader(this.Logger);
if (!header.StartsWith(this.Scheme.Name, StringComparison.OrdinalIgnoreCase))
- return this.Options.OnIncorrectScheme(this.Logger, header.Split(' ').FirstOrDefault(), this.Scheme.Name);
+ return this.Events.IncorrectScheme(this.Logger, header.Split(' ').FirstOrDefault(), this.Scheme.Name);
var token = header.Substring(this.Scheme.Name.Length).Trim();
if (String.IsNullOrEmpty(token))
- return this.Options.OnEmptyHeader(this.Logger, header);
+ return this.Events.EmptyHeader(this.Logger, header);
try
{
@@ -120,12 +56,24 @@ private AuthenticateResult GetAuthenticationResult(string header)
var identity = _identityFactory.CreateIdentity(this.Options.PayloadType, payload);
var ticket = _ticketFactory.CreateTicket(identity, this.Scheme);
- return this.Options.OnSuccessfulTicket(this.Logger, ticket);
+ var successContext = new SuccessfulTicketContext(this.Logger, ticket, this.Context, this.Options);
+ return this.Events.SuccessfulTicket(successContext);
}
catch (Exception ex)
{
- return this.Options.OnFailedTicket(this.Logger, ex);
+ var failedContext = new FailedTicketContext(this.Logger, ex, this.Context, this.Options);
+ return this.Events.FailedTicket(failedContext);
}
}
+
+ ///
+ /// The handler calls methods on the events which give the application control at certain points where processing is occurring.
+ /// If it is not provided, a default instance is supplied which does nothing when the methods are called.
+ ///
+ protected new JwtAuthenticationEvents Events
+ {
+ get => (JwtAuthenticationEvents)base.Events!;
+ set => base.Events = value;
+ }
}
-}
\ No newline at end of file
+}
diff --git a/src/JWT.Extensions.AspNetCore/JwtAuthenticationOptions.cs b/src/JWT.Extensions.AspNetCore/JwtAuthenticationOptions.cs
index 69d7a541..ae675936 100644
--- a/src/JWT.Extensions.AspNetCore/JwtAuthenticationOptions.cs
+++ b/src/JWT.Extensions.AspNetCore/JwtAuthenticationOptions.cs
@@ -8,6 +8,11 @@ namespace JWT.Extensions.AspNetCore
{
public class JwtAuthenticationOptions : AuthenticationSchemeOptions
{
+ public JwtAuthenticationOptions()
+ {
+ Events = new JwtAuthenticationEvents();
+ }
+
///
/// The keys used to sign the JWT.
///
@@ -26,41 +31,64 @@ public class JwtAuthenticationOptions : AuthenticationSchemeOptions
/// Handles missing authentication header.
///
///
- /// For the default behavior .
+ /// For the default behavior .
///
- public Func OnMissingHeader { get; set; } = JwtAuthenticationHandler.OnMissingHeader;
+ [Obsolete("Use Events.OnMissingHeader")]
+ public Func OnMissingHeader
+ {
+ get => Events.OnMissingHeader;
+ set => Events.OnMissingHeader = value;
+ }
///
/// Handles incorrect authentication scheme.
///
///
- /// For the default behavior .
+ /// For the default behavior .
///
- public Func OnIncorrectScheme { get; set; } = JwtAuthenticationHandler.OnIncorrectScheme;
+ [Obsolete("Use Events.OnIncorrectScheme")]
+ public Func OnIncorrectScheme
+ {
+ get => Events.OnIncorrectScheme;
+ set => Events.OnIncorrectScheme = value;
+ }
///
/// Handles empty authentication header.
///
///
- /// For the default behavior .
+ /// For the default behavior .
///
- public Func OnEmptyHeader { get; set; } = JwtAuthenticationHandler.OnEmptyHeader;
+ [Obsolete("Use Events.OnEmptyHeader")]
+ public Func OnEmptyHeader
+ {
+ get => Events.OnEmptyHeader;
+ set => Events.OnEmptyHeader = value;
+ }
///
/// Handles successful authentication header.
///
///
- /// For the default behavior .
+ /// For the default behavior .
///
- public Func OnSuccessfulTicket { get; set; } = JwtAuthenticationHandler.OnSuccessfulTicket;
+ [Obsolete("Use Events.OnSuccessfulTicket")]
+ public Func OnSuccessfulTicket
+ {
+ set => Events.OnSuccessfulTicket = (context) => value(context.Logger, context.Ticket);
+ }
///
/// Handles failed authentication header.
///
///
- /// For the default behavior .
+ /// For the default behavior .
///
- public Func OnFailedTicket { get; set; } = JwtAuthenticationHandler.OnFailedTicket;
+ [Obsolete("Use Events.OnFailedTicket")]
+ public Func OnFailedTicket
+ {
+ set => Events.OnFailedTicket = context => value(context.Logger, context.Exception);
+ }
///
/// Whether to include by default AuthenticationScheme into the resulting .
@@ -77,5 +105,15 @@ public class JwtAuthenticationOptions : AuthenticationSchemeOptions
/// The default value is .
///
public Type PayloadType { get; set; } = typeof(Dictionary);
+
+
+ ///
+ /// Custom Event Overrides
+ ///
+ public new JwtAuthenticationEvents Events
+ {
+ get => (JwtAuthenticationEvents)base.Events!;
+ set => base.Events = value;
+ }
}
-}
\ No newline at end of file
+}
diff --git a/src/JWT.Extensions.AspNetCore/SuccessfulTicketContext.cs b/src/JWT.Extensions.AspNetCore/SuccessfulTicketContext.cs
new file mode 100644
index 00000000..caf7fa74
--- /dev/null
+++ b/src/JWT.Extensions.AspNetCore/SuccessfulTicketContext.cs
@@ -0,0 +1,25 @@
+using Microsoft.AspNetCore.Authentication;
+using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.Logging;
+
+namespace JWT.Extensions.AspNetCore
+{
+ public class SuccessfulTicketContext
+ {
+ public SuccessfulTicketContext(ILogger logger, AuthenticationTicket ticket, HttpContext context, JwtAuthenticationOptions options)
+ {
+ this.Logger = logger;
+ this.Ticket = ticket;
+ this.Context = context;
+ this.Options = options;
+ }
+
+ public ILogger Logger { get; }
+
+ public AuthenticationTicket Ticket { get; }
+
+ public HttpContext Context { get; }
+
+ public JwtAuthenticationOptions Options { get; }
+ }
+}
diff --git a/tests/JWT.Extensions.AspNetCore.Tests/JwtAuthenticationEventsIntegrationTests.cs b/tests/JWT.Extensions.AspNetCore.Tests/JwtAuthenticationEventsIntegrationTests.cs
new file mode 100644
index 00000000..7f4f0ee2
--- /dev/null
+++ b/tests/JWT.Extensions.AspNetCore.Tests/JwtAuthenticationEventsIntegrationTests.cs
@@ -0,0 +1,146 @@
+using System;
+using System.Net;
+using System.Net.Http.Headers;
+using System.Net.Mime;
+using System.Threading;
+using System.Threading.Tasks;
+using FluentAssertions;
+using JWT.Algorithms;
+using JWT.Tests.Models;
+using Microsoft.AspNetCore.Authentication;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.TestHost;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+namespace JWT.Extensions.AspNetCore.Tests
+{
+ [TestClass]
+ public class JwtAuthenticationEventsIntegrationTests
+ {
+ private static CancellationToken _cancellationToken;
+
+ [ClassInitialize]
+ public static void ClassInitialize(TestContext context)
+ {
+ _cancellationToken = context.CancellationTokenSource.Token;
+ }
+
+ [TestMethod]
+ public async Task Request_Should_Fire_Events()
+ {
+ using var server = CreateServer(options => options.EventsType = typeof(MyEvents));
+
+ using var client = server.CreateClient();
+
+ // Arrange
+ client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(
+ JwtAuthenticationDefaults.AuthenticationScheme,
+ TestData.TokenByAsymmetricAlgorithm);
+
+ // Act
+ using var response = await client.GetAsync("https://example.com/", _cancellationToken);
+
+ // Assert
+ response.StatusCode.Should().Be(HttpStatusCode.OK);
+
+ server.Services.GetRequiredService().HandledSuccessfulTicket.Should().BeTrue();
+ }
+
+ [TestMethod]
+ public async Task Backwards_Compat_Request_Should_Fire_Events()
+ {
+ bool backwardsCompat = false;
+
+ using var server = CreateServer(options => options.OnSuccessfulTicket = (_, ticket) =>
+ {
+ backwardsCompat = true;
+ return AuthenticateResult.Success(ticket);
+ });
+ using var client = server.CreateClient();
+
+ // Arrange
+ client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(
+ JwtAuthenticationDefaults.AuthenticationScheme,
+ TestData.TokenByAsymmetricAlgorithm);
+
+ // Act
+ using var response = await client.GetAsync("https://example.com/", _cancellationToken);
+
+ // Assert
+ response.StatusCode.Should().Be(HttpStatusCode.OK);
+ backwardsCompat.Should().BeTrue();
+ }
+
+ private static TestServer CreateServer(Action configureOptions)
+ {
+ var builder = new WebHostBuilder()
+ .Configure(app =>
+ {
+ app.UseAuthentication();
+
+ app.Use(async (HttpContext context, Func _) =>
+ {
+ var authenticationResult = await context.AuthenticateAsync();
+ if (authenticationResult.Succeeded)
+ {
+ context.Response.StatusCode = StatusCodes.Status200OK;
+ context.Response.ContentType = new ContentType("text/json").MediaType;
+
+ await context.Response.WriteAsync("Hello");
+ }
+ else
+ {
+ await context.ChallengeAsync();
+ }
+ });
+ })
+ .ConfigureServices(services =>
+ {
+ services.AddAuthentication(options =>
+ {
+ // Prevents from System.InvalidOperationException: No authenticationScheme was specified, and there was no DefaultAuthenticateScheme found.
+ options.DefaultAuthenticateScheme = JwtAuthenticationDefaults.AuthenticationScheme;
+
+ // Prevents from System.InvalidOperationException: No authenticationScheme was specified, and there was no DefaultChallengeScheme found.
+ options.DefaultChallengeScheme = JwtAuthenticationDefaults.AuthenticationScheme;
+ })
+ .AddJwt(options =>
+ {
+ options.Keys = TestData.Secrets;
+ options.VerifySignature = true;
+ configureOptions(options);
+ });
+
+ services.AddSingleton()
+ .AddSingleton()
+ .AddSingleton(new DelegateAlgorithmFactory(TestData.RS256Algorithm));
+ });
+ return new TestServer(builder);
+ }
+
+ private sealed class MyEventsDependency
+ {
+ public bool HandledSuccessfulTicket { get; private set; }
+
+ public void Set() =>
+ this.HandledSuccessfulTicket = true;
+ }
+
+ private sealed class MyEvents : JwtAuthenticationEvents
+ {
+ private readonly MyEventsDependency _dependency;
+
+ public MyEvents(MyEventsDependency dependency) =>
+ _dependency = dependency;
+
+ public override AuthenticateResult SuccessfulTicket(SuccessfulTicketContext context)
+ {
+ _dependency.Set();
+ return base.SuccessfulTicket(context);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/JWT.Extensions.AspNetCore.Tests/JwtAuthenticationHandlerIntegrationTests.cs b/tests/JWT.Extensions.AspNetCore.Tests/JwtAuthenticationHandlerIntegrationTests.cs
index b4573c40..d0f21d55 100644
--- a/tests/JWT.Extensions.AspNetCore.Tests/JwtAuthenticationHandlerIntegrationTests.cs
+++ b/tests/JWT.Extensions.AspNetCore.Tests/JwtAuthenticationHandlerIntegrationTests.cs
@@ -3,6 +3,7 @@
using System.Net.Http;
using System.Net.Http.Headers;
using System.Net.Mime;
+using System.Threading;
using System.Threading.Tasks;
using AutoFixture;
using FluentAssertions;
@@ -21,6 +22,7 @@ namespace JWT.Extensions.AspNetCore.Tests
[TestClass]
public class JwtAuthenticationHandlerIntegrationTests
{
+ private static CancellationToken _cancellationToken;
private static readonly Fixture _fixture = new Fixture();
private static TestServer _server;
@@ -29,6 +31,7 @@ public class JwtAuthenticationHandlerIntegrationTests
[ClassInitialize]
public static void ClassInitialize(TestContext context)
{
+ _cancellationToken = context.CancellationTokenSource.Token;
var options = new JwtAuthenticationOptions
{
Keys = TestData.Secrets,
@@ -64,7 +67,7 @@ public async Task Request_Should_Return_Ok_When_Token_Is_Valid()
TestData.TokenByAsymmetricAlgorithm);
// Act
- var response = await _client.GetAsync("https://example.com/");
+ var response = await _client.GetAsync("https://example.com/", _cancellationToken);
// Assert
response.StatusCode.Should().Be(HttpStatusCode.OK);
@@ -79,7 +82,7 @@ public async Task Request_Should_Return_Unauthorized_When_Token_Is_Empty()
String.Empty);
// Act
- var response = await _client.GetAsync("https://example.com/");
+ var response = await _client.GetAsync("https://example.com/", _cancellationToken);
// Assert
response.StatusCode.Should().Be(HttpStatusCode.Unauthorized);
@@ -94,7 +97,7 @@ public async Task Request_Should_Return_Unauthorized_When_Token_Is_Invalid()
TestData.TokenWithIncorrectSignature);
// Act
- var response = await _client.GetAsync("https://example.com/");
+ var response = await _client.GetAsync("https://example.com/", _cancellationToken);
// Assert
response.StatusCode.Should().Be(HttpStatusCode.Unauthorized);
@@ -109,7 +112,7 @@ public async Task Request_Should_Return_Unauthorized_When_AuthenticationScheme_I
_fixture.Create());
// Act
- var response = await _client.GetAsync("https://example.com/");
+ var response = await _client.GetAsync("https://example.com/", _cancellationToken);
// Assert
response.StatusCode.Should().Be(HttpStatusCode.Unauthorized);
@@ -122,7 +125,7 @@ private static TestServer CreateServer(JwtAuthenticationOptions configureOptions
{
app.UseAuthentication();
- app.Use(async (HttpContext context, Func next) =>
+ app.Use(async (HttpContext context, Func _) =>
{
var authenticationResult = await context.AuthenticateAsync();
if (authenticationResult.Succeeded)
@@ -130,7 +133,7 @@ private static TestServer CreateServer(JwtAuthenticationOptions configureOptions
context.Response.StatusCode = StatusCodes.Status200OK;
context.Response.ContentType = new ContentType("text/json").MediaType;
- await context.Response.WriteAsync("Hello");
+ await context.Response.WriteAsync("Hello", _cancellationToken);
}
else
{
@@ -150,12 +153,11 @@ private static TestServer CreateServer(JwtAuthenticationOptions configureOptions
})
.AddJwt(options =>
{
- options.Keys = null;
+ options.Keys = configureOptions.Keys;
options.VerifySignature = configureOptions.VerifySignature;
});
services.AddSingleton(new DelegateAlgorithmFactory(TestData.RS256Algorithm));
});
-
return new TestServer(builder);
}
}