I'm making a plugin that sends mail in trapi cms using nodemailer and google's oauth2, however my tokens automatically expire after 1 hour. I am trying several ways but my code still not working. Here is my code:
const nodemailer = require("nodemailer");
const { google } = require("googleapis");
const OAuth2 = google.auth.OAuth2;
const oauth2Client = new OAuth2(
`"${process.env.CLIENT_ID }"`,
`"${process.env.CLIENT_SECRET}"`,
"https://developers.google.com/oauthplayground",
);
// oauth2Client.setCredentials({
// refresh_token: `"${process.env.REFRESH_TOKEN }"`,
// });
// const accessToken = oauth2Client.getAccessToken()
module.exports = ({ env }) => ({
// ...
email: {
provider: env(`${process.env.REACT_APP_EMAIL_PROVIDER}`),
providerOptions: {
host: env("EMAIL_SMTP_HOST", "smtp.gmail.com"),
port: env("EMAIL_SMTP_PORT", 587),
auth: {
type: "OAuth2",
user: "hotrodhv58#gmail.com",
clientId: `"${process.env.CLIENT_ID }"`,
clientSecret: `"${process.env.CLIENT_SECRET}"`,
refreshToken: `"${process.env.REFRESH_TOKEN}"`,
accessToken: `"${process.env.ACCESS_TOKEN}"`,
},
},
settings: {
defaultFrom: env(`${process.env.REACT_APP_EMAIL_ADDRESS_FROM}`),
defaultReplyTo: env(`${process.env.REACT_APP_EMAIL_ADDRESS_REPLY}`),
},
},
// ...
});
The error I received:
Error sending email to xxxxssss#gmail.com {"code":"EAUTH","command":"AUTH XOAUTH2"}
If I leave Async Await in the module, I will receive an error:
{"Errno":-4078, "code": "Esocket", "Syncall": "Connect", "Address":"127.0.0.1", "Port": 587, "Command": "Conn"}}
What do I need to do to make them work. Hope to get help from everyone!
Related
im really stuck here. i already try a couple hours to solve this. on development, nodemailer works for sending email, like verification or reset password. but when i deploy or on production mode using vercel, nodemailer not work. can somebody help me? please? i really stuck here. thank you. here's the code
const nodemailer = require("nodemailer");
const fs = require("fs");
const mustache = require("mustache");
const path = require("path");
const gmail = require("../config/gmail");
module.exports = {
sendMail: (data) => {
// eslint-disable-next-line no-new
new Promise((resolve, reject) => {
const transporter = nodemailer.createTransport({
service: "gmail",
host: "smtp.gmail.com",
port: 465,
auth: {
type: "OAuth2",
user: process.env.MAIL_USERNAME,
pass: process.env.APP_PASSWORD,
clientId: gmail.clientId,
clientSecret: gmail.clientSecret,
refreshToken: gmail.refreshToken,
accessToken: gmail.accessToken,
},
secure: "true",
});
const filePath = path.join(
__dirname,
`../../src/templates/email/${data.template}`
);
const fileTemplate = fs.readFileSync(filePath, "utf8");
const mailOptions = {
from: '"Event Organizing" <arkawebdev1#gmail.com>',
to: data.to,
subject: data.subject,
html: mustache.render(fileTemplate, { ...data }),
};
transporter.sendMail(mailOptions, (error, result) => {
if (error) {
reject(error);
} else {
resolve(result);
}
});
});
},
};
I was going through the next-auth documentation but didn't find any mention of connecting to custom configured Redis without the use of Upstash for a persistent session store.
My use case is straightforward. I am using Nginx as a load balancer between multiple nodes for my nextJS application and I would like to persist the session if in case the user logs in and refreshes the page as Nginx switches between nodes.
For e.g My Nginx config
server {
listen 80;
server_name _;
location / {
proxy_pass http://backend;
}
}
upstream backend {
ip_hash;
server <nextjs_app_ip_1>:8000;
server <nextjs_app_ip_2>:8000;
}
As you can see from the example Nginx config, there are multiple upstream server pointers here that require user session persistence.
I am using the credentials provider of next-auth as I have a Django-based auth system already available.
I did see the implementation of the next-auth adapter with Upstash. However, I have my own custom server running with Redis.
I tried connecting to Redis using ioredis which works fine as it is connected. However, I am not sure how can I use Redis here with next-auth to persist session and validate at the same time?
For e.g In express, you have a session store which you can pass your Redis Client with and it should automatically take care of persistence. Is there anything I can do to replicate the same behavior in my case?
For e.g In Express
App.use(session({
store: new RedisStore({ client: redisClient }),
secret: 'secret$%^134',
resave: false,
saveUninitialized: false,
cookie: {
secure: false, // if true only transmit cookie over https
httpOnly: false, // if true prevent client side JS from reading the cookie
maxAge: 1000 * 60 * 10 // session max age in miliseconds
}
}))
My Code:
import CredentialsProvider from "next-auth/providers/credentials";
import {UpstashRedisAdapter} from "#next-auth/upstash-redis-adapter";
import Redis from 'ioredis';
const redis = new Redis(process.env.REDIS_URL); //points to my custom redis docker container
export const authOptions = {
providers: [CredentialsProvider({
name: 'auth',
credentials: {
email: {
label: 'email',
type: 'text',
placeholder: 'jsmith#example.com'
},
password: {
label: 'Password',
type: 'password'
}
},
async authorize(credentials, req) {
const payload = {
email: credentials.email,
password: credentials.password
};
const res = await fetch(`my-auth-system-url`, {
method: 'POST',
body: JSON.stringify(payload),
headers: {
'Content-Type': 'application/json'
}
});
const user = await res.json();
console.log("user", user);
if (!res.ok) {
throw new Error(user.exception);
}
// If no error and we have user data, return it
if (res.ok && user) {
return user;
}
// Return null if user data could not be retrieved
return null;
}
})],
adapter: UpstashRedisAdapter(redis),
pages: {
signIn: '/login'
},
jwt: {
secret: process.env.SECRET,
encryption: true
},
callbacks: {
jwt: async({token, user}) => {
user && (token.user = user)
return token
},
session: async({session, token}) => {
session.user = token.user
return session
},
async redirect({baseUrl}) {
return `${baseUrl}/`
}
},
session: {
strategy: "jwt",
maxAge: 3000
},
secret: process.env.SECRET,
debug: true
}
export default NextAuth(authOptions)
Thank you so much for the help.
const nodeMailer = require("nodemailer");
const { google } = require('googleapis');
const oAuth2Client = new google.auth.OAuth2(
process.env.CLIENT_ID,
process.env.CLEINT_SECRET,
process.env.REDIRECT_URI
);
oAuth2Client.setCredentials({ refresh_token: process.env.REFRESH_TOKEN });
const sendEmail = async (options) => {
const accessToken = await oAuth2Client.getAccessToken();
const transporter = nodeMailer.createTransport({
host: process.env.SMTP_HOST,
port: process.env.SMTP_PORT,
secure: true,
service: process.env.SMTP_SERVICE,
auth: {
type: 'OAuth2',
user: process.env.SMTP_MAIL,
clientId: process.env.CLIENT_ID,
clientSecret: process.env.CLEINT_SECRET,
refreshToken: process.env.REFRESH_TOKEN,
accessToken: accessToken,
},
});
const mailOptions = {
from: process.env.SMPT_MAIL,
to: options.email,
subject: options.subject,
text: options.message,
};
await transporter.sendMail(mailOptions,function(err,info){
if(err){
console.log(err)
} else {
console.log('success')
}
});
};
module.exports = sendEmail;
when it says no refresh token , but each time when new req is made oAuth2Client creates new token and that is being passed into setting the credentials for refresh token, but ultimately the transporter is unable to process the mailing part.
In https://developers.google.com/oauthplayground : i've set API as "https://mail.google.com" and "Use your own OAuth credentials"
also the temp gmail account which i created for mailing purpose i activated Less secure app access to "On" mode.
can anyone help me to pass this error?
reg
const { google } = require('googleapis');
require('dotenv').config();
const nodemailer = require('nodemailer');
const oAuth2Client = new google.auth.OAuth2(
process.env.CLIENT_ID,
process.env.CLIENT_SECRET,
process.env.REDIRECT_URI
);
console.log(process.env.CLIENT_ID)
console.log(process.env.CLIENT_SECRET)
console.log(process.env.REDIRECT_URI)
console.log(process.env.REFRESH_TOKEN)
oAuth2Client.setCredentials({ refresh_token: process.env.REFRESH_TOKEN});
const accessToken = await oAuth2Client.getAccessToken();
const transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
type: 'OAuth2',
user: process.env.ADDRESS,
clientId: process.env.CLIENT_ID,
clientSecret: process.env.CLIENT_SECRET,
refreshToken: process.env.REFRESH_TOKEN,
accessToken: accessToken,
},
});
Main error is that process.env.anything gives undefined, i do have values with the same names as well
I have been working with this issue in many ways, but now i atleast got nodemailer seemingly to work no issue, but now my dotenv isnt working suddenly
Issue was that you cant name a >.env file
I am using couchDB and when ever i try to create views it is giving me this error
at processTicksAndRejections (internal/process/task_queues.js:97:5) {
code: 'EUNAUTHORIZED',
body: {
error: 'unauthorized',
reason: 'You are not a db or server admin.'
}
}
I am using Node-Couchdb and i am passing the credentials like this
const NodeCouchDb = require('node-couchdb')
require("dotenv-flow").config();
const couch = new NodeCouchDb({
host: process.env.DB_HOST,
protocol: process.env.DB_PROTOCOL,
port: process.env.DB_PORT
})
const couchAuth = new NodeCouchDb({
auth: {
user: process.env.DB_USER_NAME,
pass: process.env.PASSWORD
}
})
module.exports = {
couch
}
Your code is creating two instances of NodeCouchDB, couch and couchAuth where
couch points to server specified by envars without credentials
couchAuth points to the default server (127.0.0.1:5984) with credentials specified by envars
You need to combine parameters, for example
const NodeCouchDb = require("node-couchdb");
const couch = new NodeCouchDb({
host: process.env.DB_HOST,
protocol: process.env.DB_PROTOCOL,
port: process.env.DB_PORT,
auth: {
user: process.env.DB_USER_NAME,
pass: process.env.PASSWORD,
},
});
module.exports = {
couch
};