How to use LinkedIn api with Node js - node.js

All I need is to check in the backend side if the user access token is valid and get user email by its access token. It's hard to understand how to use this npm library for these purposes, so please help me.
In the documentation I've found the API address for it, but how to fetch the with Client ID and Client Secret of my app which I created on https://www.linkedin.com/developers/apps/new..
Hopefully, my question makes sense, thanks in advance <3

var passport = require('passport');
var LinkedInStrategy = require('passport-linkedin-oauth2').Strategy;
// linkedin app settings
var LINKEDIN_CLIENT_ID = "CLIENT_ID_HERE";
var LINKEDIN_CLIENT_SECRET = "CLIENT_SECRET_HERE";
var Linkedin = require('node-linkedin')(LINKEDIN_CLIENT_ID, LINKEDIN_CLIENT_SECRET);
passport.serializeUser(function (user, done) {
done(null, user);
});
passport.deserializeUser(function (obj, done) {
done(null, obj);
});
passport.use(new LinkedInStrategy({
clientID: LINKEDIN_CLIENT_ID,
clientSecret: LINKEDIN_CLIENT_SECRET,
callbackURL: "http://127.0.0.1:3000/auth/linkedin/callback",
scope: ['r_emailaddress', 'r_basicprofile', 'rw_company_admin'],
passReqToCallback: true
},
function (req, accessToken, refreshToken, profile, done) {
req.session.accessToken = accessToken;
process.nextTick(function () {
return done(null, profile);
});
}));
// for auth
app.get('/auth/linkedin',
passport.authenticate('linkedin', { state: 'SOME STATE' }),
function(req, res){
// The request will be redirected to LinkedIn for authentication, so this
// function will not be called.
});
// for callback
app.get('/auth/linkedin/callback', passport.authenticate('linkedin', { failureRedirect: '/' }),
function (req, res) {
res.redirect('/');
});
This is a Code Snippet of how i have used it, i guess it will help you on fetching with CLIENT_ID and CLIENT_SECRET.
Note : npm passport and passport-linkedin-oauth2 should already be installed

const accessToken = req.params.accessToken;
const options = {
host: 'api.linkedin.com',
path: '/v2/me',
method: 'GET',
headers: {
'Authorization': `Bearer ${accessToken}`,
'cache-control': 'no-cache',
'X-Restli-Protocol-Version': '2.0.0'
}
};
const profileRequest = https.request(options, function(result) {
let data = '';
result.on('data', (chunk) => {
data += chunk;
console.log(data)
});
result.on('end', () => {
const profileData = JSON.parse(data);
return res.status(200).json({
'status': true,
'message': "Success",
'result': profileData
});
});
});
profileRequest.end();

The existing NodeJS LinkedIn official API is not so straightforward and hardly maintained.
If relevant, you can use this NodeJS LinkedInAPI.
It allows you to easily login via username & password or with a Cookie and make various requests:
import { Client } from 'linkedin-private-api';
const username = process.env.USERNAME as string;
const password = process.env.PASSWORD as string;
(async () => {
// Login
const client = new Client();
await client.login.userPass({ username, password });
// search for companies
const companiesScroller = await client.search.searchCompanies({ keywords: 'Microsoft' });
const [{ company: microsoft }] = await companiesScroller.scrollNext();
// Search for profiles and send an invitation
const peopleScroller = await client.search.searchPeople({
keywords: 'Bill Gates',
filters: {
pastCompany: microsoft.companyId
}
});
const [{ profile: billGates }] = await peopleScroller.scrollNext();
await client.invitation.sendInvitation({
profileId: billGates.profileId,
trackingId: billGates.trackingId,
});
})

Related

node.js react Error [ERR_HTTP_HEADERS_SENT] when trying to send token using jwtToken with passport google oath2.0

I am currently trying to implement a google authentication using passport google oath2.0 on my node.js react web application with mongodb as database. I am struggling on passing token from google passport to jwtToken.
I tried a remedy by inserting the sendToken(use, 200, res) on the route parameter. I apologize for not so clear explanation but to make it easier to understand, here is my code.
backend/utils/sendToken.js
const sendToken = (user, statusCode, res) => {
// Create Jwt token
const token = user.getJwtToken();
// Options for cookie
const options = {
expires: new Date(
Date.now() + process.env.COOKIE_EXPIRES_TIME * 24 * 60 * 60 * 1000
),
httpOnly: true
}
res.status(statusCode).cookie('token', token, options).json({
success: true,
token,
user
})
}
module.exports = sendToken;
backend/passport.js
...
passport.use(new GoogleStrategy({
clientID: process.env.CLIENT_ID,
clientSecret: process.env.CLIENT_SECRET,
callbackURL: "/api/v1/google/callback",
scope: ["profile", "email"],
},
function (accessToken, refreshToken, profile, cb) {
const googleEmail = profile._json.email;
const googlePassword = profile._json.family_name;
User.findOne({
'google.google_id': profile.id
}, function(err, user) {
if (err) {
return cb(err);
}
if (!user) {
user = new User({
google: {
google_id: profile.id,
google_mail: googleEmail,
} ,
name: profile.displayName ,
email: googleEmail ,
password: googlePassword ,
avatar: { url: profile._json.picture }
});
user.save(function(err) {
if (err) console.log(err);
console.log(profile, "Register Successful, 'Access Token: '", accessToken, 'Refresh Token: ',refreshToken);
return cb(err, user);
});
} else {
console.log(profile, "Login Successful, 'Access Token: '", accessToken, 'Refresh Token: ',refreshToken);
return cb( err, user);
}
});
}
));
...
backend/routes/auth.js
const express = require('express');
const router = express.Router();
const passport = require("passport");
const sendToken = require('../utils/jwtToken');
...
router.get("/google", passport.authenticate("google", { scope: ["profile", "email"] }));
router.get(
"/google/callback",
passport.authenticate('google', { failureRedirect: '/' }),
function( req, res) {
// Successful authentication
//send user object to sendToken via jwtToken
sendToken(req.user, 200, res)
//this is where I trying to redirect after sending token to jwtToken
redirect(`http://localhost:3000/dashboard`);
});
...
You cannot redirect after you have already send a response
// you are sending a response inside sendToken function
sendToken(req.user, 200, res); // (res.status(statusCode).cookie(...).json(...)
// so you cannot redirect after response was sent
res.redirect(`http://localhost:3000/dashboard`);
If you want to redirect, you can do something like:
res.cookie('token', token, options).redirect(...);
have you ever tried using res.redirect(http://localhost:3000/dashboard) instead?

passport-azure-ad always redirect to failureRedirect but no error shown (nodejs)

following this tutorial I have build my azure ad login to use the graph api
https://learn.microsoft.com/en-us/graph/tutorials/node?tutorial-step=3
The response from azure looks got to me and I can't find any error message but it always triggers the failure redirect and therefore it does not proceed with the signInComplete function.
I was not able to figure out what's wrong. Any hint where I could look to at least to get an idea what triggered the failureRedirect?
// Callback function called once the sign-in is complete
// and an access token has been obtained
async function signInComplete(iss, sub, profile, accessToken, refreshToken, params, done) {
logger.debug("signInComplete function called")
if (!profile.oid) {
logger.error("No OID found in user profile.")
return done(new Error("No OID found in user profile."));
}
return done(null);
}
// Configure OIDC strategy
passport.use(new OIDCStrategy(
{
identityMetadata: `${config.OAUTH_AUTHORITY}${config.OAUTH_ID_METADATA}`,
clientID: config.OAUTH_APP_ID,
responseType: 'code id_token',
responseMode: 'form_post',
redirectUrl: config.OAUTH_REDIRECT_URI,
allowHttpForRedirectUrl: true,
clientSecret: config.OAUTH_APP_PASSWORD,
validateIssuer: false,
passReqToCallback: false,
scope: config.OAUTH_SCOPES.split(' '),
loggingLevel: 'warn'
},
signInComplete
));
office365Signin: function (req, res, next) {
passport.authenticate('azuread-openidconnect',
{
response: res,
prompt: 'login',
failureRedirect: '/',
failureFlash: true,
successRedirect: '/'
}
)(req,res,next);
},
office365SigninCallback: function(req, res, next) {
passport.authenticate('azuread-openidconnect',
{
response: res,
failureRedirect: process.env.FRONTEND_URL+'fail',
failureFlash: true,
successRedirect: process.env.FRONTEND_URL
}
)(req,res, next);
//failureRedirect gets always trigger even if the req.body looks correct and no error message is send
//Therefore we just check the body and trigger next if the body looks correct
var util = require('util');
logger.debug("office365SigninCallback res: "+util.inspect(res.req.body));
if (res.req.body.code && res.req.body.id_token) {
logger.debug("req.body seems correct there");
}
},
Logger office365SigninCallback res.req.body output:
office365SigninCallback res: { code: 'OAQABAAIAAAAm-06blBE1TpVMil8KPQ41qTM1deUhK_bLgEaGpsiIg5_3sa0ZNEBusd3m4rpBCrXflEsSvEtyjWWzqDhQ_9MybvYdqiR5B2FB59Msd7g8uL5YFcAExrGDqLzYo8xVIaZexHej_K3gDdJFfXbZZsiL6umdepdEXa1pyPIv4S8xVRHPcTyoB80RxpPp97uBCZagR7WstIF0QkfauUxklwlmOygAWjFvIMTuSijkkVZZ-04MbSX6wT3vBwJmQ2-kj6x_W_9fdCbYtdavgR6ZlYKtdiAxVm-3qULweEfvFo8RVC5xV2wdaPKqqYh41lcAq_1NHCiTdUcmmxbk8177WGzabDbH-rM-jRzORamSbLg_0vF48KWqu9zSgiCTX4RW556akFo6pcSkpriJWZH1aVl1cSMTWM64zb9tRM08O7hJ9YyFGTM-n6RpIiA3h9-Xh1E_TEZ8sG0noVId3yN8-gJXZ-pEB7Bur8s5C3DFOOlPgqgdEDj16tM8Wg0RinaL8P1BJ18k_Y_pr-huHMzhKaVCLYCX1Urq8fDomv0UAVchDQNIjdQ5PfiiYIT-0GYYzR5BB_5wGKJgwZypae89RRXpNJw-XOY5dv10jsUk3jEHRXW5xle2HtpM5DgCs6VbuxwVuaJfrRhfNdy7WkoOT3caV-4qTYfpfqwKvX_YtdD15RMpg-BVZQyI8b12meomlHdRi2aiqwqpTfJas0mrE7jHeScQErWx0qWAhvnZS8JJbauJGbXvjCbl2Tcoh19ngaggAA',
id_token:
'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6IkN0VHVoTUptRDVNN0RMZHpEMnYyeDNRS1NSWSJ9.eyJhdWQiOiI1YTYxYTMwZC00MTAyLTQwMGUtYTVmNS05NDJlYzAxNDE3ODciLCJpc3MiOiJodHRwczovL2xvZ2luLm1pY3Jvc29mdG9ubGluZS5jb20vZTFkMDE4YTktOWRlZC00Yjg4LTllYTItNDJkYTAwY2Q1ZjVhL3YyLjAiLCJpYrRVl4UHJjRk9aVk5tX1N6UHNyX0ZrIiwib2lkIjoiZXQiOjE1ODk4ODA3MTIsIm5iZiI6MTU4OTg4MDcxMiwiZXhwIjoxNTg5ODg0NjEyLCJhaW8iOiJBVFFBeS84UEFBQUEzb0dsSkdWK1dYYlE0elZJNHZic2ZnejZvUWZqYy9XUkNtS1QrYlRORHVjM2dYdll4L3F4OTdEMm5VeTRUUUxNIiwiY19oYXNoIjoiU1k4alM1ZjlxMkg4TU9oSmVIcjNhQSIsIm5hbWUiOiJUaW0gU3RlaW4iLCJub25jZSI6IkZfWjctTmpGSU5jgyYWRkNGMtOGM2MS00YjYxLWJmYWItZmQzNmE2YzY0MjY5IiwicHJlZmVycmVkX3VzZXJuYW1lIjoidHN0ZWluQFZBTlRBLklPIiwic3ViIjoiZ3Q3RExJZ1Y0MEJDZlRxRXhhSlM5Z09qcjhlRWU3TFF0cTJLQk9yNThmbyIsInRpZCI6ImUxZDAxOGE5LTlkZWQtNGI4OC05ZWEyLTQyZGEwMGNkNWY1YSIsInV0aSI6IjlyRHBOM0hBLTAtU3Y2T25XWmpVQUEiLCJ2ZXIiOiIyLjAifQ.uCG5x4cesT2925Kr_lXloYWxgIsPfsRX2FKd4t8ASDeQXg9PdvjTsTvnzzBqFDtW77obSX7bO75a-0XjA9TIh4-kMTgJWm8PlnHCWaHRQgfNlTmjp99oUf0msZx6OhyZ0-xFMMe6DTShFfBhHjF2ds17zw-oynv6PaygSox4s94qvL2e8ULi2wfpm4AYQwxXeUQba9dhoQu8AsCozY-6NyWIGc2alzg7TK5qBpuY16BScGsUkmChGFZ9lF9vD-uM8x0JYg0G6Uvc_aDNIWnt9B7VRH-U9sIFXtL9doaJXvRl2aPQnj6x0rtfgfJ4zonrJZQEn7e8y7XPIcnU0gMO9g',
state: 'GNy7cIjlBvfga4FhQiapnWnDAn8itXtk',
session_state: 'c88bace3-4039-9922-6f06-dcd6ba1a62ac' }
Based on the documentation the response looks correct to me:
https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow
I am grabbing this code straight from one of my projects in production. I was facing a similar problem before but it kind of resolved by itself when we were tweaking the done callback for some reason.
Maybe this can serve as an example.
Passport.js
'use strict';
//Dependencies
const passport = require('passport');
const OIDCStrategy = require('passport-azure-ad').OIDCStrategy;
//Custom Modules
const msService = require('./msService');
const DB_Connection = require('../dbConnection');
//DB Setting
require('../models/MS_User');
const User_DB = DB_Connection.model('user');
//Winston Logger
const logger = require('../log');
const passLog = logger.get('passportLog');
//Azure AD Creds
const loginCredentials = require('../creds/oicdCreds');
// Session
//Take in outlook id => keep the session data small
passport.serializeUser((outlookid, done) => {
done(null, outlookid);
});
//Deserialize when needed by querying the DB for full user details
passport.deserializeUser((outlookid, done) => {
User_DB.findOne({ outlookId: outlookid })
.then(user => {
done(null, user);
})
.catch(err => passLog.error(`Error Deserializing User: ${outlookid}:` + ' ' + err));
});
//Export the passport module
module.exports = (passport) => {
//OpenIdConnect
passport.use(new OIDCStrategy(loginCredentials,
//Verify callback for passReqToCallback: false
(iss, sub, profile, access_token, refresh_token, params, done) => {
//Get Calendar ID
msService.getCalId(access_token, calId => {
//Create or update the user
User_DB.findOneAndUpdate({ outlookId: profile.oid }, {
name: profile.displayName,
outlookId: profile.oid,
email: profile._json.email,
lastLogin: profile._json.ipaddr,
accessToken: access_token,
calId: calId
}, { upsert: true, returnNewDocument: false })
.catch(err => passLog.error(`Error Adding / Rnewing User: ${profile.oid}:` + ' ' + err));
//Return Profile ID for Serialization
done(null, profile.oid);
});
}));
};
The routes
//AD OpenIdConenct
//Login
router.get('/auth/outlook/login',
//Using MS Azure OpenId Connect strategy (passport)
passport.authenticate('azuread-openidconnect')
);
//Callback Handling
//Using MS Azure OpenId Connect strategy (passport)
router.post('/auth/outlook/callback', passport.authenticate('azuread-openidconnect', { failureRedirect: '/auth/outlook/login' }), (req, res) => {
//Redis
client.keys('*', (err, keys) => {
sessionLog.info(`Login Active Session: ${keys.length}`);
});
res.redirect('/profile_info');
}
);
If you come by this in question in google I had the same error, and it turned out I was using the Azure Secret ID, not the Secret Value
Add loggingNoPII: false to your OIDC strategy, this will print out any errors.

How to send FormData from Node/Express to another application(Node/Express) using request

I have a frontend website (ejs and node/express) running on localhost:8000 (if this helps) and the backend server (node/express) running on localhost:8010 (p.s. my database is in the backend).
I am trying to implement Social login (fb, google etc) using passport and it works perfectly fine. But i want to save the social login credentials in Database (i am using mongoose) (which is ofcourse in/on the backend server)
and my Passport application is on the frontend (express)
Also all the CRUD operation(s) i perform from webpage works like a charm
I am using request module in frontend to send http request to the backend server
Now what i am doing is
Frontend Server-
passport.use(new FacebookStrategy({
clientID: process.env.FB_CLIENT_ID || 'its a secret',
clientSecret: process.env.FB_CLIENT_SECRET || 'its a secret',
callbackURL: `${process.env.BASE_URL}/auth/callback/facebook` || '/auth/callback/facebook',
profileFields: ['name', 'email', 'link', 'locale'],
passReqToCallback: true
}, (req, accessToken, refreshToken, profile, cb) => {
const form = new FormData();
form.append('socialLogin', 'facebook');
form.append('facebook', profile.id);
form.append('accessToken', accessToken);
form.append('avatar', `https://graph.facebook.com/${profile.id}/picture?type=large`);
form.append('email', profile._json.email);
form.append('username', `${profile.name.givenName}${profile.name.familyName}`);
// const option = {
// socialLogin: 'facebook',
// facebook: profile.id,
// tokens: [{
// kind: 'facebook',
// accessToken
// }],
// avatar: `https://graph.facebook.com/${profile.id}/picture?type=large`,
// email: profile._json.email,
// username: `${profile.name.givenName} ${profile.name.familyName}`
// };
request({
method: 'POST',
dataType: 'JSON',
url: process.env.BACKEND_URL + socialRoute + '/facebook',
// data: option,
data: form,
headers: {
'secret': 'its a secret',
'authorization': true
},
contentType: false,
processData: false
}, function(error, response,
console.log('body', body);
return cb(error, body);
});
}
));
(p.s. i also wanted to show you guys the commented code, i.e. the option variable. even that didnt work)
Backend Server
Router
const socialLoginCont = require('../controllers/socialLogin.cont');
router.post('/facebook', socialLoginCont.facebook);
(yes i am using the express router)
Controller
const formidable = require('formidable');
const User = require('../models/Users');
const facebook = async (req, res, next) => {
const form = new formidable.IncomingForm();
return form.parse(req, async (err, fields, files) => {
res.send('it works from facebook: '+ fields);
});
}
module.exports = {
facebook
//, and more
}
Since all other code in my backend server works fine so i havent added any aditional code, just the part in which i need help
After i click the facebook sign button i get this message in my terminal
[nodemon] watching: *.*
[nodemon] starting `node app.js`
Server started on port 8000
body it works facebook: [object object]
[nodemon] restarting due to changes...
[nodemon] restarting due to changes...
[nodemon] starting `node app.js`
I even tried it using Postman and this is the output
it works from facebook[object Object]
If i Output single field it shows undefined
i.e.
res.send(fields.socialLogin)
If i Output multiple field , it shows [object object]
i.e.
res.send(fields)
Thats it i guess, if you guys dont get it, ill try to add some more code,
but i hope you get the gist of what i am trying to do
(I have also searched this kind of answer, but didnt find any)
Example
What i am trying to do is something like this
passport.use(new FacebookStrategy({
clientID: process.env.FACEBOOK_ID,
clientSecret: process.env.FACEBOOK_SECRET,
callbackURL: `${process.env.BASE_URL}/auth/facebook/callback`,
profileFields: ['name', 'email', 'link', 'locale', 'timezone', 'gender'],
passReqToCallback: true
}, (req, accessToken, refreshToken, profile, done) => {
if (req.user) {
User.findOne({ facebook: profile.id }, (err, existingUser) => {
if (err) { return done(err); }
if (existingUser) {
req.flash('errors', { msg: 'There is already a Facebook account that belongs to you. Sign in with that account or delete it, then link it with your current account.' });
done(err);
} else {
User.findById(req.user.id, (err, user) => {
if (err) { return done(err); }
user.facebook = profile.id;
user.tokens.push({ kind: 'facebook', accessToken });
user.profile.name = user.profile.name || `${profile.name.givenName} ${profile.name.familyName}`;
user.profile.gender = user.profile.gender || profile._json.gender;
user.profile.picture = user.profile.picture || `https://graph.facebook.com/${profile.id}/picture?type=large`;
user.save((err) => {
req.flash('info', { msg: 'Facebook account has been linked.' });
done(err, user);
});
});
}
});
} else {
User.findOne({ facebook: profile.id }, (err, existingUser) => {
if (err) { return done(err); }
if (existingUser) {
return done(null, existingUser);
}
User.findOne({ email: profile._json.email }, (err, existingEmailUser) => {
if (err) { return done(err); }
if (existingEmailUser) {
req.flash('errors', { msg: 'There is already an account using this email address. Sign in to that account and link it with Facebook manually from Account Settings.' });
done(err);
} else {
const user = new User();
user.email = profile._json.email;
user.facebook = profile.id;
user.tokens.push({ kind: 'facebook', accessToken });
user.profile.name = `${profile.name.givenName} ${profile.name.familyName}`;
user.profile.gender = profile._json.gender;
user.profile.picture = `https://graph.facebook.com/${profile.id}/picture?type=large`;
user.profile.location = (profile._json.location) ? profile._json.location.name : '';
user.save((err) => {
done(err, user);
});
}
});
});
}
}));
this is an example from https://github.com/sahat/hackathon-starter where they are storing the credentials to the database (easy)
You need to mention the correct content type in your code, like 'Content-Type': 'application/x-www-form-urlencoded' in your header, currently you are setting "contentType: false". also check the dataType: 'JSON', remove that if you are unsure about the returning content.
see this link for sample
https://flaviocopes.com/node-http-post/

How do I use passport.js to GET JSON using accessToken of an already logged in user?

I'm able to do a GET request to grab JSON from discord while using the access token that's supplied by passport. How can I use passport to grab the accessToken of a logged in user to do GET requests on another page?
passport.use(new DiscordStrategy({
clientID: keys.discord.clientID,
clientSecret: keys.discord.clientSecret,
callbackURL: '/auth/discord/redirect'
}, (accessToken, refreshToken, profile, done) => {
request({
url: 'https://discordapp.com/api/users/#me/guilds',
auth: {
'bearer': accessToken
}
}, (err, res) => {
console.log(res.body);
});
User.findOne({ discordId: profile.id }).then((currentUser) => {
if (currentUser) {
done(null, currentUser);
} else {
new User({
discordId: profile.id
}).save().then((newUser) => {
console.log('Created new user: ', newUser);
done(null, newUser);
});
}
});
}));
So I will skip the passport part and will show you the token exchange:
The signin method:
const jwt = require('jsonwebtoken');
[...]
app.post('/signin', passport.authenticate('signin'), (req, res) => {
if (req.user){
// Set the JWT token for this session
const token = jwt.sign(
{ id: req.user.id },
keys.discord.clientSecret,
{ expiresIn: config.SESSION_DURATION } //The validity time (optional)
);
const currentDate = new Date();
return res.status(200).send({
auth: true,
token: token,
// These two properties below are optional if you want to keep track
// of the session duration and send some more user info
tokenDuration: {
expire: currentDate.setMilliseconds(currentDate.getMilliseconds() + config.SESSION_DURATION)},
user: {firstname: req.user.firstname, lastname: req.user.lastname}
});
}
return res.status(401).send('Could not login');
});
Then when you make requests from the client:
axios({
method: 'POST',
url: `${url}/path`,
data: data,
headers: {
'x-access-token': jwtToken, // This is the "token" property from above
},
json: true
})
And finally you handle the above request in the server:
app.post('/path', (req, res) => {
jwt.verify(req.headers['x-access-token'], keys.discord.clientSecret, (err, decoded) => {
if (err) {
// The user is not authorized, handle properly
}
// User is authorized, do stuff
});
Hopefully this will be enough for you to start. Like I mentioned have a look at JWT, their documentation is well written :)

Node.js/Passport Twitter authorization returns 302

I'm doing a POST request to authorize Twitter via Passport Twitter strategy. The request is going on fine if I use Postman but it fails with if I use it in my app. I get a 302 in response and this in browser console
Error: Network Error
Stack trace:
createError#webpack-internal:///99:16:15
handleError#webpack-internal:///96:87:14
From what I read on the net I found that 302 would be because of some bad implementation of the a redirect call? Maybe is it that twitter does when authorizing a application and I'm not handling it correctly?
The code is as follows. Client-side using Vuejs with Axios to send a request.
Vue template:
<template>
<card>
<h4 slot="header" class="card-title">Edit linked accounts</h4>
<form>
<button type="submit" class="btn btn-info btn-fill" #click.prevent="authTwitter">
Link Facebook
</button>
<div class="clearfix"></div>
</form>
</card>
</template>
<script>
import Card from 'src/components/UIComponents/Cards/Card.vue'
import controller from '../../../../../src/controller/AuthController'
export default {
components: {
Card
},
data () {
return {
}
},
methods: {
authTwitter () {
let token = this.$session.get('jwt')
controller.http.post('/auth/twitter',{}, {
headers: {
Authorization: 'Bearer ' + token
}
})
.then(function(response) {
console.log(response)
})
.catch(function(error) {
console.log(error);
})
}
}
}
</script>
<style>
</style>
Axios settings:
const axios = require('axios');
const config = require('../../config/index.js')
let http = axios.create({
baseURL: config.url,
'Content-Type' : 'application/x-www-form-urlencoded',
'Access-Control-Allow-Origin':'*'
})
module.exports = {
http
}
And in my backend I'm doing the following:
Passport settings:
const passport = require('passport');
const StrategyTwitter = require('passport-twitter').Strategy,
LocalStrategy = require('passport-local').Strategy;
const JwtStrategy = require('passport-jwt').Strategy,
ExtractJwt = require('passport-jwt').ExtractJwt;
const {
User,
UserDetails,
UserAccounts
} = require('../models');
const bcrypt = require('bcrypt-nodejs');
const jwt = require('jsonwebtoken');
const config = require('../config/config');
let session = require('express-session')
var opts = {}
opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken();
opts.secretOrKey = config.secretKey;
module.exports = function(app) {
// Local sign-in stragetgy
passport.use('local-signin', new LocalStrategy(
function(username, password, done) {
User.findOne({
where: {
username: username
}
}).then(function(data) {
bcrypt.compare(password, data.password, function(err, response) {
if (err) {
return done(err);
}
const token = jwt.sign({
id: data.id
}, config.secretKey, {
expiresIn: 86400 // 86400 expires in 24 hours
});
return done(null, token);
});
}).catch(function(error) {
return done(error)
});
}
));
// Local sign-up strategy
passport.use('local-signup', new LocalStrategy({
usernameField: 'username',
passwordField: 'password',
passReqToCallback: true // allows us to pass back the entire request to the callback
},
function(req, username, password, done) {
process.nextTick(function() {
User.beforeCreate(function(req) {
return encryptPass(req.password)
.then(success => {
req.password = success;
})
.catch(err => {
if (err) console.log(err);
});
});
User.create({
username: username,
password: password
}).then(function(data) {
UserDetails.create({
username: req.body.username,
name: req.body.name,
dob: req.body.dob,
phone: req.body.phone,
gender: req.body.gender,
address: req.body.address,
country: req.body.country,
}).then(function(data) {
UserAccounts.create({
username: username
}).then(function(data) {
return done(null, data);
}).catch(function(error) {
return done(error.message);
});
}).catch(function(error) {
return done(error.message);
});
}).catch(function(error) {
return done(error.message);
});
})
}
));
// Passport Jwt strategy
passport.use('jwt', new JwtStrategy(opts, function(jwt_payload, done) {
console.log('jwt', jwt_payload);
UserDetails.findOne({
where: {
id: jwt_payload.id
}
})
.then(function(user) {
return done(null, user.id);
})
.catch(function(err) {
return done(err, false);
});
}));
// Use sessions for twitterStrategy Oauth1 authorizations.
passport.serializeUser(function(user, cb) {
console.log('user', user)
cb(null, user);
});
passport.deserializeUser(function(obj, cb) {
console.log('obj', obj)
cb(null, obj);
});
// Configure the Twitter strategy for use by Passport.
//
// OAuth 1.0-based strategies require a `verify` function which receives the
// credentials (`token` and `tokenSecret`) for accessing the Twitter API on the
// user's behalf, along with the user's profile. The function must invoke `cb`
// with a user object, which will be set at `req.user` in route handlers after
// authentication.
passport.use('twitter-authz', new StrategyTwitter({
consumerKey: config.keys.twitter.consumerKey,
consumerSecret: config.keys.twitter.consumerSecret,
callbackURL: process.env.CALLBACK_URL_TWITTER || 'http://120.0.0.1:8000/#/dashboard/user'
},
function(token, tokenSecret, profile, cb) {
process.nextTick(function() {
// In this example, the user's Twitter profile is supplied as the user
// record. In a production-quality application, the Twitter profile should
// be associated with a user record in the application's database, which
// allows for account linking and authentication with other identity
// providers.
console.log(token, tokenSecret, profile);
return cb(null, profile);
})
}));
// Initialize Passport and restore authentication state, if any, from the
// session.
app.use(passport.initialize());
// Session for twitterStrategy
app.use(session({
secret: config.secretKey,
resave: false,
saveUninitialized: false
}));
}
function encryptPass(pass) {
return new Promise((resolve, reject) => {
bcrypt.hash(pass, null, null, function(err, hash) {
if (err) {
return reject(err);
};
return resolve(hash);
})
})
}
And my router settings:
const AuthControllerPolicy = require('./controllers/policies/AuthControllerPolicy.js')
const AuthController = require('./controllers/AuthController.js')
const passport = require('passport');
module.exports = (app) => {
app.post('/auth/twitter',
passport.authenticate('jwt', { session: false }),
passport.authorize('twitter-authz', { session: false }),
AuthController.authTwitter)
}
Answer found here: Axios and twitter API
Looks like Twitter would not allow CORS request and it must be done only from the server-side.

Resources