Spaces:
Sleeping
Sleeping
| // src/auth.ts | |
| import { google } from 'googleapis'; | |
| import { OAuth2Client } from 'google-auth-library'; | |
| import * as fs from 'fs/promises'; | |
| import * as path from 'path'; | |
| import * as readline from 'readline/promises'; | |
| import { fileURLToPath } from 'url'; | |
| // --- Calculate paths relative to this script file (ESM way) --- | |
| const __filename = fileURLToPath(import.meta.url); | |
| const __dirname = path.dirname(__filename); | |
| const projectRootDir = path.resolve(__dirname, '..'); | |
| const TOKEN_PATH = path.join(projectRootDir, 'token.json'); | |
| const CREDENTIALS_PATH = path.join(projectRootDir, 'credentials.json'); | |
| // --- End of path calculation --- | |
| const SCOPES = [ | |
| 'https://www.googleapis.com/auth/documents', | |
| 'https://www.googleapis.com/auth/drive.file' // Or scope used in Step 1 | |
| ]; | |
| async function loadSavedCredentialsIfExist(): Promise<OAuth2Client | null> { | |
| try { | |
| const content = await fs.readFile(TOKEN_PATH); | |
| const credentials = JSON.parse(content.toString()); | |
| const { client_secret, client_id, redirect_uris } = await loadClientSecrets(); | |
| const client = new google.auth.OAuth2(client_id, client_secret, redirect_uris?.[0]); | |
| client.setCredentials(credentials); | |
| return client; | |
| } catch (err) { | |
| return null; | |
| } | |
| } | |
| async function loadClientSecrets() { | |
| const content = await fs.readFile(CREDENTIALS_PATH); | |
| const keys = JSON.parse(content.toString()); | |
| const key = keys.installed || keys.web; | |
| if (!key) throw new Error("Could not find client secrets in credentials.json."); | |
| return { | |
| client_id: key.client_id, | |
| client_secret: key.client_secret, | |
| redirect_uris: key.redirect_uris | |
| }; | |
| } | |
| async function saveCredentials(client: OAuth2Client): Promise<void> { | |
| const { client_secret, client_id } = await loadClientSecrets(); | |
| const payload = JSON.stringify({ | |
| type: 'authorized_user', | |
| client_id: client_id, | |
| client_secret: client_secret, | |
| refresh_token: client.credentials.refresh_token, | |
| }); | |
| await fs.writeFile(TOKEN_PATH, payload); | |
| console.error('Token stored to', TOKEN_PATH); | |
| } | |
| async function authenticate(): Promise<OAuth2Client> { | |
| const { client_secret, client_id, redirect_uris } = await loadClientSecrets(); | |
| const oAuth2Client = new google.auth.OAuth2(client_id, client_secret, redirect_uris?.[0]); | |
| const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); | |
| const authorizeUrl = oAuth2Client.generateAuthUrl({ | |
| access_type: 'offline', | |
| scope: SCOPES.join(' '), | |
| }); | |
| console.error('Authorize this app by visiting this url:', authorizeUrl); | |
| const code = await rl.question('Enter the code from that page here: '); | |
| rl.close(); | |
| try { | |
| const { tokens } = await oAuth2Client.getToken(code); | |
| oAuth2Client.setCredentials(tokens); | |
| if (tokens.refresh_token) { // Save only if we got a refresh token | |
| await saveCredentials(oAuth2Client); | |
| } else { | |
| console.error("Did not receive refresh token. Token might expire."); | |
| } | |
| console.error('Authentication successful!'); | |
| return oAuth2Client; | |
| } catch (err) { | |
| console.error('Error retrieving access token', err); | |
| throw new Error('Authentication failed'); | |
| } | |
| } | |
| export async function authorize(): Promise<OAuth2Client> { | |
| let client = await loadSavedCredentialsIfExist(); | |
| if (client) { | |
| // Optional: Add token refresh logic here if needed, though library often handles it. | |
| console.error('Using saved credentials.'); | |
| return client; | |
| } | |
| console.error('Starting authentication flow...'); | |
| client = await authenticate(); | |
| return client; | |
| } |