Spotify WebAPI authorization - client credentials flow error invalid_client - node.js

Straight forward question, hopefully with a straight forward answer. I'm attempting to implement the client credentials flow via Node.js, using request. Here's my code
var request = require('request');
var payload = config.spotify.clientID + ":" + config.spotify.clientSecret;
var encodedPayload = new Buffer(payload).toString("base64");
var opts = {
url: "https://accounts.spotify.com/api/token",
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
"Authorization": "Bearer " + encodedPayload
},
body: "grant_type=client_credentials&scope=playlist-modify-public playlist-modify-private"
};
request(opts, function (err, res, body) {
console.log('error', err);
console.log('status', res.statusCode);
console.log('body', body);
});
No matter what I do, the response body is always
{"error":"invalid_client"}
I've tried making the request using curl, with the same outcome.
$ curl -X POST -H 'Authorization: Bearer <base64encoded client_id:client_secret>' -d 'grant_type=client_credentials&scope=playlist-modify-public playlist-modify-private' https://accounts.spotify.com/api/token
That would imply that it's a problem with the credentials. I'm definitely using the right clientID and clientSecret for my app, which leads me to believe that it's the encoding that's causing the problem.
Am I doing the encoding right? If so, what else might be the cause?

Replace
"Authorization": "Bearer " + ...
with
"Authorization": "Basic " + ...
and see if it works better.

Related

Discogs API : Can't get anything else than "401 You must authenticate to access this resource."

I did the Oauth flow like the docs says and got the oauth_token and the oauth_token_secret, then from my nodejs server I tried this request :
request.get({
headers: {
"User-Agent": "FooBarApp/3.0",
"Authorization": {
oauth_token:"my token",
oauth_token_secret: "my secret token",
"OAuth oauth_consumer_key":"mykey",
"oauth_nonce":Date.now(),
"oauth_signature":"mypass&",
"oauth_signature_method":"PLAINTEXT",
"oauth_timestamp":Date.now(),
"oauth_verifier":"users_verifier"
},
"Content-Type": "application/x-www-form-urlencoded"
},
url: "https://api.discogs.com/oauth/identity"
I also tried to remove all parameters in "authorization" except my two tokens but nohting work. Any clues ?
The documentation is wrong and Discogs is probably too lazy to update it. I've tried to send corrections for the docs to the technical team but it's a dead end.
Their authentication mechanism IS NOT OAuth 1.0 Revision A compliant even tho they advertise otherwise.
In the meantime, here are the headers you need to make an authenticated request:
const request = require('request');
const options = {
url: 'https://api.discogs.com/oauth/identity',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'OAuth oauth_consumer_key="YOUR_CONSUMER_KEY", oauth_nonce="' + Date.now() + '", oauth_token="OAUTH_TOKEN_RECEIVED_FROM_STEP_4", oauth_signature="YOUR_CONSUMER_SECRET&OAUTH_TOKEN_SECRET_RECEIVED_FROM_STEP_4", oauth_signature_method="PLAINTEXT", oauth_timestamp="' + Date.now() + '"',
'User-Agent': 'YOUR_USER_AGENT/1.0'
}
};
request(options, (err, res, body) => {
if (!err && res.statusCode == 200) {
console.log(JSON.parse(body));
}
});
Good luck !

Unable to exchange code for access token in node.js. Mailchimp API

I am trying to use OAuth2 with the Mailchimp API, and I am following their documentation to the letter, but I am unable to complete step 4. At this step, I exchange the code I received from the authorization screen for the token. Per the documentation, this can be done in curl like so:
curl --request POST \
--url 'https://login.mailchimp.com/oauth2/token' \
--data "grant_type=authorization_code&client_id={client_id}&client_secret={client_secret}&redirect_uri={encoded_url}&code={code}" \
--include
I attempted to convert this to work on node.js by writing this:
var dataString = 'grant_type=authorization_code&client_id=' + clientid + '&client_secret=' + clientsecret + '&redirect_uri=' + encodedurl + '&code=' + url.parse(req.url, true).query.code;
var options = {
url: 'https://login.mailchimp.com/oauth2/token',
method: 'POST',
data: dataString
};
function callback(error, response, body) {
if (!error) {
console.dir(JSON.stringify(body));
}
else{
console.dir(error);
}
}
request(options, callback);
When I make the request.debug = true, I see that I am getting a 400 error. The message sent to the console is a bunch of garbled characters though. When I use these same variables and endpoints to authenticate through Postman though, it works fine, so the issue is not with the variables or the API itself.
I am not entirely sure what I am doing wrong here. The request I am making seems almost identical what is written in curl in the documentation. So where am I going wrong?
Hmm, did you forget to define request?
var request = require("request");
Finally figured it out. The issue was in the header of the request. There are two ways to fix this. The first is to use "form" instead of "data". Request includes a "content-type: x-www-form-urlencoded" header automatically if the option "form" is used.
var options = {
url: 'https://login.mailchimp.com/oauth2/token',
method: 'POST',
form: dataString
};
I am not sure what header is used when the "data" option is used, or if no content-type is declared at all. Either way, if you choose to continue to use the "data" option, you can manually declare a content-type header. This is the second possible solution.
var options = {
url: 'https://login.mailchimp.com/oauth2/token',
method: 'POST',
headers:
{ 'Content-Type': 'application/x-www-form-urlencoded' },
body: dataString
};
After alot of tries, I figured out. You can use code only once. So make sure you use code you get from redirect URI only once.
With new code use this code
const dataString = "grant_type=authorization_code&client_id="+client_id+"&client_secret="+client_secret+"&redirect_uri="+redirect_uri+"&code="+req.body.code
var options = {
url: 'https://login.mailchimp.com/oauth2/token',
method: 'POST',
headers:
{
'Content-Type': 'application/x-www-form-urlencoded',
},
form: dataString
};
function callback(error, response, body) {
if (!error) {
let str = JSON.stringify(body)
res.setHeader("Content-Type", "application/json; charset=utf-8")
res.send(body)
}
else{
console.dir(error);
res.send(error)
}
}
request(options, callback);

Execute OAuth2 with the Mailchimp API in NodeJS

I've been following MailChimp's OAuth2 tutorial (https://developer.mailchimp.com/documentation/mailchimp/guides/how-to-use-oauth2/) but got stuck when making a post request with the code and secret/key params. The closest I've gotten is a 400 Bad Request response. My code:
var args = {
headers: { "Content-Type": "application/json" },
body: "grant_type=authorization_code&client_id=" + client_id + "&client_secret=" + client_secret + "&redirect_uri=" + encoded_url + "&code=" + req.query.code,
url: "https://login.mailchimp.com/oauth2/token"
};
var r = request.post(args, function(err, req, body){
console.log(err)
console.log(req)
})
Okay, I was running in to the same thing, and finally found it. My code was very similar to yours:
this.globals.request({
method: "POST",
uri: "https://login.mailchimp.com/oauth2/token",
form: {
grant_type: "authorization_code",
client_id: this.globals.mailchimp_client_id,
client_secret: this.globals.mailchimp_client_secret,
redirect_uri: encodeURIComponent(fullUrl),
code: req.query.code
}
},
function (error, response, body) {
if (error || response.statusCode !== 200) {
self.globals.logger.debug(self.moduleName, "getMailchimpToken", "Error " + response.statusCode + "(" + response.statusMessage + ") from mailchimp: " + error, true);
body = {};
}
self.globals.logger.debug(self.moduleName, "getMailchimpToken", "got body: " + JSON.stringify(body), false);
deferred.resolve(body);
});
The problem here, and I suspect with yours, is that you are using an encoded URL in the form data, but request will encode it again. When I looked at the querystring, I saw things like
&redirect_uri=http%253A%252F%252F
where the %s were being re-encoded. Changed encodeURIComponent(fullUrl), to just fullUrl, and it worked.
One important note that was not clear to me - the redirect_uri should be the same one used in the OAuth call, including the path. Note that per the Mailchimp docs, you can vary the path in the actual call from the redirect_url used when registering the app, which is where this can be important.

node.js proxy a request to third party server return bad request

am using the request module to proxy a request to a third party serve, i followed the documention but it seems am not building the request well so i get this error in the response BadRequest.
here is the code:
auth = "Basic " + new Buffer(username + ":" + password).toString("base64");
request.post(
{
url: url,
headers : {
"Authorization" : auth,
"Content-Type" : "application/json; charset=utf-8"
} ,
qs: params
}, function(err, response, body){
var resBody = qs.parse(body);
console.log('thats the body ',resBody);
});
note the end point is an https

Send email using Google API with only access token

I want to send an email through Google API without the unnecessary OAUTH2 parameters. I only have the access_token and the refresh_token of that user.
How can I send an email through Gmail API through a basic POST request in NodeJS, with Request npm plugin?
abraham is correct, but I just thought I'd give you an example.
var request = require('request');
server.listen(3000, function () {
console.log('%s listening at %s', server.name, server.url);
// Base64-encode the mail and make it URL-safe
// (replace all "+" with "-" and all "/" with "_")
var encodedMail = new Buffer(
"Content-Type: text/plain; charset=\"UTF-8\"\n" +
"MIME-Version: 1.0\n" +
"Content-Transfer-Encoding: 7bit\n" +
"to: reciever#gmail.com\n" +
"from: sender#gmail.com\n" +
"subject: Subject Text\n\n" +
"The actual message text goes here"
).toString("base64").replace(/\+/g, '-').replace(/\//g, '_');
request({
method: "POST",
uri: "https://www.googleapis.com/gmail/v1/users/me/messages/send",
headers: {
"Authorization": "Bearer 'access_token'",
"Content-Type": "application/json"
},
body: JSON.stringify({
"raw": encodedMail
})
},
function(err, response, body) {
if(err){
console.log(err); // Failure
} else {
console.log(body); // Success!
}
});
});
Don't forget to change the reciever and sender email address for the example to work.
There are two methods for attaching OAuth2 access_tokens to a Google API request.
Using the access_token query parameter like this: ?access_token=oauth2-token
Using the HTTP Authorization header like this: Authorization: Bearer oauth2-token
The second one is prefered for POST requests so the raw HTTP request for sending an email would look something like this.
POST /gmail/v1/users/me/messages/send HTTP/1.1
Host: www.googleapis.com
Authorization: Bearer oauth2Token
{"raw":"encodedMessage"}

Resources