LinkedIn API Fails - Node.js Request - node.js

I am trying to make REST API calls to Node.js using request module. I have obtained accessToken and accessTokenSecret.
When I make an api call to obtain my profile I get a result, but when I make an api call to do a company search I get the following error
<error>
<status>401</status>
<timestamp>1345187981287</timestamp>
<request-id>HE45IXV7YZ</request-id>
<error-code>0</error-code>
<message>[unauthorized]. OAU:xxxxx|xxxxx|*01|*01:1345188248:kCNFNUu6JePTEy7k5e8Ca9vHAzg=</message>
</error>
But when I make the same API call using JAVA (Scribe jar), using the same accessToken and accessTokenSecret I get results for the company search.
I am posting my node.js code below for reference
//oauth test
var request = require('request');
var key = 'xxxxx';
var secret = 'xxxxx';
var redirect = '';
var restURL = 'http://api.linkedin.com/v1/company-search?keywords=philips&format=json';
var accessToken = 'xxxxx';
var accessTokenSecret = 'xxxxx';
var proxySetting = "http://proxy:port/";
function getRequestToken()
{
var requestOAuth =
{
consumer_key: key
, consumer_secret: secret
//, token: accessToken
//, token_secret: accessTokenSecret
};
var requestTokenURL = 'https://api.linkedin.com/uas/oauth/requestToken';
request.get({'proxy':proxySetting,url:requestTokenURL,oauth:requestOAuth},function(e,r,data)
{
console.log('Error is: ' + e);
console.log('Data is: ' + data);
console.log('Response is: ' + r);
});
}
function getAccessToken()
{
var accessOAuth =
{
consumer_key: key
, consumer_secret: secret
, token: 'xxxxx'
, token_secret: 'xxxx'
,verifier : #####
};
var accessTokenURL = 'https://api.linkedin.com/uas/oauth/accessToken';
request.get({'proxy':proxySetting,url:accessTokenURL,oauth:accessOAuth},function(e,r,data)
{
console.log('Error is: ' + e);
console.log('Data is: ' + data);
console.log('Response is: ' + r);
});
}
/
function comSearch()
{
var apiToken = 'xxxxx';
var apiTokenSecret = 'xxxxx';
var apiOAuth =
{
consumer_key: key
, consumer_secret: secret
, token: apiToken
, token_secret: apiTokenSecret
};
var apiURL = 'http://api.linkedin.com/v1/company-search?keywords=philips';
var peopleProfile = 'http://api.linkedin.com/v1/people/~';
request.get({'proxy':proxySetting,url:apiURL,oauth:apiOAuth},function(e,r,data)
{
console.log('Error is: ' + e);
console.log('Data is: ' + data);
console.log('Response is: ' + r);
});
}
comSearch();
Following is my header
Response is: GET http://api.linkedin.com/v1/company-search?keywords=philips HTTP/1.1
host: api.linkedin.com
Authorization: OAuth keywords="philips",oauth_consumer_key="xxx",oauth_nonce="xxx",oauth_signature_method="HMAC-SHA1",oauth_timestamp="1345189928",oauth_token="xxx",oauth_version="1.0",oauth_signature="xxx"
content-length: 0
Connection: keep-alive
Could there be some error due to the signature issues ?
I have posted this Issue, but posting it here to reach a wider audience
EDIT 1
Reason why I am using the request module is, it helps me do oauth behind a proxy.
I would love to try out Passport.js or node-oauth or linked-in but none seem to have options where I can specify my proxy

I managed to get it work using node-oauth
Apparently there was code fix provided so that we could access node-oauth over the proxy and that works perfectly fine.
The fix for using node-oauth over a http-proxy was mentioned by Jared Hanson in this SO Question. This fix for node-oauth over a http-proxy can be found here

Please, share your generated base signature string. It seems like your query params were not corectly added to the signature string. In some old post on linkedIn forum I've seen that params need to be organized in the string to sign in alphanumeric order.

Related

x-www-form-urlencoded format - using https in node.js

I am currently writing to an API to try and get a token. I'm nearly there but fallen at the last hurdle..
const fs = require('fs');
const https = require('https');
const ConfigParams = JSON.parse(fs.readFileSync('Config.json', 'utf8'));
const jwt = require('jsonwebtoken');
const apikey = ConfigParams.client_id;
var privateKey = fs.readFileSync(**MY KEY**);
var tkn;
const jwtOptions = {
algorithm: 'RS512',
header: { kid: 'test-1' }
}
const jwtPayload = {
iss: apikey,
sub: apikey,
aud: **API TOKEN ENDPOINT**,
jti: '1',
exp: 300
}
jwt.sign(jwtPayload,
privateKey,
jwtOptions,
(err, token) => {
console.log(err);
//console.log(token);
tkn = token;
let = tokenPayload = {
grant_type: 'client_credentials',
client_assertion_type: 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer/',
client_assertion: tkn
}
tokenAuthOptions = {
payload: tokenPayload,
host: **HOST**,
path: **PATH**,
method: 'POST',
}
https.request(
tokenAuthOptions,
resp => {
var body = '';
resp.on('data', function (chunk) {
body += chunk;
});
resp.on('end', function () {
console.log(body);
console.log(resp.statusCode);
});
}
).end();
}
)
the encoded token comes back fine for the first part, the https request though returns a problem.
the response I get back is grant_type is missing, so I know I have a formatting problem due to this x-www-form-urlencoded, but I can't figure out how to fix it.
here is what the website said:
You need to include the following data in the request body in
x-www-form-urlencoded format:
grant_type = client_credentials client_assertion_type =
urn:ietf:params:oauth:client-assertion-type:jwt-bearer
client_assertion = <your signed JWT from step 4> Here's a complete
example, as a CURL command:
curl -X POST -H "content-type:application/x-www-form-urlencoded"
--data \ "grant_type=client_credentials\ &client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer
&client_assertion="
END POINT
Ideally I want a solution using the https request, but if that's not possible I'm open to other solutions.
Any help is greatly appreciated.
Thanks,
Craig
Edit - I updated my code based on a suggestion to:
const params = new url.URLSearchParams({
grant_type: 'client_credentials',
client_assertion_type: 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer/',
client_assertion: tkn
});
axios.post("URL", params.toString()).then(resp => {
console.log("response was : " + resp.status);
}).catch(err => {
console.log("there was an error: " + err);
})
But I'm still getting an error code 400, but now with less detail as to why. (error code 400 has multiple message failures)
Postman is the best.
Thank for #Anatoly for your support which helped to point me in the right direction. I had no luck so used postman for the first time, and found it had a code snippet section, with four different ways of achieving this using node.js.
The solution with Axion was:
const axios = require('axios').default;
const qs = require('qs');
var data = qs.stringify({
'grant_type': 'client_credentials',
'client_assertion_type': 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer',
'client_assertion': tkn
});
var config = {
method: 'post',
url: '',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
data: data
};
axios(config)
.then(function (response) {
console.log(JSON.stringify(response.status));
})
.catch(function (error) {
console.log(error);
});
I believe the issue was that I was not passing the information into 'data:' in combination with the querystring problem. Using qs.stringify to format the object, then passing this into the data: key solved the problem.

How to get access token for Azure DevOps and use this for DevOps services REST APIs call?

Actually I want to get the list of "Azure Pipeline" using JavaScript REST API. Please check below for the REST API url:
https://learn.microsoft.com/en-us/rest/api/azure/devops/pipelines/pipelines/list?view=azure-devops-rest-6.0
Now to get the response we need to pass the "access token". As of now I'm getting the access token using the "#azure/ms-rest-nodeauth" library, but as a response I'm not getting the proper response. Please check the below code.
const rp = require('request-promise');
module.exports = async function (context, req) {
let url = `https://dev.azure.com/{organization}/{project}/_apis/pipelines?api-version=6.0-preview.1`;
const header = {
Authorization: `Bearer ${token}` // I got the "token" using the "**#azure/ms-rest-nodeauth**" library
};
const result = await rp({
url: url,
json: true,
headers: header,
mode: 'cors',
cache: 'no-cache',
method: 'GET'
});
context.res = {
body: result
};
}
After using the above code I'm not getting the proper response, getting the response as HTML.
So can anyone please tell me that how do I get the proper access token for DevOps services REST APIs call or How do I get the list of Azure devpos pipeline using JavaScript or Node Js ???
There are several ways to get the token. Not sure how to get the access token via #azure/ms-rest-nodeauth
, to get the access token via AAD auth to call Azure DevOps REST API, make sure you are using a user-involved flow e.g. auth code flow, device code flow, etc, as the client credential flow(use service principal or MSI to auth) will not work with Azure DevOps REST API.
For example, you could use the device-code flow.
import * as msRestNodeAuth from "#azure/ms-rest-nodeauth";
msRestNodeAuth.interactiveLoginWithAuthResponse().then((authres) => {
console.dir(authres, { depth: null })
}).catch((err) => {
console.log(err);
});
You could also use auth code flow to get the token via ADAL for Node.js.
var AuthenticationContext = require('adal-node').AuthenticationContext;
var clientId = 'yourClientIdHere';
var clientSecret = 'yourAADIssuedClientSecretHere'
var authorityHostUrl = 'https://login.windows.net';
var tenant = 'myTenant';
var authorityUrl = authorityHostUrl + '/' + tenant;
var redirectUri = 'http://localhost:3000/getAToken';
var resource = '499b84ac-1321-427f-aa17-267ca6975798';
var templateAuthzUrl = 'https://login.windows.net/' +
tenant +
'/oauth2/authorize?response_type=code&client_id=' +
clientId +
'&redirect_uri=' +
redirectUri +
'&state=<state>&resource=' +
resource;
function createAuthorizationUrl(state) {
return templateAuthzUrl.replace('<state>', state);
}
// Clients get redirected here in order to create an OAuth authorize url and redirect them to AAD.
// There they will authenticate and give their consent to allow this app access to
// some resource they own.
app.get('/auth', function(req, res) {
crypto.randomBytes(48, function(ex, buf) {
var token = buf.toString('base64').replace(/\//g,'_').replace(/\+/g,'-');
res.cookie('authstate', token);
var authorizationUrl = createAuthorizationUrl(token);
res.redirect(authorizationUrl);
});
});
// After consent is granted AAD redirects here. The ADAL library is invoked via the
// AuthenticationContext and retrieves an access token that can be used to access the
// user owned resource.
app.get('/getAToken', function(req, res) {
if (req.cookies.authstate !== req.query.state) {
res.send('error: state does not match');
}
var authenticationContext = new AuthenticationContext(authorityUrl);
authenticationContext.acquireTokenWithAuthorizationCode(
req.query.code,
redirectUri,
resource,
clientId,
clientSecret,
function(err, response) {
var errorMessage = '';
if (err) {
errorMessage = 'error: ' + err.message + '\n';
}
errorMessage += 'response: ' + JSON.stringify(response);
res.send(errorMessage);
}
);
});
You could also use the MSAL for node.js auth code flow to get the token, it is an update for ADAL, remember to change the scope to devops "scopes": ["499b84ac-1321-427f-aa17-267ca6975798/.default"].

Nodejs twitter api 403

I am trying to use the twitter api with nodejs 5.4.1, using the twitter api as a guide. Initially my bearer access token appears to be generated properly, though when I run the actuall request I keep getting a '403 Forbidden' error message. Any idea why this is?
var R = require("request");
var stream = require('twitter');
var https = require('https');
var key = 'my-key';
var secret = 'my-secret';
var cat = key +":"+secret;
var credentials = new Buffer(cat).toString('base64');
var url = 'https://api.twitter.com/oauth2/token';
R({ url: url,
method:'POST',
headers: {
"Authorization": "Basic " + credentials,
"Content-Type":"application/x-www-form-urlencoded;charset=UTF-8"
},
body: "grant_type=client_credentials"
}, function(err, resp, body) {
var an = JSON.parse(body);
console.log( an['access_token']);
runIt(an['access_token']);
console.dir(body); //the bearer token...
});
function runIt(key){
var options = {
host: 'api.twitter.com',
path: '/1.1/users/search.json?q=Twitter%20API&page=1&count=3',
headers: {
'Host': 'api.twitter.com',
'Authorization' : 'Bearer ' + key,
'Accept-Encoding': 'gzip'
}
};
https.get(options,(res)=>{
console.log(res.statusCode);
console.log(res);
});
}
For Twitter User Api you'll have to follow the proper oauth steps to get things work properly.
Initialy there will be 2-step request process that will leave you with token and secret of user.
You will use that information to sign request with method like HMAC-SHA1 so that you can access data from twitter, node-auth can be helpful in this step. Twitter Link - Authorizing requests
For further understanding see these tutorials:
Implement Twitter Sign
Nodejs Twitter api
and for code inspiration:
Twitter Streamming | A NodeJS Component

Authenticate to JIRA using node-jira module

I need to connect my application to JIRA API, and I found module node-jira, that should help me with that.
However, I'm having problem with authentication.
Here's what I done (nothing special, but for some reason, it doesn't work):
var JiraApi = require('jira').JiraApi;
var jira = new JiraApi('https', '[url to my jira project]', 443, '[username]', '[password]', '2.0.alpha1');
jira.getCurrentUser(function(error, issue) {
if(error){
console.log(error);
return;
}
console.log('success');
});
I receive:
401: Error while getting current user
Any ideas what could go wrong?
After digging into source code, looks like mentioned method isn't making request properly.
It does this.request instead of this.doRequest. I'll submit it to github repo.
This may give you some ideas; it's not a call to get an issue from JIRA, but it shows how to set up an Atlassian API call (from Google Sheets). You just need to plug in the right URL and Endpoint (for a JIRA issue as an example).
function showAtlassian() {
var html = HtmlService.createHtmlOutputFromFile('atlassianform')
.setWidth(200)
.setHeight(200);
SpreadsheetApp.getUi().showModalDialog(html, 'Atlassian Login');
}
function processAtlassian(myForm) {
var username = myForm.un;
var userpw = myForm.pw;
var myencoded = Utilities.base64Encode(username+":"+userpw);
var headers = {"Authorization" : "Basic " + myencoded};
var options = {
'method': 'get',
"contentType" : "application/json",
"headers": headers,
'muteHttpExceptions': false
}
var ui = SpreadsheetApp.getUi();
url = 'https://---your domain --/wiki/rest/api/user/current';
try {
var response = UrlFetchApp.fetch(url, options);
var data = JSON.parse(response)
var result = ui.alert( 'got valid connection userkey ' + data.userKey );
} catch(error) {
var result = ui.alert( 'invalid user or password: url: '+ url +' err: ' + error.toString());
getatlassian();
}
}
function getatlassian() {
var ui = SpreadsheetApp.getUi();
showAtlassian()
}

Node.js and twilio integration

I am trying to integrate twilio with Node.js+express.
I don't have a site yet. what value should I give for HOSTNAME, along with SID and AUTH_TOKEN, these values I got from twilio site.
I have written some code, whatever suggestion given below I have placed in to views folder in twiclient.js , I have added a route in app.js to redirect the request if /twi is called , but I am not getting any result. some errors are appearing in the console, would you please help me figure out what I'm doing wrong? I have placed the correct SID, token and hostname, as specified below.
app.js has the following entry, does anything else need to be done for the twilio calling part to work?
Also, where should I define the GUI for calling a phone in the views folder?
var TwilioClient = require('twilio').Client,
      Twiml = require('twilio').Twiml,
      sys = require('sys');
var client = new TwilioClient('MY_ACCOUNT_SID', 'MY_AUTH_TOKEN', 'MY_HOSTNAME');
var phone = client.getPhoneNumber('+2323232323');
phone.setup(function() { phone.makeCall('+15555555555', null, function(call) {});
phone.setup(function() {
    phone.makeCall('+15555555555', null, function(call) {
        call.on('answered', function(callParams, response) {
            response.append(new Twiml.Say('Hey buddy. Let\'s meet for drinks later tonight.'));
            response.send();
        });
    });
});
The hostname is 'api.twilio.com'. Your SID and AUTH_TOKEN come from your twilio account. When you log in, go to the dashboard. You'll find your SID and AUTH_TOKEN listed there.
Here's the code I use to make a request to twilio to place a call. It should help you get started.
var https = require('https');
var qs = require('querystring');
var api = 'your api key';
var auth = 'your auth token';
var postdata = qs.stringify({
'From' : '+5554321212',
'To' : '+5552226262',
'Url' : 'http://yourwebsite.com/call'
});
var options = {
host: 'api.twilio.com',
path: '/2010-04-01/Accounts/<your api key>/Calls.xml',
port: 443,
method: 'POST',
headers: {
'Content-Type' : 'application/x-www-form-urlencoded',
'Content-Length' : postdata.length
},
auth: api + ':' + auth
};
var request = https.request(options, function(res){
res.setEncoding('utf8');
res.on('data', function(chunk){
console.log('Response: ' + chunk);
})
})
request.write(postdata);
request.end();

Resources