Twitter v2 API search endpoint "Field Authorization Error" - node.js

When requesting 'organic_metrics' field in Twitter v2 API search endpoint I am getting the following: "Field Authorization Error"
This is my request script in Nodejs
function requestSearch (keyword) {
const search = {
method: 'GET',
uri: 'https://api.twitter.com/2/tweets/search/recent',
headers: {
"User-Agent": "v2RecentSearchJS",
"authorization": `Bearer ${process.env.TWITTER_BEARER_TOKEN}`
},
qs: {
query: "context:66.1001503516555337728 context:66.857879456773357569" // `entity: ${keyword}`
},
json: true,
gzip: true
};
const params = {
"ids": "1397885797957738496", // Edit Tweet IDs to look up
"tweet.fields": "context_annotations,entities,organic_metrics", // Edit optional query parameters here
"user.fields": "created_at" // Edit optional query parameters here,
}
const lookup = {
method: 'GET',
uri: 'https://api.twitter.com/2/tweets',
headers: {
"User-Agent": "v2RecentSearchJS",
"authorization": `Bearer ${process.env.TWITTER_BEARER_TOKEN}`
},
qs: params
}
return rp(lookup)
.then(response => {
// console.log('API call response:', response);
return response
})
.catch((err) => {
console.log('API call error:', err.message);
});
}

According to the Twitter documentation:
Public metrics can be requested with OAuth 2.0 Bearer Token authentication. Non-public metrics can be requested for owned/authorized Tweets only. This means developers are required to authenticate using OAuth 1.0a User Context authorization. If you need to generate an access token and secret for the Tweet owner, you can do so with the 3-legged OAuth process.
[...]
Organic metrics: Grouping of public and non-public metrics attributed to an organic context (posted and viewed in a regular manner). Requires OAuth 1.0a User Context authentication.
In this case, you are using a Bearer Token to access the API, so you will not be able to access the organic metrics (this is what the "Field Authorization Error" message is telling you). You could use the public_metrics field instead.

Related

Spotify Web API Error 400: "Only valid bearer authentication supported"

I'm trying to use the Spotify Web API to search for songs through node, but it keeps sending me a status 400 error with the message: "Only valid bearer authentication supported". This is my code:
app.get("/", (req, res) => {
let searchurl = "https://api.spotify.com/v1/search?";
request.post(
{
url: searchurl,
data: {
q: "john",
type: "album",
},
headers: {
"Content-Type": "application/json",
Authorization:
"Basic " +
Buffer.from(client_id + ":" + client_secret).toString("base64"),
},
method: "POST",
},
function (e, r, body) {
console.log(body);
}
);
});
I don't understand what the issue is and have read through everything I could find, but got nowhere. Am I supposed to use a different access key?
Have a look at the Authorisation Guide for Spotify, you can use the Client Id and Client Secret to get an Access Token and it is that you send as part of an Authorization header when making the request to the Search for an Item endpoint you're trying to use

Spotify Authorization from Node Server not working with curl

I have a node server which gets an access token from Spotify's Web API. The response looks like this:
Response:
{
"statusCode": 200,
"body": "{\"type\":\"success\",\"done\":{\"json\":{\"access_token\":\"BQDqtYhVpafUIMYtZbwmy6iJcC_wvzR9Xrw6bRDFfpL3zZYfkCp2-KZaQVS-ZoElMF1czAl_B1vEaDrtPBOElSV3D5k\",\"token_type\":\"Bearer\",\"expires_in\":3600,\"scope\":\"user-top-read\"}}}",
"headers": {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Headers": "Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token"
}
}
When I try to use the access_token on Spotify's online API tool, I get an error for incomplete JSON. I think this is because the token I generate is only 91 characters long while the code they generate is 171 characters long. Why is my auth code so short?
I want an access token so I can use this react module for accessing my top tracks.
Here is my code for getting the access token:
let getAccessToken = (queryStringParameters) => {
let url = 'https://accounts.spotify.com/api/token';
let encoded = (new Buffer(client_id + ':' + client_secret).toString('base64'));
console.log("encoded = " + encoded);
let params = {
grant_type: 'authorization_code',
username: username,
password: password,
scope: scope
};
const formParams = Object.keys(params).map((key) => {
return encodeURIComponent(key) + '=' + encodeURIComponent(params[key]);
}).join('&');
return fetch(url, {
method: 'POST',
headers: {
"Authorization": 'Basic ' + encoded,
'Accept': 'application/json',
'Content-Type': 'application/x-www-form-urlencoded'
},
body: formParams
})
.then((response) => {
console.log(util.inspect(response, { showHidden: true, depth: null }));
return response.json();
})
.catch((error) => {
done({
error: error
});
});
};
According to the Authorisation Guide the authorization_code grant type only takes the code and redirect URI values. Not sure why the username and password ones you provide are even accepted, it is possible the token returned is a client credentials one as those tend to be shorter, that only access non-user related endpoints like loading Artist data, but the parameters you're providing appear to be undocumented at least in that guide.

Reddit gives 403 when upvoting via API

I've registered as the Web app as required by the Reddit API for the Oauth access with identity, edit, flair, history, modconfig, modflair, modlog, modposts, modwiki, mysubreddits, privatemessages, read, report, save, submit, subscribe, vote, wikiedit, wikiread scopes.
I'd authorized my app and have exchanged the generated code for the access_token with 3600 seconds validity.
'use strict';
let request = require('request');
const USER_AGENT = 'web:com.example.server:v0.0.1 (by /u/sridharrajs)';
const token = '<my access_token within 3600 seconds validity>';
request({
method: 'POST',
url: 'https://www.reddit.com/api/vote',
headers: {
'User-Agent': USER_AGENT,
'Authorization': `bearer ${token}`,
'Content-Type': 'application/x-www-form-urlencoded'
},
form: {
id: "t1_9qy47p",
dir: "1"
},
json: false
}, function (error, response, body) {
if (error) {
console.log('error', error);
} else if (body.error) {
console.log('body.error', body);
}
return console.log(body);
});
But when I try to upvote a reddit submission using API, I get an error.
{"message": "Forbidden", "error": 403}
The link that I'm trying to upvote is Tim Cook warns of ‘data-industrial complex’ in call for comprehensive US privacy laws
I tried switching both bearer and Bearer as per the answer in Reddit API returns HTTP 403, and tried using different User-Agent as suggested in 403 error when trying to get data from Reddit API. Nothing seem to work.
What am I missing?
Solved. I need to use https://oauth.reddit.com instead of www.reddit.com.
You may now make API requests to reddit's servers on behalf of that user, by including the following header in your HTTP requests:
Authorization: bearer TOKEN
API requests with a bearer token should be made to https://oauth.reddit.com, NOT www.reddit.com.

Configuring request to Google My Business API to avoid Unauthenticated error

I keep getting an unauthenticated error back when submitting my request to the Google My Business API in my Node.js app. The response:
{
"error": {
"code": 401,
"message": "Request is missing required authentication credential. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.",
"status": "UNAUTHENTICATED"
}
}
For what it's worth, I'm using the request-promise client to make the request. My function is below. I just received the access token, so I'm fairly certain that it's good, and I can see it through the err.options.Authorization log. I know the location ID doesn't exist yet, but I don't think that's what the error is telling me.
const request = require('request-promise');
...
function checkLocation (loc) {
return request({
method: 'GET',
uri: `https://mybusiness.googleapis.com/v4/accounts/${ACCOUNT_ID}/locations/${loc._id}`,
Authorization: `OAuth ${ACCESS_TOKEN}`
})
.then(function (response) {
console.log(response);
})
.catch(function (err) {
console.error(err.error, err.options.Authorization);
});
}
Is my request formatted incorrectly or am I not sending all I need to be?
Update: I left out possibly crucial information that this is through the one time authorization process for server-side apps like outlined here: https://developers.google.com/identity/protocols/OAuth2. My trouble is wrapped up in the sentence on that page, "After an application obtains an access token, it sends the token to a Google API in an HTTP authorization header."
Turned out my header wasn't formatted correctly. The Authorization key should be in a headers object:
{
method: 'GET',
uri: `https://mybusiness.googleapis.com/v4/accounts/${ACCOUNT_ID}/locations/${loc._id}`,
headers: {
Authorization: `OAuth ${ACCESS_TOKEN}`
}
}

Node/react best practice: How do I keep track on the current client/user in OAuth2 flow?

I'm a beginner with Node and React, and web programming in general. I want to import user credentials from LinkedIn's API and for that I need to authenticate using OAuth2.
My approach so far is to make an API-call from the client side to the LinkedIn oauth API with the relevant parameters, including a redirect URI which leads to an API endpoint on my node server. When the user has been redirected and approved LinkedIn's authentication dialog box, they will be redirected to the node server with an access token.
My question is as follows: I now want to update the user in my database with their corresponding access token, but how do I know which user to update when I can't get any information about the client in my function that handles the last redirect and fetches the access token?
Here's my node function that handles the redirect from LinkedIn:
router.get('/redirect', (req, res) => {
// Handle cancel by user
if(req.query.error){
console.log(req.query.error_description)
return
}
// Extract variables
const code = req.query.code
const state = req.query.state
// Check that state matches
if (state !== testState) {
console.log("State doesnt match")
return
}
// Exchange Authorization Code for an Access Token
var options = {
method: 'POST',
url: 'https://www.linkedin.com/oauth/v2/accessToken',
form: {
client_id: 'theClientID',
client_secret: 'theClienSecret',
grant_type: 'authorization_code',
code: code,
redirect_uri: 'http://localhost:3000/api/linkedin/redirect'
},
headers:
{ 'cache-control': 'no-cache',
"content-type": "application/json",
'user-agent': 'node.js' },
json: true };
// make the actual request
request(options, (error, response, body) => {
if (error) {
res.status(500).json({
message: error
})
return
}
// Extract access token
const token = body.access_token;
// Here I want to save access token to DB with the corresponding
// user, but I don't know which user to update
})
// Redirect user to profile
res.writeHead(301, {
Location: 'http://localhost:3000/profile'
})
res.end()
})
I had a really hard time formulating this question but I hope that my message gets through.

Resources