import { refreshAccessToken } from './microsoft-oauth'; import { prisma } from '@/lib/prisma'; import { getRedisClient, KEYS } from '@/lib/redis'; /** * Check if a token is expired or about to expire (within 5 minutes) */ export function isTokenExpired(expiryTimestamp: number): boolean { const fiveMinutesInMs = 5 * 60 * 1000; return Date.now() + fiveMinutesInMs >= expiryTimestamp; } /** * Refresh an access token if it's expired or about to expire */ export async function ensureFreshToken( userId: string, email: string ): Promise<{ accessToken: string; success: boolean }> { try { // Get stored credentials using raw query until Prisma schema is updated const credentials = await prisma.$queryRaw` SELECT "useOAuth", "refreshToken", "accessToken", "tokenExpiry" FROM "MailCredentials" WHERE "userId" = ${userId} AND "email" = ${email} LIMIT 1 `; const credData = Array.isArray(credentials) && credentials.length > 0 ? credentials[0] : null; // If not OAuth or missing refresh token, return failure if (!credData?.useOAuth || !credData.refreshToken) { return { accessToken: '', success: false }; } // If token is still valid, return current token if (credData.tokenExpiry && credData.accessToken && new Date(credData.tokenExpiry) > new Date(Date.now() + 5 * 60 * 1000)) { return { accessToken: credData.accessToken, success: true }; } // Token is expired or about to expire, refresh it console.log(`Refreshing token for user ${userId}, account ${email}`); const tokens = await refreshAccessToken(credData.refreshToken); // Update database with new token information using raw query await prisma.$executeRaw` UPDATE "MailCredentials" SET "accessToken" = ${tokens.access_token}, "refreshToken" = ${tokens.refresh_token || credData.refreshToken}, "tokenExpiry" = ${new Date(Date.now() + (tokens.expires_in * 1000))} WHERE "userId" = ${userId} AND "email" = ${email} `; // Update Redis cache const redis = getRedisClient(); const key = KEYS.CREDENTIALS(userId, email); const credStr = await redis.get(key); if (credStr) { const creds = JSON.parse(credStr); creds.accessToken = tokens.access_token; if (tokens.refresh_token) { creds.refreshToken = tokens.refresh_token; } creds.tokenExpiry = Date.now() + (tokens.expires_in * 1000); await redis.set(key, JSON.stringify(creds), 'EX', 86400); // 24 hours } return { accessToken: tokens.access_token, success: true }; } catch (error) { console.error(`Error refreshing token for user ${userId}:`, error); return { accessToken: '', success: false }; } }