feat(apikeys): optional ExpiresUtc — create + verifier enforcement + sqlite v3 migration (archreview G-2)
ApiKeyRecord/ApiKeyListItem gain a nullable ExpiresUtc (NULL = never expires); ApiKeyFailure gains KeyExpired. ApiKeyVerifier rejects a key whose ExpiresUtc is at-or-before now (inclusive, injected clock), before the secret comparison. CreateKeyAsync gets an expiresUtc overload; rotate preserves existing expiry. SQLite schema bumps to v3: a nullable expires_utc column, added to fresh DBs via CREATE and to existing v1/v2 DBs via an idempotent guarded ALTER — donor v2 gateway-auth.db upgrades in place, no key invalidated. Version 0.1.3 -> 0.1.4 (not yet published; nuget push is human-gated). Consumers (HistorianGateway, mxaccessgw) bump to 0.1.4 to set/enforce expiry. 146 Auth.ApiKeys tests pass.
This commit is contained in:
@@ -8,7 +8,7 @@ public sealed record ApiKeyOptions
|
||||
public bool RunMigrationsOnStartup { get; init; } = true;
|
||||
}
|
||||
|
||||
public enum ApiKeyFailure { MissingOrMalformed, KeyNotFound, KeyRevoked, PepperUnavailable, SecretMismatch }
|
||||
public enum ApiKeyFailure { MissingOrMalformed, KeyNotFound, KeyRevoked, PepperUnavailable, SecretMismatch, KeyExpired }
|
||||
|
||||
public sealed record ApiKeyIdentity(string KeyId, string DisplayName, IReadOnlySet<string> Scopes, object? Constraints);
|
||||
|
||||
@@ -29,7 +29,10 @@ public interface IApiKeyVerifier
|
||||
public sealed record ApiKeyRecord(
|
||||
string KeyId, string KeyPrefix, byte[] SecretHash, string DisplayName,
|
||||
IReadOnlySet<string> Scopes, string? ConstraintsJson,
|
||||
DateTimeOffset CreatedUtc, DateTimeOffset? LastUsedUtc, DateTimeOffset? RevokedUtc);
|
||||
DateTimeOffset CreatedUtc, DateTimeOffset? LastUsedUtc, DateTimeOffset? RevokedUtc,
|
||||
// Optional absolute expiry. NULL = never expires (the default for every key minted before this
|
||||
// field existed, so upgrading a store leaves existing keys valid). Enforced in ApiKeyVerifier.
|
||||
DateTimeOffset? ExpiresUtc = null);
|
||||
|
||||
public interface IApiKeyStore
|
||||
{
|
||||
@@ -46,7 +49,9 @@ public sealed record ApiKeyAuditEntry(string? KeyId, string EventType, string? R
|
||||
/// </summary>
|
||||
public sealed record ApiKeyListItem(
|
||||
string KeyId, string KeyPrefix, string DisplayName, IReadOnlySet<string> Scopes,
|
||||
string? ConstraintsJson, DateTimeOffset CreatedUtc, DateTimeOffset? LastUsedUtc, DateTimeOffset? RevokedUtc);
|
||||
string? ConstraintsJson, DateTimeOffset CreatedUtc, DateTimeOffset? LastUsedUtc, DateTimeOffset? RevokedUtc,
|
||||
// Optional absolute expiry (NULL = never expires); surfaced so admins can see/alert on expiry.
|
||||
DateTimeOffset? ExpiresUtc = null);
|
||||
|
||||
public interface IApiKeyAdminStore
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user