I've been trying to use the node package Twitter to stream, and then process the tweets for further use but am, apparently, already failing at authorization because every time I do try to access the stream I get a 401 or 403 response from the server.
I've tried these two ways of authenticating
const Twitter = require('twitter');
const twitterAPIKey = process.env.TWITTER_API_KEY;
const twitterAPIKeySecret = process.env.TWITTER_API_KEY_SECRET;
const twitterAccessToken = process.env.TWITTER_ACCESS_TOKEN;
const twitterAccessTokenSecret = process.env.TWITTER_ACCESS_TOKEN_SECRET;
const bearerToken = process.env.TWITTER_BEARER_TOKEN;
const users = [
'2898008473'
]
const twitterClient = new Twitter({
consumer_key: twitterAPIKey,
consumer_secret: twitterAPIKeySecret,
bearer_token: bearerToken
});
const stream = twitterClient.stream('statuses/filter', {follow: users}, function(stream) {
stream.on('data', function (data) {
console.log(data);
});
stream.on('error', function (error) {
console.log(error);
});
});
This is the current iteration of my code, previously I've also tried running the authentication as follows
const twitterClient = new Twitter({
consumer_key: twitterAPIKey,
consumer_secret: twitterAPIKeySecret,
access_token: twitterAccessToken,
access_token_secret: twitterAccessTokenSecret
});
With no success so far. My project has been approved for elevated access and I even generated new keys after that just to make sure everything would work correctly.
The error is probably not in your Auth code.
If this app was created after mid-2022 you no longer have access to v1.1 statuses/filter (regardless of elevated access) as it is being retired. Use the V2 filtered stream instead.
My application uses the Zoom API with OAuth.
The process is well put in the zoom developer docs and I followed them
I created a zoom app in the developer's account and got the clientID and clientSecret.
First we need to get the Authorization code from "https://zoom.us/oauth/authorize". With this code we can get the access token from "https://zoom.us/oauth/token". Pretty straight forward. I tried it on Postman and all the APIs work.
My JS code below doesn't work and keeps failing to do this task.
const express = require('express');
const axios = require('axios');
let token = null;
const app = express();
const clientId = 'ADqR4l7KTfMmXXXXXXXX';
const clientSecret = 'mhVytefIFS4fSqQ3XXXXXXXXXX';
const redirectURL = 'http://localhost:3000/oauth-callback'
app.get('/', (req, res) => {
res.redirect(`https://zoom.us/oauth/authorize?response_type=code&client_id=${clientId}&redirect_uri=${redirectURL}`);
});
app.get('/oauth-callback', (req, res) => {
const body = {
client_id: clientId,
client_secret: clientSecret,
code: req.query.code
};
const opts = { headers: { accept: 'application/json' } };
axios.post(`https://zoom.us/oauth/token`, body, opts).
then(res => res.data['access_token']).
then(_token => {
console.log('My token:', token);
token = _token;
res.json({ ok: 1 });
}).
catch(err => res.status(500).json({ message: err.message }));
});
app.listen(3000);
console.log('App listening on port 3000');
zoom dev acct:
zoom dev account
Error message:
Error message
How can I get the access token? Please help me find my errors in the code.
I am trying to get the data my nodeJS server is receiving from a form on the front end to send that data to my email. I have tried to use nodemailer and haven't succeeded much. Can someone tell me perhaps what I am doing wrong with the following code?
const express = require("express");
const app = express();
const nodemailer = require("nodemailer");
var smtpTransport = require("nodemailer-smtp-transport");
const PORT = process.env.PORT || 4000;
app.use(express.static(__dirname + "/front-end"));
app.get("/", (req, resp) => {
resp.sendFile(__dirname + "/front-end/index.html");
});
app.use(express.json());
app.use(express.urlencoded());
app.post("/formData", (req, resp) => {
const data = req.body;
var transport = nodemailer.createTransport(
smtpTransport({
service: "Gmail",
auth: {
user: "user#gmail.com",
pass: "123456",
},
})
);
transport.sendMail(
{
//email options
from: "Sender Name <email#gmail.com>",
to: "Receiver Name <receiver#email.com>", // receiver
subject: "Emailing with nodemailer", // subject
html: data, // body (var data which we've declared)
},
function (error, response) {
//callback
if (error) {
console.log(error);
} else {
console.log("Message sent:");
resp.send("success!");
}
transport.close();
}
);
});
app.listen(PORT, () => {
console.log(`server running on port ${PORT}`);
});
Your code, at a glance, looks fine to me. I think the problem is (since you’re not stating you have set that up), that you want to send email with GMail. If you want to send email from your own app or web service via Gmail, you should set up a project in the Google Cloud Platform. Read more here.
Alternatively, you could use a service like Postmark, which you can configure to send emails via a domain that you own. There’s a free trial. Mailgun is a similar service. (I’m not affiliated to either).
I am logging users in via their domain Google accounts using passport.js. This works great, but now I need to give this application access to a few Google API's (drive, sheets, etc).
When a user logs in, a message appears in the logs, that makes it seem like passport has all the required info:
info: [06/Jun/2019:21:24:37 +0000] "302 GET /auth/callback?code=** USER ACCESS TOKEN HERE **&scope=email%20profile%20https://www.googleapis.com/auth/drive.file%20https://www.googleapis.com/auth/spreadsheets%20https://www.googleapis.com/auth/userinfo.email%20https://www.googleapis.com/auth/userinfo.profile%20https://www.googleapis.com/auth/drive HTTP/1.1" [46]
This is achieved by passing the appended scopes via passport.authenticate(), which presents the user with the "Grant access to these things on your Google account to this app?" screen :
//Initial auth call to Google
router.get('/',
passport.authenticate('google', {
hd: 'edmonds.wednet.edu',
scope: [
'email',
'profile',
'https://www.googleapis.com/auth/drive',
'https://www.googleapis.com/auth/drive.file',
'https://www.googleapis.com/auth/spreadsheets'
],
prompt: 'select_account'
})
);
However, when I go and try to call an API with something like:
const {google} = require('googleapis');
const sheets = google.sheets({version: 'v4', auth});
router.post('/gsCreate', function(req,res,next){
sheets.spreadsheets.create({
// Details here.....
});
});
I get nothing but errors (the current one is debug: authClient.request is not a function)
My question is: Is it possible for me to use a setup like this, asking the user to log in and grant permissions once, and then somehow save that to their user session via passport?
I had the same question, but I was able to access Google Gmail API functionalities along with Passport.js user authentication by specifying 'scopes' using the following process.
First, create a file to setup the passport-google-strategy in nodejs as follows.
passport_setup.js
const passport = require('passport')
const GoogleStrategy = require('passport-google-oauth20')
const fs = require("fs");
const path = require('path');
//make OAuth2 Credentials file using Google Developer console and download it(credentials.json)
//replace the 'web' using 'installed' in the file downloaded
var pathToJson = path.resolve(__dirname, './credentials.json');
const config = JSON.parse(fs.readFileSync(pathToJson));
passport.serializeUser((user, done) => {
done(null, user.id)
})
passport.deserializeUser((id, done) => {
const query = { _id: id }
Users.findOne(query, (err, user) => {
if (err) {
res.status(500).json(err);
} else {
done(null, user)
}
})
})
//create a google startergy including following details
passport.use(
new GoogleStrategy({
clientID: config.installed.client_id,
clientSecret: config.installed.client_secret,
callbackURL: config.installed.redirect_uris[0]
}, (accessToken, refreshToken,otherTokenDetails, user, done) => {
//in here you can access all token details to given API scope
//and i have created file from that details
let tokens = {
access_token: accessToken,
refresh_token: refreshToken,
scope: otherTokenDetails.scope,
token_type: otherTokenDetails.token_type,
expiry_date:otherTokenDetails.expires_in
}
let data = JSON.stringify(tokens);
fs.writeFileSync('./tokens.json', data);
//you will get a "user" object which will include the google id, name details,
//email etc, using that details you can do persist user data in your DB or can check
//whether the user already exists
//after persisting user data to a DB call done
//better to use your DB user objects in the done method
done(null, user)
})
)
Then create your index.js file in nodejs for API route management and to call send method of Gmail API.
Also, run the following command to install "google-apis"
npm install googleapis#39 --save
index.js
const express = require("express")
//import passport_setup.js
const passportSetup = require('./passport_setup')
const cookieSeesion = require('cookie-session');
const passport = require("passport");
//import google api
const { google } = require('googleapis');
//read credentials file you obtained from google developer console
const fs = require("fs");
const path = require('path');
var pathToJson_1 = path.resolve(__dirname, './credentials.json');
const credentials = JSON.parse(fs.readFileSync(pathToJson_1));
//get Express functionalities to app
const app = express();
// **Middleware Operations**//
//cookie encryption
app.use(cookieSeesion({
name:'Reserve It',
maxAge: 1*60*60*1000,
keys: ['ranmalc6h12o6dewage']
}))
//initialize passort session handling
app.use(passport.initialize())
app.use(passport.session())
app.use(express.json());
//**API urls**//
//route to authenticate users using google by calling google stratergy in passport_setup.js
//mention access levels of API you want in the scope
app.get("/google", passport.authenticate('google', {
scope: ['profile',
'email',
'https://mail.google.com/'
],
accessType: 'offline',
prompt: 'consent'
}))
//redirected route after obtaining 'code' from user authentication with API scopes
app.get("/google/redirect", passport.authenticate('google'), (req, res) => {
try {
//read token file you saved earlier in passport_setup.js
var pathToJson_2 = path.resolve(__dirname, './tokens.json');
//get tokens to details to object
const tokens = JSON.parse(fs.readFileSync(pathToJson_2));
//extract credential details
const { client_secret, client_id, redirect_uris } = credentials.installed
//make OAuth2 object
const oAuth2Client = new google.auth.OAuth2(client_id,
client_secret,
redirect_uris[0])
// set token details to OAuth2 object
oAuth2Client.setCredentials(tokens)
//create gmail object to call APIs
const gmail = google.gmail({ version: 'v1', auth: oAuth2Client })
//call gmail APIs message send method
gmail.users.messages.send({
userId: 'me',//'me' indicate current logged in user id
resource: {
raw: //<email content>
}
}, (err, res) => {
if (err) {
console.log('The API returned an error: ' + err)
throw err
}
console.log('Email Status : ' + res.status)
console.log('Email Status Text : ' + res.statusText)
})
res.status(200).json({ status:true })
} catch (err) {
res.status(500).json(err)
}
})
app.listen(3000, () => { console.log('Server Satrted at port 3000') })
You can separate the routes in the index.js file to different files for clarity using express.Router()
If you want to call another Google API service just change this code segment and code below that;
const gmail = google.gmail({ version: 'v1', auth: oAuth2Client })
gmail.users.messages.send(....Send Method internal implementation given above....)
For Google Drive:
const drive = google.drive({version: 'v3', auth: oAuth2Client});
drive.files.list(...Refer "Google Drive API" documentation for more details....)
I believe you can't use passport.js for three-legged oauth for APIs like Sheets or Drive.
Have a look at the Using OAuth for web servers documentation instead.
user835611 has the correct answer, as that page explains everything quite nicely. However, if you still need more, the below link really helped me to understand how this works.
https://github.com/googleapis/google-auth-library-nodejs#oauth2
I'm building a node app where users can select keywords to follow on Twitter. Their 'wall' will be automatically updated as new tweets come in with their selected keywords.
The way I've built it is each user joins their own room named with their user id. The tweets should then be pushed to their room and prepended to the list with jQuery.
The problem is If I open 4 tabs and log 4 different users in it only updates the first 2 that were logged in with their Twitter feed! It doesn't matter which order I log them in it's only the first to that receive updates.
When logging the error I get: Exceeded connection limit for the user
I'm guessing Twitter only allows a single connection per API account. Is this correct?
Is there any way around this as I need individual streams for each user?
My server code is:
var socket = require( './public/node_modules/socket.io' );
var express = require('./public/node_modules/express');
var request = require('./public/node_modules/request');
var Twitter = require('./public/node_modules/twitter');
var app = express();
var server = require('http').createServer(app);
var io = socket.listen( server );
var port = process.env.PORT || 4321;
server.listen(port, function () {
console.log('Server listening at port %d', port);
});
//setup Twitter Details
var watchList = ['ferrari'];
var T = new Twitter({
consumer_key: 'xxx'
, consumer_secret: 'xxx'
, access_token_key: 'xxx'
, access_token_secret: 'xxx'
});
io.on('connection', function (client) {
client.on('join', function(data)
{
//send to the user in question i.e client
client.emit('update','You are connected');
//send to ALL users
io.sockets.emit('update', 'New user '+data.name+' has joined');
client.join(data.id, function()
{
console.log('JOINING ROOM: '+data.id+' following: '+data.following);
if(data.following!='')
{
T.stream('statuses/filter', {track: data.following}, function(stream) {
stream.on('data', function(tweet) {
client.emit('stream',tweet.text);
//io.sockets.to(data.id).emit('stream', tweet.text);
});
stream.on('error', function(error) {
console.log(error);
});
});
}
});
});
});
Thanks in advance