import axios from 'axios'; // Microsoft OAuth URLs const MICROSOFT_AUTHORIZE_URL = 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize'; const MICROSOFT_TOKEN_URL = 'https://login.microsoftonline.com/common/oauth2/v2.0/token'; // Client configuration from environment variables const clientId = process.env.MICROSOFT_CLIENT_ID; const clientSecret = process.env.MICROSOFT_CLIENT_SECRET; const redirectUri = process.env.MICROSOFT_REDIRECT_URI; // Required scopes for IMAP and SMTP access const REQUIRED_SCOPES = [ 'offline_access', 'https://outlook.office.com/IMAP.AccessAsUser.All', 'https://outlook.office.com/SMTP.Send' ].join(' '); /** * Generates the authorization URL for Microsoft OAuth */ export function getMicrosoftAuthUrl(state: string): string { const params = new URLSearchParams({ client_id: clientId!, response_type: 'code', redirect_uri: redirectUri!, scope: REQUIRED_SCOPES, state, response_mode: 'query' }); return `${MICROSOFT_AUTHORIZE_URL}?${params.toString()}`; } /** * Exchange authorization code for tokens */ export async function exchangeCodeForTokens(code: string): Promise<{ access_token: string; refresh_token: string; expires_in: number; }> { const params = new URLSearchParams({ client_id: clientId!, client_secret: clientSecret!, code, redirect_uri: redirectUri!, grant_type: 'authorization_code' }); try { const response = await axios.post(MICROSOFT_TOKEN_URL, params.toString(), { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }); return { access_token: response.data.access_token, refresh_token: response.data.refresh_token, expires_in: response.data.expires_in }; } catch (error) { console.error('Error exchanging code for tokens:', error); throw new Error('Failed to exchange authorization code for tokens'); } } /** * Refresh an access token using a refresh token */ export async function refreshAccessToken(refreshToken: string): Promise<{ access_token: string; refresh_token?: string; expires_in: number; }> { const params = new URLSearchParams({ client_id: clientId!, client_secret: clientSecret!, refresh_token: refreshToken, grant_type: 'refresh_token', scope: REQUIRED_SCOPES }); try { const response = await axios.post(MICROSOFT_TOKEN_URL, params.toString(), { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }); return { access_token: response.data.access_token, refresh_token: response.data.refresh_token, expires_in: response.data.expires_in }; } catch (error) { console.error('Error refreshing token:', error); throw new Error('Failed to refresh access token'); } } /** * Create special XOAUTH2 string for IMAP authentication */ export function createXOAuth2Token(email: string, accessToken: string): string { const auth = `user=${email}\x01auth=Bearer ${accessToken}\x01\x01`; return Buffer.from(auth).toString('base64'); }