Spotify API - Retrieving Valid Access Token in Google Apps Scripts - javascript

Here is the documentation for the Spotify API (I'm using the Implicit Grant Flow): https://beta.developer.spotify.com/documentation/general/guides/authorization-guide/#implicit-grant-flow
I'm trying to write a script in Google Sheets. I'm focussing on the basic setup, but I cannot seem to get the access token working.
SOLVED:
I'm currently receiving the following error (it seems like my
parameters for my fetch method aren't set properly):
"error":"unsupported_grant_type","error_description":"grant_type must be client_credentials, authorization_code or refresh_token"
SOLUTION:
The grant_type must be listed as a payload according to the Google
Scripts method UrlFetchApp.fetch (see updated code below)
--
SOLVED:
As you can see below I'm using the 'get' method when trying to get the
token (despite the documentation specifying 'post') because the post
method consistently returns a 405 error. I think this is the step I'm
screwing up on. I'm assuming that I'm not supposed to be using the
csrf_token as the access token.
SOLUTION:
https://accounts.spotify.com/token should have been
https://accounts.spotify.com/api/token
Updated working code below:
var fetchParams = {
'method':'post',
'payload':{'grant_type':'client_credentials'},
'headers':{'Authorization':authorization},
'muteHttpExceptions':true
}
var replaceResponse = UrlFetchApp.fetch('https://accounts.spotify.com/api/token', fetchParams);
var regExp = /access_token(.*?):/;
var contentText = replaceResponse.getContentText();
var access_token = contentText.slice(contentText.search('access_token')+15,contentText.search(',')-1);
var requestOptions = {
'headers':{'Authorization':'Bearer '+access_token},
'muteHttpExceptions':true
}
var finalResponse = UrlFetchApp.fetch('https://api.spotify.com/v1/tracks/4dhARBZ8YLvm8oRDnCIeXr', requestOptions);

I modified your script for retrieving access token by following curl -X "POST" -H "Authorization: Basic ZjM4ZjAw...WY0MzE=" -d grant_type=client_credentials https://accounts.spotify.com/api/token of the document. Can you please try this modified script?
var authorization = "Basic "+ Utilities.base64Encode('<client_id>:<client_secret>');
var fetchParams = {
method: 'post', // Modified
payload: {'grant_type': 'client_credentials'}, // Modified
headers: {'Authorization': authorization},
muteHttpExceptions: true
}
var replaceResponse = UrlFetchApp.fetch("https://accounts.spotify.com/api/token", fetchParams); // Modified
Logger.log(replaceResponse.getContentText())
Reference :
Client Credentials Flow
If the response message was changed, please tell me.

Related

How to assign bearer token to authorization header in javaScript

I'm trying to make a GET request from the instructure-canvas API that requires a bearer token. I'm able to do so via both Postman and a curl command they provided me with:
curl -H "Authorization: Bearer <ACCESS-TOKEN>" "https://canvas.instructure.com/api/v1/courses"
Both these methods work and I am returned with the proper json data. However, I was wondering if there exists a way of doing this same operation in JavaScript (with or without additional libraries/frameworks). Apologies if this is trivial, I am very new to working with API's.
If you're making the request from the browser, you can use the Fetch API. It'll look a little something like this:
const url = ""; // API URL
const token = ""; // API Token
const method = "GET"; // Request method, change for what's needed
fetch(url, {
method,
headers: {
"Authorization": `Bearer ${token}` // This is the important part, the auth header
}
}).then(res => res.json().then(console.log)).catch(console.error); // Do better handling here
Depending on the server setup, you may need additional headers. Also keep an eye on the console for errors relating to CORs, as once again they will differer depending on how the server has been configured.

how to solve not a valid key=value pair (missing equal-sign) in Authorization header error in GAS

I've been stuck in getting data with rest api in GAS and I have already put the Auth token on headers but I got error "〜〜〜〜 not a valid key=value pair (missing equal-sign) in Authorization header". Actually , I've already succeeded in getting this data in Python but I can not get it in GAS. I hope anyone gives me advice . Thank you so much.
I confirmed id_token is correct.
So my error is caused in var response1 = UrlFetchApp.fetch(data_endpoint, request1);
GAS
function myFunction() {
var login_endpoint = "API URL FOR TOKEN";
var params0 = {"adminId": "xxxxxx","password": "xxxxxxxx"};
var request0 = {
"method": "post",
"payload": JSON.stringify(params0),
};
var response0 = UrlFetchApp.fetch(login_endpoint, request0);
var data = JSON.parse(response0);
var id_token = data.Result.id_token;
// Logger.log(id_token);
var params1 = {'adminId': 'xxxxx','pgId': 'xxxxxxxxx','extraColumn': []};
var data_endpoint = "API URL FOR USER DATA";
var request1 = {
"method": "get",
'contentType': 'application/json',
"payload": JSON.stringify(params1),
"headers": {
"Authorization":'Bearer '+ id_token,
},
muteHttpExceptions : true
};
var response1 = UrlFetchApp.fetch(data_endpoint, request1);
Logger.log(response1);
}
Python
param0 = {"adminId": "xxxxx","password": "xxxxxxx"}
url0 = "API URL FOR TOKEN"
response_post = requests.post(url0, json=param0)
response_data = response_post.json()
id_token = response_data["Result"]["id_token"]
headers = {"Content-Type":"application/json", "Authorization":id_token}
param1 = {'adminId': 'xxxx','pgId': 'xxxxxxx','extraColumn': []}
url1 = "API URL FOR USER DATA"
response_get = requests.get(url1, json=param1, headers=headers)
response_get.encoding = 'UTF-8'
with open('./test.csv','w') as f:
f.write(response_get.text)
When I saw your python script which worked fine, I thought that the value of param1 is sent as "data" with GET method. In order to achieve this with Google Apps Script, payload is required to be used in the request body. But in this case, the request is automatically changed to POST method. It seems that this is the current specification of UrlFetchApp. By this specification, I guessed that in the current stage, your python script cannot be directly converted to Google Apps Script.
From your additional tests, at the API you want to use, it was found that POST method cannot be used. So, in the current stage, in order to use the API you want to use, I think that it might be required to sent the value of param1 as "data" with GET method.
Note:
For achieving your goal, for example, how about requesting it to Google issue tracker as the future request? Ref
Reference:
fetch(url, params)
When the official document of params is seen, it says as follows.
the payload (that is, the POST body) for the request. Certain HTTP methods (for example, GET) do not accept a payload. It can be a string, a byte array, a blob, or a JavaScript object. A JavaScript object is interpreted as a map of form field names to values, where the values can be either strings or blobs.

Access Token error - Graph API getting user profile

I'm using Microsoft graph API to get to login and get a users profile. I have the accessToken. Though I'm trying to get the profile of the user that I got the AccessToken with.
This is my code, am I missing anything here? Just need the users profile. Note: I'm using Cors anywhere through a proxy server, which has worked for getting the code and accessToken.
Thanks for your help!
I've tried adding the resource URL. I've tried changing the headers (you don't need body parameters for GET and DEL requests).
let auth =
"http://localhost:8080/https://graph.microsoft.com/v1.0/me?access_token=";
let client_id = "?client_id=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
let redirect_uri = "&redirect_uri=http://localhost:8100/";
let response = "&response_type=code";
let resource = "&resource=https://graph.microsoft.com";
let scope =
"&scope=openid+https://outlook.office.com/Contacts.read+offline_access";
let url =
auth + token + resource + client_id + redirect_uri;
//let url = 'http://localhost:8080/https://graph.microsoft.com/v1.0/me?access_token=' + token +"&resource=https://graph.microsoft.com";
this.http.get(url, {
headers: {
Authorization: "Bearer " + token,
"Content-Type": "application/x-www-form-urlencoded",
"Access-Control-Allow-Origin": "*",
resource: "https://graph.microsoft.com"
}
});
Expected: to take the AccessToken and get a user's profile like in Part 4 here.
You've got a number of things going on here.
You're specifying both scope and resource properties. These don't belong together. If you're using the v1 Endpoint then you should be using resource, if you're using the v2 Endpoint then you should be using scope. See Scopes, Not Resources in the documentation.
Your url is not correct. The actual URL should look like this for v1:
https://login.microsoftonline.com/common/oauth2/authorize?client_id={id}&scope=https%3A%2F%2Fgraph.microsoft.com&redirect_uri={uri}&response_type=code
or for v2, like this:
https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id={id}&scope=openid+user.read+contacts.read+offline_access&redirect_uri={uri}&response_type=code
Can't use http.get() for this. OAuth's Authorization Code grant starts by redirecting the user to this URL. It will then return the code you then POST back to the /token endpoint to retrieve the access_token and refresh_token.
You need the User.Read scope to retrieve a user's profile (or User.ReadBasic.All to retrieve other user's profiles).
I would recommend using the v2 Endpoint and starting here:
Microsoft v2 Endpoint Primer
Get access tokens to call Microsoft Graph
AAD v2 Endpoint Overview

Invalid input response and secret when verifying google reCaptcha

I am really struggling to get a successful response when doing a post request to the google recaptcha api. I am receiving the following response:
{
"success": false,
"error-codes": [
"invalid-input-response",
"invalid-input-secret"
]
}
I had a look at reCAPTCHA - error-codes: 'missing-input-response', 'missing-input-secret' when verifying user's response (missing details on POST) and followed the answer as closely as possible but with no success.
Here is my file below:
var request = require('request');
module.exports = {
verifyCaptcha: function(req, res) {
var secret = 'SECRET_KEY';
var response = JSON.stringify(req.body.response);
request({
url: 'https://www.google.com/recaptcha/api/siteverify',
method: 'POST',
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: `secret=${secret}&response=${response}`,
}, function (err, response, body) {
if (err) {
res.status(500).send({
error: "Could not verify captcha"
});
} else {
res.status(200).send({
message: body
});
}
});
},
}
If anyone has a solution to this problem please let me know!
Due to the docs: https://developers.google.com/recaptcha/docs/verify
invalid-input-secret: The secret parameter is invalid or malformed.
Maybe you have mixed the site_key and the secret_key.
You need to add the user remote IP address.
var user_ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
request({
url: 'https://www.google.com/recaptcha/api/siteverify',
method: 'POST',
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: `secret=${secret}&response=${response}&remoteip=${user_ip}`}...
Another thing I see that you are not using template literal, you should change the quotes to ` instead of '.
OR, You should use a ready-made module for reCaptcha, like this one:
https://www.npmjs.com/package/recaptcha
For reCAPTCHA Enterprise, check the official docs: https://cloud.google.com/recaptcha-enterprise/docs/create-assessment.
In short, you need to use the library that Google provides:
const { RecaptchaEnterpriseServiceClient } =
require('#google-cloud/recaptcha-enterprise');
const client = new RecaptchaEnterpriseServiceClient();
const [ response ] = await client.createAssessment({...});
RecaptchaEnterpriseServiceClient requires a service account to be created beforehand as described here. The key for that account with the right roles set can then be read by the app. Check the arguments of the constructor to see the available options to pass the data if the file cannot be retrieved automatically.
var response = JSON.stringify(req.body.response);
The stringifying here is probably the cause of the invalid-input-response error.
If your body is something like {"g-recaptcha-response": "..."}, you need to pull out the response value and pass that directly in your post.
Regarding invalid-input-secret, if you have set up your key and secret through the classic interface at https://www.google.com/u/1/recaptcha/admin/create, then you shouldn't have a problem.However if you set up a key with recaptcha Enterprise on Google Cloud, then it requires that you do Oauth authentication to the Google Cloud API and then use the create.assessment endpoint to get back information on the validity of the user. As Yuuhn implied, the Google provided library makes interaction with recaptcha Enterprise easier, without a lot of documentation digging to find where your REST API calls need to go.

User credentials required: Google Cloud Print Submit API

I am trying to access the Submit API that is apart of the Google Cloud Print however I am running into the error "User credentials required".
I am able to get all the way through authentication and am able to retrieve my access token. I was following this guide https://developers.google.com/cloud-print/docs/appDevGuide
I do not know where it is going wrong. Does anyone know where the credentials are supposed to be inputted?
Here is my code for this portion:
function submitPrintJob(token){
try{
var params = {'printerid':'PRINTER_ID','title':'Test Print Job','ticket':{"version": "1.0", "print": {}},'contentType':'application/pdf'};
var response = https.post({
url: 'https://www.google.com/cloudprint/submit',
body: params,
headers: {'Authorization':'Bearer ' + token}
});
log.debug('submitPrintJob','Response - ' + response.body);
}catch(e){
log.error('submitPrintJob','Error - ' + e.message);
}
}
This code is being in done in Netsuite which is where the https.post API is coming in. I also am aware that I am not sending a document through but I at least need to get past this step. I am getting this error using Postman as well.
Editing to add the portion where I get the token:
I send a request to: https://accounts.google.com/o/oauth2/v2/auth
Parameters:
response_type: code,
scope: https://www.googleapis.com/auth/cloud-platform.read-only,
state: state_parameter_passthrough_value,
redirect_uri: scriplet url
client_id: client id
Google oauth returns a authorization code. I exchange the code for a token this way:
function getToken(code){
try{
var params = {'code':code,'client_id':CLIENT_ID,'client_secret':CLIENT_SECRET,'redirect_uri':REDIRECT_URI,'grant_type':'authorization_code'}
var response = https.post({
url: 'https://www.googleapis.com/oauth2/v4/token',
body: params,
headers: {'Content-Type':'application/x-www-form-urlencoded'}
});
var token = response.body.access_token;
submitPrintJob(token);
}catch(e){
log.error('getAuthCode','Error - ' + e.message);
}
}
As I thought, the problem is how you are getting the access token. In order to get a valid access token to do your cloud print business, you need to include the proper scope. That means that your params object should like like this:
var params = {'code':code,'client_id':CLIENT_ID,'client_secret':CLIENT_SECRET,'redirect_uri':REDIRECT_URI, 'scope': 'https://www.googleapis.com/auth/cloudprint', 'grant_type':'authorization_code'}
This should give you a valid access token to interact with Google Cloud Print. I hope it helps!

Categories

Resources