How to make a token request in R? - r

Trying to get an access token for an API so I can use R to pull the data. The documentation I'm using has the following instructions:
The following POST request shows the format of an Axon Evidence token request:
POST /api/oauth2/token HTTP/1.1
Host: api.evidence.com
Content-Type: application/x-www-form-urlencoded
grant_type: client_credentials&partner_id={partner ID}&client_id={client ID}&client_secret={client secret}
Note: ensure that you use URL-encoded forms for all parameter values. The client secret is base64 encoded and therefore usually end in an equals sign (=), which must be encoded as %3D. Additionally, if you use a manual REST client for testing, ensure that you know whether the client is automatically performing URL encoding. For more information, see Resources.
I'm trying to request a token using the httr package with the instructions above and it doesn't seem to be working. I'm using:
Token_Response <- POST("https://api.evidence.com/", body = "POST /api/oauth2/token HTTP/1.1
Host: api.evidence.com
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials&partner_id={partner ID}&client_id={client ID}&secret={client secret}")
Unfortunately I can't make this question reproducible for security reasons, but I'm hoping it's just a syntax problem on my end.

You don't usually work directly with the body or headers when using HTTR. The function can do most of the formatting of the request for you. A proper translation would look more like
url <- "https://api.evidence.com/"
partnerId <- "my partner ID"
clientId <- "my client ID"
clientSecret <- "my client secret"
token_Response <- POST(url,
encode="form",
body=list(
grant_type = "client_credentials",
partner_id = partnerId,
client_id = clientId,
secret = clientSecret
)
)
I used a few variables for clarity but you could put the values directly in the function call if you like.

Related

415 error when trying to access UMLS API via R vs Postman

I can successfully hit the endpoints for the UMLS authentication via Postman, but keep getting 415 errors when moving this code to R and using httr. This only seems to work when using x-www-form-urlencoded (as opposed to json).
My relevant Postman headers are:
Content-Type: application/x-www-form-urlencoded and
Accept: /*/
And trying to recreate this in R:
library(httr)
auth_endpoint <- "https://utslogin.nlm.nih.gov/cas/v1/api-key"
auth_headers <- c("Content-Type" = "application/x-www-form-urlencoded",
"Accept" = "*/*")
getTGT <- function(endpoint, headers) {
request_body <- list(apikey = "API_KEY_HERE")
request <- POST(url = endpoint,
headers = add_headers(.headers = headers),
body = request_body
}
This request is returning the 415 error which I can only tell is related to the Content-Type. I am more used to using JSON but that doesn't work in Postman either. Am I creating the request body correctly for a x-www-form-urlencoded type?
Finally figured this out - for x-www-form-urlencoded content, there needs to be encode = 'form' included in the POST call.

API access, Hashing query, possibly related to character encoding

Its going to be impossible to provide a reproducible example for this as it has to do with accessing a particular API - apologies in advance. I am trying to access the edinburgh fringe festivals API through R. The documentation says the following:
Authentication
An access key is required for all requests to the API and can be
obtained by registration. This key, combined with the signature
explained below, is required to get any access to the API. If you do
not provide an access key, or provide an invalid key or signature, the
server will return an HTTP 403 error.
Your secret token is used to calculate the correct signature for each
API request and must never be disclosed. Once issued, it is never
transmitted back or forward. The API server holds a copy of your
secret token, which it uses to check that you have signed each request
correctly.
You calculate the signature using the HMAC-SHA1 algorithm:
Build the full API request URL, including your access key but excluding the server domain - eg /events?festival=book&key=12345. See
the note below on URL encoding.
Calculate the hmac hash of the url using the sha1 algorithm and your secret token as the key.
Append the hex-encoded hash to your url as the signature parameter
URL encoding in queries
You should calculate the signature after URL-encoding any parameters -
for example, to search for the title "Mrs Brown" you would first build
the URL /events?title=Mrs%20Brown&key=12345 and then sign this string
and append the signature.
Signature encoding
Some languages - notably C# - default to encoding hashes in UTF-16.
Ensure your signature is encoded in plain ASCII hex or it will not be
valid.
What I have tried so far is below:
library(digest)
library(jsonlite)
source("authentication.R") # credentials stored here
create the query string
query <- paste0('/events?festival=demofringe&size=20&from=1&key=', API_KEY)
create the hashed query
sig <- hmac(SECRET_SIGNING_KEY, query, algo="sha1")
create the final url
url <- paste0('https://api.edinburghfestivalcity.com', query, '&signature=', sig)
submit to the API
results <- fromJSON(url)
and I get the error:
Error in open.connection(con, "rb") : HTTP error 417.
I'm not sure that the signature is ASCII encoded as per the documentation. Does anyone know how to debug this situation? I have tried iconv() to try and convert the encoding and when I call Encoding() on the character object it returns "unknown". I have also tried saving both files in RStudio with "save with encoding" set to ASCII and I have tried sourcing the authentications with encoding = "ASCII".
Incidentally when I paste the final url into a browser, I get the following error:
Invalid Accept header value. ['application/json', 'application/json;ver=2.0'] are supported
That's a server error. It should understand that
Accept: application/json, text/*, */*
Matches application/json. Note that instead of modifying jsonlite, it is beter to manually retrieve the response form the server, and then feed it to jsonlite.
library(httr)
library(jsonlite)
req <- GET(your_url, accept("application/json")
json <- content(req, as = 'text')
data <- fromJSON(json)
In the end, I solved this problem by editing the jsonlite::fromJSON() function. namely the line
curl::handle_setheaders(h, Accept = "application/json, text/*, */*")
I changed to
curl::handle_setheaders(h, Accept = "application/json")
I then also had to point to the internal functions with jsonlite:::. Now it works fine.

Paw base Oauth encoding

I am trying to do oauth 2 with Paw. It doesn't appear to be encoding my Client ID and Client Secret correctly. My server expects username:password format. I have tried it in the same field, separate, with same results.
Example
Input = VjE6MHJ:SjZvR24=
Base 64 encode result = `VmpFNk1ISjpTalp2UjI0PQ==
Paw result = VmpFNk1ISjpTalp2UjI0JTNE
The base 64 result works and returns a token, but Paw does not as it is encoded wrong.
It's a late answer, sorry! It seems like the only difference is that the = sign at the end of your password, is URL encoded by Paw, while your server doesn't expects a URL encoded value.
According to the OAuth 2 spec / 2.3.1. Client Password, we need to URL encode the Client ID and Client Secret. Then the question is, should we also encode the = sign? It's not very clear from the spec. Have you tested with other clients (maybe client implementation of OAuth, in JS/Swift/Python/Java)?

Curl -u equivalent in HTTP request

I've been trying to plug into the Toggl API for a project, and their examples are all using CURL. I'm trying to use the C# wrapper which causes a bad request when trying to create a report, so I thought I'd use Postman to try a simple HTTP request.
I can't seem to get the HTTP request to accept my API Token though. Here's the example that they give (CURL):
curl -u my-secret-toggl-api-token:api_token -X GET "https://www.toggl.com/reports/api/v2/project/?page=1&user_agent=devteam#example.com&workspace_id=1&project_id=2"
I've tried the following HTTP request with Postman with a header called
api_token with my token as the value:
https://www.toggl.com/reports/api/v2/project/?user_agent=MYEMAIL#EMAIL.COM&project_id=9001&workspace_id=9001
(changed ids and email of course).
Any help on how to use the CURL -u in HTTP would be appreciated, thanks.
The easy way is adding credential into url as user:pass# format.
https://my-secret-toggl-api-token:api_token#www.toggl.com/reports/api/v2/project/?page=...
<---------------------------------->
Alternately you can use credential with your http header like below:
Authorization: Basic XXXXXX
Here XXXXXX is base64(my-secret-toggl-api-token:api_token)
As explained to me in another post, you can pass the api token to the user property if you are using HttpWebRequest:
request.Headers.Add("Authorization", "Basic " + Convert.ToBase64String(System.Text.ASCIIEncoding.ASCII.GetBytes($"my-secret-toggl-api-token:api_token")));
Using fetch
In node environment, your request might look something like so:
const url = 'https://www.toggl.com/reports/api/v2/project/page=1&user_agent=devteam#example.com&workspace_id=1&project_id=2';
const token = 'my-secret-toggl-api-token:api_token';
fetch(url, {
method: 'GET', // not required
headers: {
Authorization: `Basic ${Buffer.from(String(token)).toString('base64')}`,
},
})

AccessToken for Windows Push Notifications returns Bad Request 400

PLEASE HELP!! Can't figure out why this simple code given by MSDN doesn't work....
I am using the following code in GetAccessToken() as given in the this MSDN article to get the access token to be used in windows notifications, but it returns "Bad Request 400"
PACKAGE_SECURITY_IDENTIFIER, CLIENT_SECRET are the values obtained when the app was registered with the Windows Store Dashboard
string urlEncodedSid = HttpUtility.UrlEncode(PACKAGE_SECURITY_IDENTIFIER);
string urlEncodedSecret = HttpUtility.UrlEncode(CLIENT_SECRET);
string body = String.Format("grant_type=client_credentials&client_id={0}&client_secret={1}&scope=notify.windows.com", urlEncodedSid, urlEncodedSecret);
string response;
using (WebClient client = new WebClient())
{
client.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
response = client.UploadString("https://login.live.com/accesstoken.srf", body);
}
Any help would be highly appreciated.......
I suspect the problem has to do with either an incorrect package identifier, and / or incorrect client secret.
From the MSDN page Push notification service request and response headers:
RESPONSE DESCRIPTION
--------------- --------------------------
200 OK The request was successful.
400 Bad Request The authentication failed.
Update - I ran the code from the question, using FAKE credentials.
Here is the RAW HTTP request:
POST https://login.live.com/accesstoken.srf HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Host: login.live.com
Content-Length: 88
Expect: 100-continue
Connection: Keep-Alive
grant_type=client_credentials&client_id=test&client_secret=test&scope=notify.windows.com
Here is the server's RAW response:
HTTP/1.1 400 Bad Request
Cache-Control: no-store
Content-Length: 66
Content-Type: application/json
Server: Microsoft-IIS/7.5
X-WLID-Error: 0x80045A78
PPServer: PPV: 30 H: BAYIDSLGN2A055 V: 0
Date: Thu, 21 Mar 2013 12:34:19 GMT
Connection: close
{"error":"invalid_client","error_description":"Invalid client id"}
You will note that the response is a 400. There is also some json that indicates the type of error. In my case, the error is Invalid client id. You probably want to take a look at your response - it will give you an indication of what happened.
I used Fiddler to debug the request/ response.
I found the reason for the error response. In fact it is the wrong PACKAGE_SECURITY_IDENTIFIER and CLIENT_SECRET.
DO NOT type the values. Because associated ASCII values differ. Therefore it is always better to copy and paste directly.
You will probably will get the access token with the simple code snippet.
Cheers
If you're using the new HttpClient API and you're sure you've copied and pasted the SID/secret values correct, you might be experiencing this issue because of encoding, provided you're using the FormUrlEncodedContent class as the content of your POST operation.
Contrary to the examples in the MSDN documentation, you don't want to URL encode the SID and secret values before adding them to the KeyValuePair collection. This is because encoding is implied by the FormUrlEncodedContent class, though I'm not seeing any documentation for this behavior. Hopefully this saves someone some time because I've been wrestling with this all night...

Resources