@snehal96/unimail
Version:
Unified email fetching & document extraction layer for modern web apps
92 lines (91 loc) • 3.4 kB
JavaScript
import { google } from 'googleapis';
/**
* Google-specific OAuth implementation
*/
export class GoogleOAuthProvider {
/**
* Initialize the Google OAuth flow and generate an authorization URL
*/
async initializeOAuthFlow(options) {
const oauth2Client = this.createOAuth2Client(options);
const authUrl = oauth2Client.generateAuthUrl({
access_type: options.accessType || 'offline',
scope: options.scopes,
prompt: options.prompt || 'consent', // Always request consent to ensure we get a refresh token
});
return {
authUrl,
// Could add a state parameter for security if needed
};
}
/**
* Handle the OAuth callback and exchange the code for tokens
*/
async handleCallback(code, options) {
const oauth2Client = this.createOAuth2Client(options);
try {
const { tokens } = await oauth2Client.getToken(code);
if (!tokens.access_token) {
throw new Error('No access token returned from Google OAuth flow');
}
return {
accessToken: tokens.access_token,
refreshToken: tokens.refresh_token || '',
expiresAt: tokens.expiry_date ? tokens.expiry_date : Date.now() + 3600 * 1000, // Default to 1 hour if no expiry
tokenType: tokens.token_type || 'Bearer',
scope: tokens.scope,
idToken: tokens.id_token || '',
};
}
catch (error) {
throw new Error(`Failed to exchange authorization code: ${error.message}`);
}
}
/**
* Refresh an access token using a refresh token
*/
async refreshToken(refreshToken, options) {
const oauth2Client = this.createOAuth2Client(options);
oauth2Client.setCredentials({
refresh_token: refreshToken
});
try {
const { credentials } = await oauth2Client.refreshAccessToken();
if (!credentials.access_token) {
throw new Error('No access token returned when refreshing token');
}
return {
accessToken: credentials.access_token,
refreshToken: credentials.refresh_token || refreshToken, // Keep existing refresh token if new one not provided
expiresAt: credentials.expiry_date || (Date.now() + 3600 * 1000),
tokenType: credentials.token_type || 'Bearer',
scope: credentials.scope,
idToken: credentials.id_token || '',
};
}
catch (error) {
throw new Error(`Failed to refresh token: ${error.message}`);
}
}
/**
* Revoke a token (can be either an access token or a refresh token)
*/
async revokeToken(token, options) {
const oauth2Client = this.createOAuth2Client(options);
try {
await oauth2Client.revokeToken(token);
return true;
}
catch (error) {
console.error('Error revoking token:', error);
return false;
}
}
/**
* Create an OAuth2Client instance with the provided options
* @private
*/
createOAuth2Client(options) {
return new google.auth.OAuth2(options.clientId, options.clientSecret, options.redirectUri);
}
}