Successful Login to API; Unsuccessful at accessing any data due to being unauthorized - api

I am attempting to come up with a live leaderboard for my local club using the PDGA's (Professional Disc Golf Association) API. I am writing a Google Apps Script intending to auto populate a Google Sheet with a Club Ranking that can be refreshed as needed.
Right now, all I am trying to do is make pull of data to ensure I am able to begin using the API, but I can't seem to do even that.
For reference, here are the only two resources I have to work with regarding this specific API:
PDGA REST API Authentication
PDGA REST API Services
I have got the original login to work using this code:
function apiLogin() {
var LoginUrl = 'https://api.pdga.com/services/json/user/login';
var LoginDetails = {
'username' : Username,
'password' : Password
};
var LoginRequest = {
'method' : 'post',
'Content-Type' : 'application/json',
'payload' : LoginDetails
};
var LoginResponse = UrlFetchApp.fetch(LoginUrl, LoginRequest);
var json = LoginResponse.getContentText();
var LoginData = JSON.parse(json);
Logger.log(LoginData);
var SessionID = LoginData['sessid'];
var SessionName = LoginData['session_name'];
var Tok = LoginData['token'];
var playerFetchPar = {
'method' : 'get',
'Cookie' : SessionID + '=' + SessionName
};
var PlayerResponse = UrlFetchApp.fetch('https://api.pdga.com/services/json/players?pdga_number=1',playerFetchPar); //ERROR
Logger.log(PlayerResponse);
};
It's the last part when I am trying to call on data from a player that I get the following error message:
Exception: Request failed for https://api.pdga.com returned code 403. Truncated server response: ["Access denied for user anonymous"] (use muteHttpExceptions option to examine full response)
I am guessing that my screw up is in my interpretion of the parameter Cookie from that second link. In the initial response to make sure I was logging in properly, I received a session_name and sessid but I can't seem to figure out what is expected from Cookie. I am sorry if the answer is obvious, but any help would be greatly appreciated!

The documentation says
Cookie: session_name=sessid
You've used
Cookie: sessid=session_name
Reverse it:
'Cookie' : `${SessionName}=${SessionID}`
And you need to send it as a header:
const playerFetchPar = {
method : 'get',
headers: {'Cookie' : `${SessionName}=${SessionID}`}
};

Related

Apps Script PUT API

My goal is to update an API using Apps Script but I cannot work out how to do it. For simplicity sake here is my code:
let APIkey = "...";
let url = "..."
newData = {"stock_status": "instock"}
//Update API
The problem is I do not know how to get any further. I have read the relevant docs to this API but to no avail and I couldn't find anything about put requests in the Apps Script docs.
Answer:
You need to use UrlFetchApp.
Example:
I don't know how your API accepts authentication, but assuming it accepts the key as a URL parameter then you can do something like:
let APIkey = "..."
let url = "..."
const newData = {
"stock_status": "instock"
}
var options = {
'method' : 'PUT',
'contentType': 'application/json',
'payload' : JSON.stringify(newData)
}
UrlFetchApp.fetch(`${url}?key=${APIkey}`, options);
You can read the full documentation on fetch here

Unable to generate OAuth 2.0 Access Token from Office365 via JavaScript

I'm trying to pull an access token from Office365's /token identity platform endpoint via OAuth 2.0 client credentials grant flow. I have my app registered, the client ID & secret, etc...
I can make the POST request in Postman and receive the access token without issue:
However, when I try the POST request via JavaScript (by way of Google Apps Script), I receive an error message: AADSTS900144: The request body must contain the following parameter: 'grant_type'
I've already Google'd this error and found a bunch of different solutions, and have tried implementing them to no avail. I imagine this has to do with the URL encoding, but cannot figure it out.
Code:
function getO365() {
// POST Request (To get Access Token)
var tenantID = 'longstringhere'
var appID = 'longstringhere'
var appSecret = 'longstringhere'
var graphScore = 'https://graph.microsoft.com/.default'
var url = 'https://login.microsoftonline.com/' + tenantID + '/oauth2/v2.0/token'
var data = {
'client_id': appID,
'scope': graphScore,
'client_secret': appSecret,
'grant_type': 'client_credentials'
};
var postOptions = {
'method': 'POST',
'headers': {
'Accept': 'application/json',
'Content-Type': 'application/x-www-form-urlencoded'
},
'body': data,
'redirect': 'follow'
};
var authToken = UrlFetchApp.fetch(url, postOptions);
}
The only real difference between my code and the JavaScript Fetch code I pulled off of Postman is:
var urlencoded = new URLSearchParams();
urlencoded.append("client_id", "longstringhere");
urlencoded.append("scope", "https://graph.microsoft.com/.default");
urlencoded.append("client_secret", "longstringhere");
urlencoded.append("grant_type", "client_credentials");
When I try to use URLSearchParams in Google Apps Script, I keep getting this error: ReferenceError: URLSearchParams is not defined
Any ideas? Thanks in advance!
This was resolved by changing 'body' to 'payload' for UrlFetchApp per the documentation. Edited code to reflect the change. Credit to #TheMaster for pointing out my mistake.
'payload': data,//from 'body': data,

How can I read the LtpaToken2 token from my XMLHttpRequest response?

I'm trying to debug another developers code which looks like this:
xhr.open("POST", url, true, this.state.userid, this.state.password);
xhr.withCredentials = true;
xhr.onload = () => {
console.log("here is our packet " + JSON.stringify(xhr));
if (xhr.status === 200) {
var test = xhr.getAllResponseHeaders();
var respoheader = JSON.stringify(xhr.responseHeaders);
var token = respoheader.substring(
respoheader.indexOf("LtpaToken2"),
respoheader.indexOf(
";",
respoheader.indexOf("LtpaToken2")
)
);
console.log("token is parsed ===" + token);
When I run this query from Postman I see two "Set-Cookie" headers added to the response, and one has the content "LtpaToken2=YpMnhu...", which is apparently what I need to grab. But when I run the code above, it does not include this header. I apparently need to grab this token for future calls to another API.
Can someone explain what I'm doing wrong? How can I capture this token, or how am I supposed to connect to another API without this token? As it seems to always be the case with IBM tech, I can find almost ZERO documentation about LtpaTokens.

Unable to get access Token linkedin Oauth

I know some will put comment like this post is duplicate of so many questions, but I've tried many ways to achieve Access Token in linkedin Oauth. Explaining what i tried.
1) I'm following it's official doc's Linkedin Oauth2
2) I'm successfully getting Authorization code from step 2 and passing that code to step 3 for exchanging Auth code for getting Access Token. But i'm getting following error
{"error_description":"missing required parameters, includes an invalid parameter value, parameter more than once. : Unable to retrieve access token : appId or redirect uri does not match authorization code or authorization code expired","error":"invalid_request"}
3) According to some links i need to set content-type in the header.Link which tells to set content-type is missing
4)Then i tried calling https://www.linkedin.com/uas/oauth2/accessToken this service instead of POSt to GET. And passing data as queryParams.
5) Some link says oauth code expires in 20 sec, So i've checked, i'm making call for access token in less that 1 sec.
6) And if i pass data in Body params like as below and used url as https://www.linkedin.com/uas/oauth2/accessToken
var postData = {
grant_type: "authorization_code",
code: authCode,
redirect_uri: 'https%3A%2F%2Foauthtest-mydeployed-app-url',
client_id: 'my_client_id',
client_secret: 'secret_key'
};
7) With Get call my url i tried
https://www.linkedin.com/uas/oauth2/accessToken?grant_type=authorization_code&code='+authCode+'&redirect_uri=https%3A%2F%2Foauthtest-mydeployed-app-url&client_id=my_client_id&client_secret=secret_key
Still i'm getting Error even though status code is 200, i'm getting that error(with GET api)
and If POSt by passing postData in body i'm getting bad request 400 status code
Not understanding why m I not getting access code. I've read many solutions.
Sharing code as requested.
sap.ui.define([
"sap/ui/core/mvc/Controller",
"sap/m/MessageToast"
], function (Controller, MessageToast) {
"use strict";
return Controller.extend("OauthTest.OauthTest.controller.View1", {
onPress: function (evt) {
var sPath =
'https://www.linkedin.com/uas/oauth2/authorization?response_type=code&client_id=my_client_id&redirect_uri=https%3A%2F%2Foauthtest-mydeployed-app-url&state=DCEeFWf45A53sdfKef424&scope=r_basicprofile';
window.location.href = sPath;
var oRouter = new sap.ui.core.UIComponent.getRouterFor(this);
oRouter.navTo("View2", {
"username": "Test"
});
MessageToast.show(evt.getSource().getId() + " Pressed");
},
//after user allows access, user will be redirected to this app with code and state in URL
//i'm fetching code from URL in below method(call is happening in max.569ms)
onAfterRendering: function () {
var currentUrl = window.location.href;
var url = new URL(currentUrl);
var authCode = url.searchParams.get("code");
if (authCode !== undefined && authCode !== null) {
var postData = {
grant_type: "authorization_code",
code: authCode,
redirect_uri: 'https%3A%2F%2Foauthtest-mydeployed-app-url',
client_id: 'my_client_id',
client_secret: 'secret_key'
};
/* var accessTokenUrl = 'https://www.linkedin.com/uas/oauth2/accessToken?grant_type=authorization_code&code=' + authCode +'&redirect_uri=https%3A%2F%2Foauthtest-mydeployed-app-url&client_id=my_client_id&client_secret=secret_key';*/
var accessTokenUrl = 'https://www.linkedin.com/uas/oauth2/accessToken';
$.ajax({
url: accessTokenUrl,
type: "POST",
beforeSend: function (xhr) {
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
},
data: postData,
success: function (data, textStatus, jqXHR) {
console.log(data);
alert('success');
},
error: function (jqXHR, textStatus, errorThrown) {
console.log(errorThrown);
alert('error');
}
});
}
}
});
});
Help will be appriciated..!!!
Finally I am happy to post my answer after so much search.
Every step I did is correct only, but one thing I was missing here like, Linkedin API doesn't supports CORS.
I tried implementing Javascript SDK, that works like charm. But API wasn't.
Then I found very helpful Link which says I need to implement Rest API from backend by allowing CORS, not from front end.
Make sure to follow all the points which I mentioned above in my post.
And for Allow CORS follow this link. You will get data but only basic profile of user according to LinkedIn Terms data can be accessible
Hope this post may help someones time to search more

What should I consider when I am doing an authentication process with a titanium app?

Hello it's my first time doing a sign in process in a mobile app with Titanium and I wonder what information should I save and the best practice to do it?
My server is configured in this way:
The server requires I send a user and password and if the information match it will provide a token session.
This is the code I use for signing in:
function signIn(e) {
//function to use HTTP to connect to a web server and transfer the data.
var sendit = Ti.Network.createHTTPClient({
onerror : function(e) {
Ti.API.debug(e.error);
alert('There was an error during the connection');
},
timeout : 100000,
});
//Here you have to change it for your local ip
sendit.open('POST', 'http://myserver');
var params = {
user : $.txtUsuario.value,
password : $.txtPassword.value
};
sendit.send(params);
//Function to be called upon a successful response
sendit.onload = function() {
var json = this.responseText;
var response = JSON.parse(json);
if (response.success == "true")
{
var landing = Alloy.createController("menu").getView();
$.index.close();
landing.open();
}
else
{
alert(response);
}
};
};
the code above is working, however I do not know how to manage the sign out. I would like my application works like the most apps do, e.g:
You sign in once and after that if you do not close the app you are able to continues using it and even making a request.
Thank you for any explanation.
It depends on your app requirements. for exemple if you will use the token in your app later you can save it as an AppProperty :
Ti.App.Properties.setString('token',yourTokenGoHere);
and in the app starting you can get it back :
var myToken = Ti.App.Properties.getString('token');
and then you can make a test for example if the token is still valid or not :
if(myToken === 'invalidtoken')
youSholdLogin();
else
youCanGoFurther();
and when the user disconnect rest the token to be invalid :
Ti.App.Properties.setString('token', 'invalidtoken');