Files

80 lines
3.2 KiB
JavaScript

/***********************************************************************************************************************************************************************
* File Name: get_gmail_refresh_token.js
* Type of Program: One-time setup script (run locally, not deployed)
* Description: Mints a long-lived Gmail API refresh token for the sending mailbox
* (EMAIL_FROM, e.g. services.philpro@gmail.com), so services/email.service.js
* can send mail over HTTPS via the Gmail API instead of SMTP.
*
* Prerequisites (one-time, in Google Cloud Console — same project as GOOGLE_CLIENT_ID):
* 1. APIs & Services → Library → enable "Gmail API".
* 2. APIs & Services → Credentials → open the OAuth client used for GOOGLE_CLIENT_ID
* → Authorized redirect URIs → add: http://localhost:5555/oauth2callback
* (You can remove this URI again after this script succeeds.)
*
* Usage:
* node scripts/get_gmail_refresh_token.js
* → prints an auth URL. Open it in a browser, sign in AS the EMAIL_FROM mailbox,
* approve the "Send email on your behalf" consent screen.
* → the script prints GMAIL_REFRESH_TOKEN — copy it into Render's env vars.
*
* Author: Kenneth Obsequio (@lash0000)
* Date Created: Jul. 14, 2026
***********************************************************************************************************************************************************************/
'use strict';
require('dotenv').config();
const http = require('http');
const { OAuth2Client } = require('google-auth-library');
const REDIRECT_URI = 'http://localhost:5555/oauth2callback';
const SCOPE = 'https://www.googleapis.com/auth/gmail.send';
const clientId = process.env.GOOGLE_CLIENT_ID;
const clientSecret = process.env.GOOGLE_CLIENT_SECRET;
if (!clientId || !clientSecret) {
console.error('Missing GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRET in .env');
process.exit(1);
}
const client = new OAuth2Client(clientId, clientSecret, REDIRECT_URI);
const authUrl = client.generateAuthUrl({
access_type: 'offline',
prompt: 'consent', // forces a refresh_token even if this account consented before
scope: [SCOPE],
});
console.log('\nOpen this URL, sign in AS the EMAIL_FROM mailbox, and approve access:\n');
console.log(authUrl, '\n');
console.log(`Waiting for the redirect on ${REDIRECT_URI} ...\n`);
const server = http.createServer(async (req, res) => {
if (!req.url.startsWith('/oauth2callback')) {
res.writeHead(404).end();
return;
}
const code = new URL(req.url, REDIRECT_URI).searchParams.get('code');
if (!code) {
res.writeHead(400).end('Missing ?code — check the URL Google redirected you to.');
return;
}
try {
const { tokens } = await client.getToken(code);
res.writeHead(200, { 'Content-Type': 'text/plain' }).end('Done — check your terminal.');
console.log('GMAIL_REFRESH_TOKEN=' + tokens.refresh_token, '\n');
console.log('Copy the line above into Render\'s environment variables, then redeploy.');
} catch (err) {
res.writeHead(500).end('Token exchange failed — see terminal.');
console.error('Token exchange failed:', err.response?.data || err.message);
} finally {
server.close();
}
});
server.listen(5555);