Skip to content

Commit 68eb37b

Browse files
Tighten MCP expiry tests and page model flow
Agent-Logs-Url: https://github.com/IntelliTect/EssentialCSharp.Web/sessions/29b86c94-db59-4104-8285-197ae2428813 Co-authored-by: BenjaminMichaelis <22186029+BenjaminMichaelis@users.noreply.github.com>
1 parent c42156a commit 68eb37b

3 files changed

Lines changed: 28 additions & 7 deletions

File tree

EssentialCSharp.Web.Tests/McpApiTokenServiceTests.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,21 @@ await Assert.That(entity.ExpiresAt!.Value)
2323
.IsEqualTo(McpApiTokenService.GetDefaultExpirationUtc(entity.CreatedAt));
2424
}
2525

26+
[Test]
27+
public async Task CreateTokenAsync_WithExpiryWithinSixMonths_UsesRequestedExpiry()
28+
{
29+
string userId = await McpTestHelper.CreateUserAsync(factory, "mcp-custom-expiry");
30+
31+
using var scope = factory.Services.CreateScope();
32+
var tokenService = scope.ServiceProvider.GetRequiredService<McpApiTokenService>();
33+
DateTime requestedExpiry = DateTime.UtcNow.AddMonths(3);
34+
35+
(_, var entity) = await tokenService.CreateTokenAsync(userId, "custom-expiry", requestedExpiry);
36+
37+
await Assert.That(entity.ExpiresAt).IsNotNull();
38+
await Assert.That(entity.ExpiresAt!.Value).IsEqualTo(requestedExpiry);
39+
}
40+
2641
[Test]
2742
public async Task CreateTokenAsync_WithExpiryBeyondSixMonths_Throws()
2843
{

EssentialCSharp.Web/Areas/Identity/Pages/Account/Manage/McpAccess.cshtml.cs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ public class McpAccessModel(
3333
public async Task<IActionResult> OnGetAsync()
3434
{
3535
DisableCaching();
36-
InitializeExpiryDefaults();
36+
InitializeExpiryBounds();
37+
ApplyDefaultExpiryIfMissing();
3738
string? userId = userManager.GetUserId(User);
3839
if (userId is null) return Challenge();
3940
UserTokens = await tokenService.GetUserTokensAsync(userId);
@@ -43,7 +44,8 @@ public async Task<IActionResult> OnGetAsync()
4344
public async Task<IActionResult> OnPostCreateAsync()
4445
{
4546
DisableCaching();
46-
InitializeExpiryDefaults();
47+
InitializeExpiryBounds();
48+
ApplyDefaultExpiryIfMissing();
4749
string? userId = userManager.GetUserId(User);
4850
if (userId is null) return Challenge();
4951

@@ -95,9 +97,13 @@ private void DisableCaching()
9597
Response.Headers.Expires = "0";
9698
}
9799

98-
private void InitializeExpiryDefaults()
100+
private void InitializeExpiryBounds()
99101
{
100102
MaxExpiresOn = McpApiTokenService.GetDefaultExpiryDate();
103+
}
104+
105+
private void ApplyDefaultExpiryIfMissing()
106+
{
101107
ExpiresOn ??= MaxExpiresOn;
102108
}
103109
}

EssentialCSharp.Web/Services/McpApiTokenService.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -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? utcNowOverride = null)
18-
=> DateOnly.FromDateTime(utcNowOverride ?? DateTime.UtcNow).AddMonths(DefaultLifetimeMonths);
17+
public static DateOnly GetDefaultExpiryDate(DateTime? referenceTimeUtc = null)
18+
=> DateOnly.FromDateTime(referenceTimeUtc ?? DateTime.UtcNow).AddMonths(DefaultLifetimeMonths);
1919

20-
public static DateTime GetDefaultExpirationUtc(DateTime? utcNowOverride = null)
21-
=> GetDefaultExpiryDate(utcNowOverride).ToDateTime(TimeOnly.MaxValue, DateTimeKind.Utc);
20+
public static DateTime GetDefaultExpirationUtc(DateTime? referenceTimeUtc = null)
21+
=> GetDefaultExpiryDate(referenceTimeUtc).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)

0 commit comments

Comments
 (0)