@@ -14,11 +14,11 @@ public class McpApiTokenService(EssentialCSharpWebContext db)
1414
1515 public sealed record ResolvedMcpApiToken ( Guid TokenId , string UserId ) ;
1616
17- public static DateOnly GetDefaultExpiryDate ( DateTime ? utcNow = null )
18- => DateOnly . FromDateTime ( utcNow ?? DateTime . UtcNow ) . AddMonths ( DefaultLifetimeMonths ) ;
17+ public static DateOnly GetDefaultExpiryDate ( DateTime ? utcNowOverride = null )
18+ => DateOnly . FromDateTime ( utcNowOverride ?? DateTime . UtcNow ) . AddMonths ( DefaultLifetimeMonths ) ;
1919
20- public static DateTime GetDefaultExpirationUtc ( DateTime ? utcNow = null )
21- => GetDefaultExpiryDate ( utcNow ) . ToDateTime ( TimeOnly . MaxValue , DateTimeKind . Utc ) ;
20+ public static DateTime GetDefaultExpirationUtc ( DateTime ? utcNowOverride = null )
21+ => GetDefaultExpiryDate ( utcNowOverride ) . ToDateTime ( TimeOnly . MaxValue , DateTimeKind . Utc ) ;
2222
2323 /// <summary>Returns SHA-256 hash of the raw token as a byte array (varbinary(32)).</summary>
2424 public static byte [ ] HashToken ( string rawToken )
@@ -40,10 +40,7 @@ public static string GenerateRawToken()
4040 {
4141 string raw = GenerateRawToken ( ) ;
4242 DateTime createdAt = DateTime . UtcNow ;
43- DateTime maxExpiration = GetDefaultExpirationUtc ( createdAt ) ;
44- DateTime effectiveExpiration = expiresAt ?? maxExpiration ;
45- if ( effectiveExpiration > maxExpiration )
46- throw new ArgumentOutOfRangeException ( nameof ( expiresAt ) , MaxExpiryValidationMessage ) ;
43+ DateTime effectiveExpiration = ResolveExpiration ( expiresAt , createdAt ) ;
4744
4845 var entity = new McpApiToken
4946 {
@@ -58,6 +55,18 @@ public static string GenerateRawToken()
5855 return ( raw , entity ) ;
5956 }
6057
58+ private static DateTime ResolveExpiration ( DateTime ? requestedExpirationUtc , DateTime createdAtUtc )
59+ {
60+ DateTime maxExpiration = GetDefaultExpirationUtc ( createdAtUtc ) ;
61+ if ( requestedExpirationUtc is null )
62+ return maxExpiration ;
63+
64+ if ( requestedExpirationUtc > maxExpiration )
65+ throw new ArgumentOutOfRangeException ( nameof ( requestedExpirationUtc ) , MaxExpiryValidationMessage ) ;
66+
67+ return requestedExpirationUtc . Value ;
68+ }
69+
6170 /// <summary>
6271 /// Revokes a token by ID. Validates ownership to prevent cross-user revocation.
6372 /// Returns false if token not found or user doesn't own it.
0 commit comments