// // OAuthTokenStorage.swift // FantasyWatch // // Created by Claude Code // import Foundation actor OAuthTokenStorage { private let ubiquitousStore = NSUbiquitousKeyValueStore.default private func accessTokenKey(for userID: String) -> String { "com.fantasyhockey.user.\(userID).yahoo.accessToken" } private func refreshTokenKey(for userID: String) -> String { "com.fantasyhockey.user.\(userID).yahoo.refreshToken" } private func tokenExpiryKey(for userID: String) -> String { "com.fantasyhockey.user.\(userID).yahoo.tokenExpiry" } func saveTokenPair(_ tokenPair: TokenPair, for userID: String) { ubiquitousStore.set(tokenPair.accessToken, forKey: accessTokenKey(for: userID)) ubiquitousStore.set(tokenPair.refreshToken, forKey: refreshTokenKey(for: userID)) ubiquitousStore.set(tokenPair.expiryDate.timeIntervalSince1970, forKey: tokenExpiryKey(for: userID)) ubiquitousStore.synchronize() } func getAccessToken(for userID: String) -> String? { ubiquitousStore.string(forKey: accessTokenKey(for: userID)) } func getRefreshToken(for userID: String) -> String? { ubiquitousStore.string(forKey: refreshTokenKey(for: userID)) } func getTokenExpiry(for userID: String) -> Date? { let timestamp = ubiquitousStore.double(forKey: tokenExpiryKey(for: userID)) guard timestamp > 0 else { return nil } return Date(timeIntervalSince1970: timestamp) } func isTokenValid(for userID: String) -> Bool { guard let expiryDate = getTokenExpiry(for: userID) else { return false } return expiryDate > Date().addingTimeInterval(60) } func clearTokens(for userID: String) { ubiquitousStore.removeObject(forKey: accessTokenKey(for: userID)) ubiquitousStore.removeObject(forKey: refreshTokenKey(for: userID)) ubiquitousStore.removeObject(forKey: tokenExpiryKey(for: userID)) ubiquitousStore.synchronize() } }