From 46a9dab6c3a6422905850beb0b4c16e1ef84ae97 Mon Sep 17 00:00:00 2001 From: Joe DeCock Date: Thu, 22 Jan 2026 15:20:37 -0600 Subject: [PATCH] Rename expiration mode for clarity This is based on feedback from Brock and Dom --- .../DPoP/DPoPOptions.cs | 4 ++-- ...tionMode.cs => DPoPProofExpirationMode.cs} | 6 ++--- .../DPoP/DPoPProofValidator.cs | 16 +++++++------- .../DPoP/DPoPIntegrationTests.cs | 4 ++-- .../DPoP/FreshnessTests.cs | 22 +++++++++---------- .../DPoP/ReplayTests.cs | 4 ++-- 6 files changed, 28 insertions(+), 28 deletions(-) rename aspnetcore-authentication-jwtbearer/src/AspNetCore.Authentication.JwtBearer/DPoP/{ExpirationValidationMode.cs => DPoPProofExpirationMode.cs} (72%) diff --git a/aspnetcore-authentication-jwtbearer/src/AspNetCore.Authentication.JwtBearer/DPoP/DPoPOptions.cs b/aspnetcore-authentication-jwtbearer/src/AspNetCore.Authentication.JwtBearer/DPoP/DPoPOptions.cs index 08a0a8556..2390247cc 100644 --- a/aspnetcore-authentication-jwtbearer/src/AspNetCore.Authentication.JwtBearer/DPoP/DPoPOptions.cs +++ b/aspnetcore-authentication-jwtbearer/src/AspNetCore.Authentication.JwtBearer/DPoP/DPoPOptions.cs @@ -40,9 +40,9 @@ public sealed class DPoPOptions /// /// Controls how the issued at time of proof tokens is validated. Defaults to . + /// cref="DPoPProofExpirationMode.IssuedAt"/>. /// - public ExpirationMode ProofTokenExpirationMode { get; set; } = ExpirationMode.IssuedAt; + public DPoPProofExpirationMode ProofTokenExpirationMode { get; set; } = DPoPProofExpirationMode.IssuedAt; /// /// The maximum allowed length of a proof token, which is enforced to diff --git a/aspnetcore-authentication-jwtbearer/src/AspNetCore.Authentication.JwtBearer/DPoP/ExpirationValidationMode.cs b/aspnetcore-authentication-jwtbearer/src/AspNetCore.Authentication.JwtBearer/DPoP/DPoPProofExpirationMode.cs similarity index 72% rename from aspnetcore-authentication-jwtbearer/src/AspNetCore.Authentication.JwtBearer/DPoP/ExpirationValidationMode.cs rename to aspnetcore-authentication-jwtbearer/src/AspNetCore.Authentication.JwtBearer/DPoP/DPoPProofExpirationMode.cs index e290dcd51..297888f71 100644 --- a/aspnetcore-authentication-jwtbearer/src/AspNetCore.Authentication.JwtBearer/DPoP/ExpirationValidationMode.cs +++ b/aspnetcore-authentication-jwtbearer/src/AspNetCore.Authentication.JwtBearer/DPoP/DPoPProofExpirationMode.cs @@ -6,14 +6,14 @@ namespace Duende.AspNetCore.Authentication.JwtBearer.DPoP; /// /// Controls how the issued at time of proof tokens is validated. /// -public enum ExpirationMode +public enum DPoPProofExpirationMode { /// - /// Validate the time from the server-issued nonce. + /// Validate the expiration time from the server-issued nonce. /// Nonce, /// - /// Validate the time from the iat claim in the proof token. + /// Validate the expiration time from the iat claim in the proof token. /// IssuedAt, /// diff --git a/aspnetcore-authentication-jwtbearer/src/AspNetCore.Authentication.JwtBearer/DPoP/DPoPProofValidator.cs b/aspnetcore-authentication-jwtbearer/src/AspNetCore.Authentication.JwtBearer/DPoP/DPoPProofValidator.cs index 0158302d8..b1aad3c2f 100644 --- a/aspnetcore-authentication-jwtbearer/src/AspNetCore.Authentication.JwtBearer/DPoP/DPoPProofValidator.cs +++ b/aspnetcore-authentication-jwtbearer/src/AspNetCore.Authentication.JwtBearer/DPoP/DPoPProofValidator.cs @@ -384,8 +384,8 @@ internal class DPoPProofValidator : IDPoPProofValidator } // get the largest skew based on how the client's freshness is validated - var validateIat = dPoPOptions.ProofTokenExpirationMode != ExpirationMode.Nonce; - var validateNonce = dPoPOptions.ProofTokenExpirationMode != ExpirationMode.IssuedAt; + var validateIat = dPoPOptions.ProofTokenExpirationMode != DPoPProofExpirationMode.Nonce; + var validateNonce = dPoPOptions.ProofTokenExpirationMode != DPoPProofExpirationMode.IssuedAt; var skew = TimeSpan.Zero; if (validateIat && dPoPOptions.ProofTokenIssuedAtClockSkew > skew) { @@ -412,7 +412,7 @@ internal class DPoPProofValidator : IDPoPProofValidator { var dPoPOptions = OptionsMonitor.Get(context.Scheme); - var validateIat = dPoPOptions.ProofTokenExpirationMode != ExpirationMode.Nonce; + var validateIat = dPoPOptions.ProofTokenExpirationMode != DPoPProofExpirationMode.Nonce; if (validateIat) { ValidateIat(context, result); @@ -422,7 +422,7 @@ internal class DPoPProofValidator : IDPoPProofValidator } } - var validateNonce = dPoPOptions.ProofTokenExpirationMode != ExpirationMode.IssuedAt; + var validateNonce = dPoPOptions.ProofTokenExpirationMode != DPoPProofExpirationMode.IssuedAt; if (validateNonce) { ValidateNonce(context, result); @@ -441,7 +441,7 @@ internal class DPoPProofValidator : IDPoPProofValidator DPoPProofValidationResult result) { // iat is required by an earlier validation, so result.IssuedAt will not be null - if (IsExpired(context, result.IssuedAt!.Value, ExpirationMode.IssuedAt)) + if (IsExpired(context, result.IssuedAt!.Value, DPoPProofExpirationMode.IssuedAt)) { result.SetError("Invalid 'iat' value."); } @@ -473,19 +473,19 @@ internal class DPoPProofValidator : IDPoPProofValidator /// Validates the expiration of the DPoP proof. /// Returns true if the time is beyond the allowed limits, false otherwise. /// - internal bool IsExpired(DPoPProofValidationContext context, long time, ExpirationMode mode) + internal bool IsExpired(DPoPProofValidationContext context, long time, DPoPProofExpirationMode mode) { // It is the responsibility of the caller to call this method with either ExpirationMode.IssuedAt or ExpirationMode.Nonce. // Even if the configured ExpirationMode is Both, we are validating one or the other at this point, and the // caller should make two calls, passing the more specific modes. - if (mode == ExpirationMode.Both) + if (mode == DPoPProofExpirationMode.Both) { throw new ArgumentException("IsExpired should be called with a specific mode (IssuedAt or Nonce), not Both.", nameof(mode)); } var dpopOptions = OptionsMonitor.Get(context.Scheme); var validityDuration = dpopOptions.ProofTokenLifetime; - var skew = mode == ExpirationMode.Nonce ? dpopOptions.ProofTokenNonceClockSkew + var skew = mode == DPoPProofExpirationMode.Nonce ? dpopOptions.ProofTokenNonceClockSkew : dpopOptions.ProofTokenIssuedAtClockSkew; return ExpirationValidator.IsExpired(validityDuration, skew, time); diff --git a/aspnetcore-authentication-jwtbearer/test/AspNetCore.Authentication.JwtBearer.Tests/DPoP/DPoPIntegrationTests.cs b/aspnetcore-authentication-jwtbearer/test/AspNetCore.Authentication.JwtBearer.Tests/DPoP/DPoPIntegrationTests.cs index ce9c9c02c..2b9a0a570 100644 --- a/aspnetcore-authentication-jwtbearer/test/AspNetCore.Authentication.JwtBearer.Tests/DPoP/DPoPIntegrationTests.cs +++ b/aspnetcore-authentication-jwtbearer/test/AspNetCore.Authentication.JwtBearer.Tests/DPoP/DPoPIntegrationTests.cs @@ -162,7 +162,7 @@ public class DPoPIntegrationTests [Fact] public async Task missing_nonce_generates_server_issued_nonce() { - ApiOptions = opt => opt.ProofTokenExpirationMode = ExpirationMode.Nonce; + ApiOptions = opt => opt.ProofTokenExpirationMode = DPoPProofExpirationMode.Nonce; await Initialize(); var token = await LoginAndGetToken(); Api.HttpClient.SetToken("DPoP", token.AccessToken); @@ -203,7 +203,7 @@ public class DPoPIntegrationTests ApiOptions = opt => { - opt.ProofTokenExpirationMode = ExpirationMode.Nonce; + opt.ProofTokenExpirationMode = DPoPProofExpirationMode.Nonce; }; Api.OnConfigureServices += services => { diff --git a/aspnetcore-authentication-jwtbearer/test/AspNetCore.Authentication.JwtBearer.Tests/DPoP/FreshnessTests.cs b/aspnetcore-authentication-jwtbearer/test/AspNetCore.Authentication.JwtBearer.Tests/DPoP/FreshnessTests.cs index 159c0f13a..c60df80a7 100644 --- a/aspnetcore-authentication-jwtbearer/test/AspNetCore.Authentication.JwtBearer.Tests/DPoP/FreshnessTests.cs +++ b/aspnetcore-authentication-jwtbearer/test/AspNetCore.Authentication.JwtBearer.Tests/DPoP/FreshnessTests.cs @@ -133,10 +133,10 @@ public class FreshnessTests : DPoPProofValidatorTestBase } } [Theory] - [InlineData(ClockSkew, 0, ExpirationMode.IssuedAt)] - [InlineData(0, ClockSkew, ExpirationMode.Nonce)] + [InlineData(ClockSkew, 0, DPoPProofExpirationMode.IssuedAt)] + [InlineData(0, ClockSkew, DPoPProofExpirationMode.Nonce)] public void use_client_or_server_clock_skew_depending_on_validation_mode(int clientClockSkew, int serverClockSkew, - ExpirationMode mode) + DPoPProofExpirationMode mode) { Options.ProofTokenIssuedAtClockSkew = TimeSpan.FromSeconds(clientClockSkew); Options.ProofTokenNonceClockSkew = TimeSpan.FromSeconds(serverClockSkew); @@ -182,15 +182,15 @@ public class FreshnessTests : DPoPProofValidatorTestBase } [Theory] - [InlineData(ExpirationMode.IssuedAt)] - [InlineData(ExpirationMode.Both)] - public void validate_iat_when_option_is_set(ExpirationMode mode) + [InlineData(DPoPProofExpirationMode.IssuedAt)] + [InlineData(DPoPProofExpirationMode.Both)] + public void validate_iat_when_option_is_set(DPoPProofExpirationMode mode) { Options.ProofTokenExpirationMode = mode; Options.ProofTokenLifetime = TimeSpan.FromSeconds(ValidFor); Options.ProofTokenIssuedAtClockSkew = TimeSpan.FromSeconds(ClockSkew); Result.IssuedAt = IssuedAt; - if (mode == ExpirationMode.Both) + if (mode == DPoPProofExpirationMode.Both) { Options.ProofTokenNonceClockSkew = TimeSpan.FromSeconds(ClockSkew); Result.Nonce = DataProtector.Protect(IssuedAt.ToString()); @@ -209,15 +209,15 @@ public class FreshnessTests : DPoPProofValidatorTestBase } [Theory] - [InlineData(ExpirationMode.Nonce)] - [InlineData(ExpirationMode.Both)] - public void validate_nonce_when_option_is_set(ExpirationMode mode) + [InlineData(DPoPProofExpirationMode.Nonce)] + [InlineData(DPoPProofExpirationMode.Both)] + public void validate_nonce_when_option_is_set(DPoPProofExpirationMode mode) { Options.ProofTokenExpirationMode = mode; Options.ProofTokenLifetime = TimeSpan.FromSeconds(ValidFor); Options.ProofTokenNonceClockSkew = TimeSpan.FromSeconds(ClockSkew); Result.Nonce = DataProtector.Protect(IssuedAt.ToString()); - if (mode == ExpirationMode.Both) + if (mode == DPoPProofExpirationMode.Both) { Result.IssuedAt = IssuedAt; } diff --git a/aspnetcore-authentication-jwtbearer/test/AspNetCore.Authentication.JwtBearer.Tests/DPoP/ReplayTests.cs b/aspnetcore-authentication-jwtbearer/test/AspNetCore.Authentication.JwtBearer.Tests/DPoP/ReplayTests.cs index 23fc3ccfc..8ff4f3c13 100644 --- a/aspnetcore-authentication-jwtbearer/test/AspNetCore.Authentication.JwtBearer.Tests/DPoP/ReplayTests.cs +++ b/aspnetcore-authentication-jwtbearer/test/AspNetCore.Authentication.JwtBearer.Tests/DPoP/ReplayTests.cs @@ -29,8 +29,8 @@ public class ReplayTests : DPoPProofValidatorTestBase { ReplayCache.ExistsFunc = _ => false; - Options.ProofTokenExpirationMode = (validateIat && validateNonce) ? ExpirationMode.Both - : validateIat ? ExpirationMode.IssuedAt : ExpirationMode.Nonce; + Options.ProofTokenExpirationMode = (validateIat && validateNonce) ? DPoPProofExpirationMode.Both + : validateIat ? DPoPProofExpirationMode.IssuedAt : DPoPProofExpirationMode.Nonce; Options.ProofTokenIssuedAtClockSkew = TimeSpan.FromSeconds(clientClockSkew); Options.ProofTokenNonceClockSkew = TimeSpan.FromSeconds(serverClockSkew); Options.ProofTokenLifetime = TimeSpan.FromSeconds(ValidFor);