using System.Collections.Concurrent; using MealPlan.Api.Models; namespace MealPlan.Api.Services; /// /// Thread-safe in-memory refresh token store registered as a singleton. /// Note: tokens live only for the lifetime of the process. For multi-instance /// deployments this should be swapped for a shared store (e.g. Redis), but it /// satisfies the "do not modify the database" constraint of this project. /// public class InMemoryRefreshTokenStore : IRefreshTokenStore { private readonly ConcurrentDictionary _tokens = new(); public void Add(RefreshToken token) => _tokens[token.Token] = token; public RefreshToken? Get(string token) => _tokens.TryGetValue(token, out var found) ? found : null; public RefreshToken? Revoke(string token) { if (!_tokens.TryGetValue(token, out var found)) { return null; } var wasActive = found.IsActive; found.IsRevoked = true; return wasActive ? found : null; } public void RemoveExpired() { foreach (var kvp in _tokens) { if (kvp.Value.IsRevoked || DateTime.UtcNow >= kvp.Value.ExpiresAtUtc) { _tokens.TryRemove(kvp.Key, out _); } } } }