Couldn't fetch user profile while Instagram Business Login in nodejs via passport-instagram and passport - oauth-2.0

I have implemented instagram oauth using passport and passport-instagram package in nodejs.
Below is my code.
require("dotenv").config();
const express = require("express");
const app = express();
const passport = require("passport");
const InstagramStrategy = require("passport-instagram").Strategy;
const ExpressSession = require("express-session");
app.use(passport.initialize());
app.use(
ExpressSession({
resave: false,
saveUninitialized: true,
secret: "mylittlesecret",
})
);
app.use(passport.session());
// Serialize user data to store in the session
passport.serializeUser(function(user, done) {
done(null, user);
});
// Deserialize user data from the session
passport.deserializeUser(function(obj, done) {
done(null, obj);
});
passport.use(
new InstagramStrategy({
clientID: "Instagram_client_id",
clientSecret: "Instagram_client_secret",
callbackURL: "https://d5d0-115-xxx-xx-179.ngrok.io/auth/instagram/callback",
},
function(accessToken, refreshToken, profile, cb) {
process.nextTick(function() {
return cb(null, profile);
});
}
)
);
// Instagram login route
app.get(
"/auth/instagram",
passport.authenticate("instagram", {
scope: [
"pages_show_list",
"user_media",
"user_profile",
"instagram_basic",
"instagram_content_publish",
"instagram_manage_comments",
"instagram_manage_insights",
"pages_read_engagement",
],
})
);
// Instagram callback route
app.get(
"/auth/instagram/callback",
passport.authenticate("instagram", {
failureRedirect: "/error",
}),
(req, res) => {
res.redirect("/profile");
}
);
app.get("/profile", (req, res) => {
res.send("Proile");
});
app.get("/error", (req, res) => {
res.send("error");
});
const PORT = process.env.PORT;
app.get("/", (req, res) => {
res.send("Home");
});
app.listen(PORT, () => {
console.log(`Server is running at ${PORT}`);
});
I have created a consumer facebook app in developers platform and added product of Instagram basic display api , in basic display api valid oauth redirect uri , i have entered : https://d5d0-115-xxx-xx-179.ngrok.io/auth/instagram/callback url which i have declared in my code and
and in deauthroize callback url : https://dd9b-115-xxx-xx-179.ngrok.io/auth/instagram/
I have also added tester insatgram account also
When i hit /auth/instagram route this is taking me to instagram login, after completing all the steps im recieving error like this,
InternalOAuthError: failed to fetch user profile
at /Users/vivekgupta/Desktop/AdosphereServices/instalogin/node_modules/passport-instagram/lib/strategy.js:80:28
at passBackControl (/Users/vivekgupta/Desktop/AdosphereServices/instalogin/node_modules/oauth/lib/oauth2.js:132:9)
at IncomingMessage.<anonymous> (/Users/vivekgupta/Desktop/AdosphereServices/instalogin/node_modules/oauth/lib/oauth2.js:157:7)
at IncomingMessage.emit (node:events:402:35)
at endReadableNT (node:internal/streams/readable:1343:12)
at processTicksAndRejections (node:internal/process/task_queues:83:21)
Please help me with this ,
Thank You In advance.

Related

How to get link to composition by using status callbacks twilio

Here is what I tried but it's not working.
This guy is responsible for creating a composition after the meeting is ended.
app.post('/api/endMeeting', (req, res) => {
const roomSid = req.body.roomSid;
userEmail = req.body.userEmail;
const client = require('twilio')(config.twilio.apiKey, config.twilio.apiSecret, {accountSid: config.twilio.accountSid});
client.video.rooms(roomSid).update({ status: 'completed' });
client.video.compositions.create({
roomSid: roomSid,
audioSources: '*',
videoLayout: {
grid : {
video_sources: ['*']
}
},
statusCallback: `${process.env.REACT_APP_BASE_URL}/api/getMeeting`,
statusCallbackMethod: 'POST',
format: 'mp4'
}).then(() => {
// sendRecordingEmail(composition.sid, userEmail);
res.status(200).send({
message: 'success'
});
}).catch(err => {
res.status(500).send({
message: err.message
});
});
});
And this guy will send the download link of the composition to the participant when it's available.
app.post('/api/getMeeting', (req, res) => {
if (req.query.StatusCallbackEvent === 'composition-available') {
const client = require('twilio')(config.twilio.apiKey, config.twilio.apiSecret, {accountSid: config.twilio.accountSid});
const compositionSid = req.query.CompositionSid;
const uri = "https://video.twilio.com/v1/Compositions/" + compositionSid + "/Media?Ttl=3600";
client.request({
method: "GET",
uri: uri,
}).then((response) => {
const requestUrl = request(response.data.redirect_to);
sendRecordingEmail(requestUrl, userEmail);
res.status(200).send("success");
}).catch((error) => {
res.status(500).send("Error fetching /Media resource " + error);
});
}
});
I can confirm that the composition is created exactly in the Twilio console.
But it seems the status callback guy is not working and I can see the below issue.
It seems I made mistakes in using the status callback.
Please let me know what is the problem and how I can solve this.
Thank you.
Thank you very much for #philnash's help in solving this problem.đź‘Ť
I solved the above issue and I can get the download link of the composition for now.
The problem was in the status callback function and I should use req.body instead of req.query because of the status callback method. (It's POST on my code.)
Here is the code that is fixed.
app.post('/api/getMeeting', (req, res) => {
if (req.body.StatusCallbackEvent === 'composition-available') {
const client = require('twilio')(config.twilio.apiKey, config.twilio.apiSecret, {accountSid: config.twilio.accountSid});
const compositionSid = req.body.CompositionSid;
const uri = "https://video.twilio.com/v1/Compositions/" + compositionSid + "/Media?Ttl=3600";
client.request({
method: "GET",
uri: uri,
}).then((response) => {
const requestUrl = response.body.redirect_to; // Getting the redirect link that user can download composition
sendRecordingEmail(requestUrl, userEmail); // Send URL via email to the user
res.status(200).send("success");
}).catch((error) => {
res.status(500).send("Error fetching /Media resource " + error);
});
} else {
res.status(204).send('compositioin is not available');
}
});

How to refresh access token in electron app?google oauth2.0

I use this api to provide google login function for my electron app
https://github.com/googleapis/google-auth-library-nodejs
My access token expires after 3600 seconds
I don’t want my users to log in again after 3600 seconds
How can I make the token refresh automatically?
I try to use the document example code on the my app
But it doesn't seem to work
How can I get a new access_token
I try the code below to get a new access_token
But nothing happens
const { app, BrowserWindow, screen } = require('electron');
const fs = require('fs');
const { google } = require('googleapis'); // auth node js
googleOAuth2Login();
function googleOAuth2Login() {
const SCOPES = ['https://www.googleapis.com/auth/drive'];
const TOKEN_PATH = 'token.json';
fs.readFile('credentials.json', (err, content) => {
if (err) return console.log('Error loading client secret file:', err);
authorize(JSON.parse(content), showAccessToken);
});
function authorize(credentials, callback) {
const { client_secret, client_id, redirect_uris } = credentials.installed;
const oAuth2Client = new google.auth.OAuth2(
client_id,
client_secret,
redirect_uris[0]
);
// Check if we have previously stored a token.
fs.readFile(TOKEN_PATH, (err, content) => {
if (err) return getAccessToken(oAuth2Client, callback);
oAuth2Client.setCredentials(JSON.parse(content));
callback(JSON.parse(content))
oAuth2Client.on('tokens', (tokens) => {
//this handle not work
if (tokens.refresh_token) {
// store the refresh_token in my database!
console.log(tokens.refresh_token);
}
console.log(tokens.access_token);
});
});
}
/**
* This method opens a new window to let users log-in the OAuth provider service,
* grant permissions to OAuth client service (this application),
* and returns OAuth code which can be exchanged for the real API access keys.
*
* #param {*} interactionWindow a window in which the user will have interaction with OAuth provider service.
* #param {*} authPageURL an URL of OAuth provider service, which will ask the user grants permission to us.
* #returns {Promise<string>}
*/
function getOAuthCodeByInteraction(interactionWindow, authPageURL) {
interactionWindow.loadURL(authPageURL, { userAgent: 'Chrome' });
return new Promise((resolve, reject) => {
const onclosed = () => {
reject('Interaction ended intentionally ;(');
};
interactionWindow.on('closed', onclosed);
interactionWindow.on('page-title-updated', (ev) => {
const url = new URL(ev.sender.getURL());
// console.log(url.searchParams)
if (url.searchParams.get('approvalCode')) {
console.log('allow')
interactionWindow.removeListener('closed', onclosed);
interactionWindow.close();
return resolve(url.searchParams.get('approvalCode'));
}
if ((url.searchParams.get('response') || '').startsWith('error=')) {
console.log('reject')
interactionWindow.removeListener('closed', onclosed);
interactionWindow.close();
return reject(url.searchParams.get('response'));
}
});
});
};
function executeAuthWindow(authWindow, authUrl) {
authWindow.setMenu(null);
authWindow.show();
return new Promise((resolve, reject) => {
getOAuthCodeByInteraction(authWindow, authUrl)
.then((res) => {
if (res != 'Interaction ended intentionally ;(') {
return resolve(res);
}
if (res == 'Interaction ended intentionally ;(') {
return reject('Fail:Authorization window colose');
}
}).catch((err) => {
if (err = 'error=access_denied') {
return reject('Fail: error=access_denied');
}
});
})
}
function getAccessToken(oAuth2Client, callback) {
const authUrl = oAuth2Client.generateAuthUrl({
access_type: 'offline',
scope: SCOPES
});
const authWindow = new BrowserWindow({
width: 600,
height: 800,
show: false,
'node-integration': false,
'web-security': false
});
executeAuthWindow(authWindow, authUrl)
.then((code) => {
//access_token: and refresh_token:
oAuth2Client.getToken(code, (err, token) => {
if (err) return console.error('Error retrieving access token', err);
console.log('getToken')
console.log(token)
oAuth2Client.setCredentials(token);
console.log(oAuth2Client)
fs.writeFile(TOKEN_PATH, JSON.stringify(token), (err) => {
if (err) return console.error(err);
console.log('Token stored to', TOKEN_PATH);
});
});
}).catch((err) => {
console.log(err)
})
}
// initOAuthClient
function showAccessToken(token) {
console.log(token)
}
}
credentials file
{
"installed": {
"client_id": "*******17079-*********gjlh6g2nnndhqotn3ij509k.apps.googleusercontent.com",
"project_id": "quickstart-**********",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_secret": "*********dNz3Gceo9F",
"redirect_uris": [
"urn:ietf:wg:oauth:2.0:oob",
"http://localhost"
]
}
}

zapier oauth2 giving error for access_token

Hi i am trying to implement oauth2 with Zapier platform, and i am facing some error.
I just have a testing node.js app where i am login request from zapier platform.
const express = require('express');
const jwt = require('jsonwebtoken');
const uuidv4 = require('uuid/v4');
const app = express();
const port = process.env.PORT || 3000;
let count = 0;
// const redirect url = https://zapier.com/dashboard/auth/oauth/return/App77581CLIAPI/
app.get('/', (req, res) => res.json({
count
}));
app.post('/zapier', (req, res) => {
count++;
res.json({
count
})
})
app.get('/api/login', (req, res) => {
// console.log('req', req);
const { state } = req.query;
// const state = 1578212496.13945431311;
console.log(state);
const user = {
name: "ankit",
id: 12344
}
const token = jwt.sign(user, "luciferTonify");
const code = uuidv4();
res.redirect(`https://zapier.com/dashboard/auth/oauth/return/App77581CLIAPI?code=${code}&state=${state}&access_token=${code}&token_type=bearer`);
})
app.post('/api/login', (req, res) => {
const user = {
name: "ankit",
id: 12344
}
const token = jwt.sign(user, "luciferTonify");
res.json({ token });
});
function verifyToken(req, res, next) {
const { authorization: token } = req.headers;
if (typeof token == 'undefined' || !token) {
req.token = token;
next();
} else {
res.sendStatus(403);
}
}
app.listen(port, () => console.log(`Example app listening on port ${port}!`))
its just a testing app, so i am trying to send an access_token, but zapier is giving me this error
**
Zapier could not connect to your account. Field named access_token
not found in OAuth2 results
**
?
can anyone help me what i am doing wrong ?

Can't use GitHub for 3rd party authentication in Parse Server

I am trying to setup a simple example of 3rd party authentication in a localhost parse server using GitHub. I read the parse guide, the wiki, as well as old issues and websites (pre- and post- the opensourcing of parse). Almost everything is working, but the last part: the link between the GitHub access token and the Parse.User.
Here's my client and server code.
Client code (using hello.js for connecting with github and getting the access_token):
<html>
<body>
<script src="src/hello.polyfill.js"></script>
<script src="src/hello.js"></script>
<script src="src/modules/github.js"></script>
<script src="https://npmcdn.com/parse/dist/parse.min.js"></script>
<button onclick="hello('github').login()">Login with GitHub</button>
<div id='profile'></div>
<script>
const parseClientID = "[MY_PARSE_APP_ID]";
const githubClientID = "[MY_GITHUB_APP_ID]";
Parse.initialize(parseClientID);
Parse.setURL = "http://localhost:1337/parse";
var provider = {
authenticate(options) {if (options.success) {options.success(this, {});}},
restoreAuthentication(authData) {},
getAuthType() {return 'github';},
deauthenticate() {}
};
let authData = {authData: {access_token: 'REPLACED_ON_THE_FLY', id: githubClientID}};
hello.init({github: githubClientID}, {
oauth_proxy: 'http://localhost:3000/proxy',
redirect_uri: 'http://localhost:3000/redirect'
});
// after loging in, when github calls back, this part of the code tries to
// link the github data with a Parse.User
hello.on('auth.login', (auth) => {
authData.authData.access_token = auth.authResponse.access_token;
var user = new Parse.User();
user._linkWith(provider, authData).then(usr=>console.log(usr), err=>console.log(err));
});
</script>
</body>
</html>
Server code (nothing fancy, standard parse-server route, and oauthshim to talk with hello.js):
var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var ParseServer = require('parse-server').ParseServer;
var oauthshim = require('oauth-shim');
var app = express();
app.get('/', (req, res) => {res.render('index');});
app.get('/redirect', (req, res) => {res.render('redirect');});
var api = new ParseServer({
"appId": "[MY_PARSE_APP_ID]",
"masterKey": "[MY_PARSE_MASTER_KEY]",
"appName": "connect",
"databaseURI": "mongodb://127.0.0.1:27017/parse",
"serverURL": "http://localhost:1337/parse",
"auth": {"github": {"id":"[MY_GITHUB_APP_ID]","access_token":"spaceholder"}}
});
app.use('/parse', api);
oauthshim.init([{
client_id: '[MY_GITHUB_APP_ID]',
client_secret: '[MY_GITHUB_SECRET]',
grant_url: 'https://github.com/login/oauth/access_token',
domain: 'http://localhost:3000/redirect'
}]);
app.use('/proxy', oauthshim);
app.listen(1337, function() {console.log('parse-server running on port 1337.');});
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use(function(req, res, next) { next(createError(404));});
app.use(function(err, req, res, next) {
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
res.status(err.status || 500);
res.render('error');
});
module.exports = app;
The client displays a single "login" button. On clicking, it connects to github, gets an access token, which is then used to user._linkWith().
At this point, I get this error in the Web console:
error: Github auth is invalid for this user. code=101, message=Github auth is invalid for this user.
I think that I'm not writing the auth object properly, but I can't figure out how to do it just from the Custom Authentication section of the Guide in the parse-server website (https://docs.parseplatform.org/parse-server/guide/#oauth-and-3rd-party-authentication).
Thank you in advance !
I have implemented the github login but not in the same way you did but I think it should work the process should be the same.
You need to get the access token and next with the token get the github user id at https://api.github.com/user. And finaly call the _linkWith method.
On the server side you don't need to add auth configuration. your server should be :
var api = new ParseServer({
"appId": "[MY_PARSE_APP_ID]",
"masterKey": "[MY_PARSE_MASTER_KEY]",
"appName": "connect",
"databaseURI": "mongodb://127.0.0.1:27017/parse",
"serverURL": "http://localhost:1337/parse",
});
And on client client side you don't need to configure the provider. Just call _linkWith like that :
hello.on('auth.login', (auth) => {
// get the github user id before
const authData = {
id: 'your github user id'
access_token: 'your access token'
}
const user = new Parse.User()
return user._linkWith('github', { authData }).then(user => {
// do what you want with user
})
Hope this will help you.

MS Graph Sample Application Integration Test not Working

I want to do what the MS Graph sample node app is doing in its integrationTests.js, but that test doesn't work. Here's what I've tried:
Followed the quick start for creating a node.js app.
Ran the app. Ensured it worked by sending an e-mail.
Modified the test Checking that the sample can send an email to use my account parameters.
Tried to run the test. It fails with 403: insufficient scope. The call to get the token returned scopes, but lacked Mail.Send.
In the post data for the call to login.microsoftonline.com, I added "scope: 'Mail.Send'"
I still receive a valid token, and the return scope includes Mail.Send, but when I try to post with that token, I get 400: cannot POST /beta/me/sendMail
I tried adding scope (Mail.Send) in the query string and as a header (thought I saw that somewhere), but it made no difference.
I added the Mail.Send permission (under "Application Permissions") for the app in the application registration portal.
I compared the token (using https://jwt.ms) from my test call to the call from the app when it works. I see no real difference. They both contain the Mail.Send scope.
Here is the code (which is only slightly different from what's in the sample):
// in graphHelper.js
function postSendMail(accessToken, message, callback) {
request
.post('https://graph.microsoft.com/beta/me/sendMail')
//.post('https://graph.microsoft.com/beta/me/sendMail?scope=Mail.Send') // nope
.send(message)
.set('Authorization', 'Bearer ' + accessToken)
.set('Content-Type', 'application/json')
.set('Content-Length', message.length)
.set('scope', 'Mail.Send') // nope
.end((err, res) => {
callback(err, res);
});
}
describe('Integration', function () { // mocha
var accessToken;
var scope;
const config = getConfig();
// My account variables in testConfig.json file
function getConfig() {
var configFilePath = path.join(__dirname, 'testConfig.json');
return JSON.parse(fs.readFileSync(configFilePath, { encoding: 'utf8' }));
}
function getAccessToken(done) {
var postData = querystring.stringify(
{
grant_type: 'password',
//grant_type: 'client_id', // not supported
//grant_type: 'authorization_code', // This assumes you've requested an auth code.
resource: 'https://graph.microsoft.com/',
scope: 'Mail.Send',
client_id: config.test_client_id_v2,
client_secret: config.test_client_secret_v2,
username: config.test_username,
password: config.test_password
}
);
var postOptions = {
host: 'login.microsoftonline.com',
port: 443,
path: '/common/oauth2/token',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': Buffer.byteLength(postData)
}
};
var postRequest = https.request(postOptions, function (res) {
var data = '';
res.setEncoding('utf8');
res.on('data', function (chunk) {
data += chunk;
});
res.on('end', function () {
const response = JSON.parse(data);
accessToken = response.access_token;
scope = response.scope;
done();
});
});
postRequest.on('error', function (e) {
console.log('Error: ' + e.message);
done(e);
});
postRequest.write(postData);
postRequest.end();
}
before( // eslint-disable-line no-undef
function (done) {
getAccessToken(done);
}
);
it('Checking that the sample can send an email',
function (done) {
var postBody = emailer.generateMailBody(config.test_name, config.test_username);
graphHelper.postSendMail(
accessToken, scope,
JSON.stringify(postBody),
function (error) {
assert(error === null, `The sample failed to send an email: ${error}`);
done();
});
}
);
});

Resources