namespace IronServices.Client; /// /// Interface for storing authentication tokens. /// Implement this for platform-specific secure storage (e.g., MAUI SecureStorage, Windows Credential Manager). /// public interface ITokenStorage { /// /// Save the session token. /// Task SaveTokenAsync(string token, DateTime? expiresAt); /// /// Get the stored session token. /// Task<(string? Token, DateTime? ExpiresAt)> GetTokenAsync(); /// /// Clear the stored token. /// Task ClearTokenAsync(); } /// /// In-memory token storage (not persisted across app restarts). /// public class InMemoryTokenStorage : ITokenStorage { private string? _token; private DateTime? _expiresAt; public Task SaveTokenAsync(string token, DateTime? expiresAt) { _token = token; _expiresAt = expiresAt; return Task.CompletedTask; } public Task<(string? Token, DateTime? ExpiresAt)> GetTokenAsync() { return Task.FromResult((_token, _expiresAt)); } public Task ClearTokenAsync() { _token = null; _expiresAt = null; return Task.CompletedTask; } } /// /// File-based token storage (for console apps, testing). /// public class FileTokenStorage : ITokenStorage { private readonly string _filePath; public FileTokenStorage(string? filePath = null) { _filePath = filePath ?? Path.Combine( Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "IronServices", "session.json"); } public async Task SaveTokenAsync(string token, DateTime? expiresAt) { var directory = Path.GetDirectoryName(_filePath); if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory)) { Directory.CreateDirectory(directory); } var data = new { token, expiresAt = expiresAt?.ToString("O") }; var json = System.Text.Json.JsonSerializer.Serialize(data); await File.WriteAllTextAsync(_filePath, json); } public async Task<(string? Token, DateTime? ExpiresAt)> GetTokenAsync() { if (!File.Exists(_filePath)) { return (null, null); } try { var json = await File.ReadAllTextAsync(_filePath); var data = System.Text.Json.JsonSerializer.Deserialize(json); DateTime? expiresAt = null; if (!string.IsNullOrEmpty(data?.ExpiresAt)) { expiresAt = DateTime.Parse(data.ExpiresAt, null, System.Globalization.DateTimeStyles.RoundtripKind); } return (data?.Token, expiresAt); } catch { return (null, null); } } public Task ClearTokenAsync() { if (File.Exists(_filePath)) { File.Delete(_filePath); } return Task.CompletedTask; } private class TokenData { public string? Token { get; set; } public string? ExpiresAt { get; set; } } }