AWS API in R - Added Authorization Header but getting InvalidSignatureException - r

I am trying to use AWS API in R. I am using R so that i can add it to an exisiting ShinyApp (which is a web application build in R).
This API: https://docs.aws.amazon.com/connect/latest/APIReference/API_GetCurrentMetricData.html
Using signature version 4:
https://docs.aws.amazon.com/general/latest/gr/signature-version-4.html
I have added the 'Authorization' details to the header as per AMZ documentation, and the exact header works perfectly in python, but strangely not in R and returns an error saying 'InvalidSignatureException'.
My guess is that i have got something wrong with the variables in the POST function. I've quite a few different arrangements of the POST variables to try and get it to work but nothing seems to help.
This is the python code which works:
import requests
url = "https://connect.eu-central-1.amazonaws.com/metrics/current/XXXXXXX"
payload = "{\r\n \"InstanceId\" : \"XXXXXXX\",\r\n \"Filters\" : {\r\n \"Queues\" : [\r\n \"XXXXXXX\",\r\n \"arn:aws:connect:eu-central-1:XXXXXXX:instance/XXXXXXX/queue/XXXXXXX\"\r\n ]\r\n },\r\n \"CurrentMetrics\" : [\r\n {\r\n \"Name\" : \"AGENTS_ONLINE\",\r\n \"Unit\" : \"COUNT\"\r\n },\r\n {\r\n \"Name\" : \"AGENTS_AVAILABLE\",\r\n \"Unit\" : \"COUNT\"\r\n },\r\n {\r\n \"Name\" : \"OLDEST_CONTACT_AGE\",\r\n \"Unit\" : \"SECONDS\"\r\n },\r\n {\r\n \"Name\": \"AGENTS_ERROR\",\r\n \"Unit\": \"COUNT\"\r\n }\r\n ]\r\n}\r\n "
headers = {
'Content-Type': "application/json",
'X-Amz-Content-Sha256': "XXXXXXX",
'Host': "connect.eu-central-1.amazonaws.com",
'X-Amz-Date': "20190724T162517Z",
'Authorization': "AWS4-HMAC-SHA256 Credential=XXXXXXX/20190724/eu-central-1/connect/aws4_request, SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=XXXXXXX",
}
response = requests.request("POST", url, data=payload, headers=headers)
print(response.text)
My attempt to write in R. (returns x-amzn-ErrorType: InvalidSignatureException)
library(httr)
library(jsonlite)
request_body_json <-
'{
"InstanceId" : "xxxxxxxxxx",
"Filters" : {
"Queues" : [
"xxxxxxxxxx",
"arn:aws:connect:eu-central-1:xxxxxxxxxx:instance/xxxxxxxxxx/queue/xxxxxxxxxx"
]
},
"CurrentMetrics" : [
{
"Name" : "AGENTS_ONLINE",
"Unit" : "COUNT"
},
{
"Name" : "AGENTS_AVAILABLE",
"Unit" : "COUNT"
},
{
"Name" : "OLDEST_CONTACT_AGE",
"Unit" : "SECONDS"
},
{
"Name": "AGENTS_ERROR",
"Unit": "COUNT"
}
]
}'
hdrs <- list(
'Content-Type'= "application/json",
'X-Amz-Content-Sha256'= "XXXXXXX",
'Host'= "connect.eu-central-1.amazonaws.com",
'X-Amz-Date'= "20190724T162517Z",
'Authorization'= "AWS4-HMAC-SHA256 Credential=XXXXXXX/20190724/eu-central-1/connect/aws4_request, SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date, Signature=XXXXXXX"
)
a <- POST(
url = "https://connect.eu-central-1.amazonaws.com/metrics/current/xxxxxxxxxx"
,do.call(add_headers,hdrs)
,verbose(info = TRUE)
,body = request_body_json
,encode = "json"
)

Fixed and added the authorisations steps in too.
# Librarys used
library(httr)
library(jsonlite)
library(aws.signature)
#gather variables
host <- "connect.eu-central-1.amazonaws.com"
sha <- "xxxx"
amzdate <- format(Sys.time(), "%Y%m%dT%H%M%SZ",tz = "UTC")
payload <-
'{
"InstanceId" : "xxxx-xxxx-xxxx-xxxx-xxxx",
"Filters" : {
"Queues" : [
"xxxx-xxxx-xxxx-xxxx"
]
},
"CurrentMetrics" : [
{
"Name" : "OLDEST_CONTACT_AGE",
"Unit" : "SECONDS"
},
{
"Name": "CONTACTS_IN_QUEUE",
"Unit": "COUNT"
}
]
}'
content_type <-"application/json"
url_api <-"https://connect.eu-central-1.amazonaws.com/metrics/current/xxxx-xxxx-xxxx-xxxx"
region <- "eu-central-1"
service <- "connect"
verb <- "POST"
action <- "/metrics/current/xxxx-xxxx-xxxx-xxx-xxxx"
key <- "xxxx"
secret <- "xxxx"
#headers so far (can't add signature yet)
hdrs <- list('Content-Type' = content_type,
Host = host,
'x-amz-content-sha256' = sha,
'x-amz-date' = amzdate)
#get v4 signature
sig <- signature_v4_auth(datetime = amzdate,
region = region,
service = service,
verb = verb,
action = action,
query_args = list(),
canonical_headers = hdrs,
request_body = payload,
key = key,
secret = secret,
session_token = NULL,
query = FALSE,
algorithm = "AWS4-HMAC-SHA256")
#add signature header to header
auth <- sig$SignatureHeader
a <- httr::VERB(verb = "POST"
,url = url_api
,encode = 'json'
,content_type_json()
,body = payload
,httr::add_headers(
'Content-Type' = content_type,
Authorization = auth,
Host = host,
`X-Amz-Content-Sha256` = sha,
`X-Amz-Date` = amzdate)
)
results <- content(a,"parsed")

Related

getting error when trying post tweet using httr and twitter PIN-based authorization

I am trying to post a new tweet from R using httr. But I am getting the following error:
{"errors":[{"code":32,"message":"Could not authenticate you."}]}
I am using the following code to authorize my app using PIN-based authorization
app <- oauth_app(
app = "",
key = "CONSUMER_KEY",
secret = "CONSUMER_SECRET"
)
create_oauth_signature <- function(url, method, oauth_app, token = NULL, token_secret = NULL, private_key = NULL, ...){
httr::oauth_header(
httr::oauth_signature(
url,
method,
app = oauth_app,
token,
token_secret,
private_key,
other_params = list(...)
)
)
}
get_authorization_url <- function(app, callback, permission = NULL){
response <- POST(
url = "https://api.twitter.com/oauth/request_token",
create_oauth_signature("https://api.twitter.com/oauth/request_token", "POST", app, oauth_callback = callback)
)
stop_for_status(response)
params <- httr::content(
response,
type = "application/x-www-form-urlencoded"
)
authorization_url <- modify_url(
"https://api.twitter.com/oauth/authenticate",
query = list(
oauth_token = params$oauth_token
)
)
return(list(authorization_url, params$oauth_token))
}
get_user_oauth_token <- function(verfier_code, token){
response <- POST(
modify_url(
url = "https://api.twitter.com/oauth/access_token",
query = list(
oauth_verifier = verfier_code,
oauth_token = token
)
)
)
return(response)
}
authUrl <- get_authorization_url(app, callback = "oob")
after this, I get authorization link from authUrl[[1]] and visit the link from my browser. Authorize the app and copy the code. Then use the get_user_oauth_token() to get the token and secret as follows:
token <- get_user_oauth_token("THE_CODE_FROM_TWITTER", authURL[[2]])
token <- content(token, type = "application/x-www-form-urlencoded")
Now I want to use the user's oauth_token and secret to post a tweet. I am following this documentation.
response <- POST(
url = modify_url(
url = "https://api.twitter.com/1.1/statuses/update.json",
query = list(status = "Hello")
),
create_oauth_signature("https://api.twitter.com/1.1/statuses/update.json", "POST", app, token = token$oauth_token, token_secret = token$oauth_token_secret),
content_type("application/json")
)
But I am getting the following error:
$`{"errors":[{"code":32,"message":"Could not authenticate you."}]}`
I am sure that the credentials are valid. Because If I use the same credentials with rtweet::post_tweet() it works just fine.
It would be so helpful if anybody could just point out what I am doing wrong.
Thanks in advance.

Converting a cURL command to HTTR in R

I have a cURL command that I would like to convert to R using the httr package. The cURL command looks something like this (I obviously can't post the full scope of it, given certain confidentiality restrictions):
curl --request POST \
--url https://api.cfb.com/v1/players/110960703/stats \
--header 'Accept: application/json' \
--header 'Authorization: Basic ThisIsWhereTheAPIKeyGoes==' \
--header 'Content-Type: application/json' \
--data '
{
"statsContext": {
"statsId": "1"
},
"responses": [
{
"type": "ReceiverStats",
"QuestionId": "466069",
"ResponseId": "1898226"
}
]
}
'
I would like to convert it to an HTTR script that looks like this:
ExportIdAPI <- POST(
'https://api.cfb.com/v1/players/110960703/stats',
accept_json(),
content_type_json(),
add_headers(Authorization = Basic ThisIsWhereTheAPIKeyGoes==),
encode = "json",
body=list(statsId = 1,
QuestionId = 466069,
ResponseId = 1898226))
The problem is, this script does not work. What does work is this script:
ExportIdAPI <- POST(
'https://api.cfb.com/v1/players/110960703/stats',
accept_json(),
content_type_json(),
add_headers(Authorization = Basic ThisIsWhereTheAPIKeyGoes==),
encode = "json",
body=list(statsId = 1))
Based on how the original curl request is structured, am I just not storing it right in the body=list statement?
EDIT: I should note that this script runs perfectly fine. I just don't want it to be structured that way and I would like it to better reflect the format I'm trying to achieve from above.
headers = c(
`Accept` = 'application/json',
`Authorization` = 'Basic ThisIsWhereTheAPIKeyGoes==',
`Content-Type` = 'application/json'
)
data = ' { "statsContext": { "statsId": "1" }, "responses": [ { "type": "SurveyResponse", "QuestionId": "466069", "ResponseId": "1898226" } ] } '
res <- httr::POST(url = 'https://api.cfb.com/v1/players/110960703/stats', httr::add_headers(.headers=headers), body = data)
EDIT 2: Based on MrFlick's response, I tried running:
ExportIdAPI <- POST(
'https://api.cfb.com/v1/players/110960703/stats',
accept_json(),
content_type_json(),
add_headers(Authorization = Basic ThisIsWhereTheAPIKeyGoes==),
encode = "json",
data = list(statsContext = list(statsId = 1), responses= list(list(type="SurveyResponse", QuestionId="466069", ResponseId="1898226")))
)
But I'm met with the following error:
Response [https://api.cfb.com/v1/players/110960703/stats]
Date: 2021-08-26 20:58
Status: 400
Content-Type: application/json; charset=utf-8
Size: 144 B
{
"errors": [
{
"code": "INVALID_PARAMETER",
"text": "The body of the request is null or cannot be parsed."
}
]
The httr documentation for the POST function provides an example for how to post a json.
In your case, you could really just copy the json of the cURL command to the body parameter of the POST function:
ExportIdAPI <- POST(
'https://api.cfb.com/v1/players/110960703/stats',
accept_json(),
content_type_json(),
add_headers(Authorization = 'Basic ThisIsWhereTheAPIKeyGoes=='),
body = '
{
"statsContext": {
"statsId": "1"
},
"responses": [
{
"type": "ReceiverStats",
"QuestionId": "466069",
"ResponseId": "1898226"
}
]
}', encode = "raw")
You can have the ROST() request format the JSON for you. As a general rule named lists are turned into JSON objects {} and unnamed list become arrays []. You can do
POST(
'https://api.cfb.com/v1/players/110960703/stats',
accept_json(),
content_type_json(),
add_headers(Authorization = "Basic ThisIsWhereTheAPIKeyGoes=="),
encode = "json",
body = list(
statsContext = list(
statsId = 1
),
responses= list(
list(
type="SurveyResponse",
QuestionId="466069",
ResponseId="1898226"
)
)
)
)

Cannot pass the POST request to Find query of mongolite and it returns null

library(jsonlite)
library(mongolite)
library(lubridate)
#' #post /predict
predict= function(x, y)
{
mongodatas <- mongo(collection='db12', url='mongodb://ganesh123:ganesh123456789#ds263137.mlab.com:63137/ganesh123')
naan <- mongodatas$find(query= '{ "data_time": {"$gte": "x" , "$lt": "y"} }',
fields= '{"_id": 0, "data_time": 1, "id": 1, "sensor3": 1 }',
sort= '{"data_time": 1}' ,
limit=5000
)
return(naan)
}
The above code is my R Api done using plumber and done using POST method and this works if the below postman input x and y is given as static in the find query
naan <- mongodatas$find(query= '{ "data_time": {"$gte": **"x"** , "$lt": **"y"**} }', "
{
"x": "2018-07-25 17:02:17.249591",
"y": "2018-07-25 17:02:17.674801"
}
The above code is my input to R Api
This is input from postman link http://localhost:3000/predict
"id": "1",
"data_time": "2018-07-25 17:02:17.249591",
"sensor3": "4.12"
This is my database structure. The query cannot process the input data.

How to Post API in R having header & json body

How to call API Post in R
Request URL
https://westus.api.cognitive.microsoft.com/text/analytics/v2.0/sentiment
Request headers
Ocp-Apim-Subscription-Key = some value &
Content-Type = application/json
Body application/json
{
"documents": [
{
"language": "string",
"id": "string",
"text": "string"
}
]
}
Please help!!!
Here is the example -
request_body <- data.frame(
language = c("en","en"),
id = c("1","2"),
text = c("This is wasted! I'm angry","This is awesome! Good Job Team! appreciated")
)
Converting the Request body(Dataframe) to Request body(JSON)
require(jsonlite)
request_body_json <- toJSON(list(documents = request_body), auto_unbox = TRUE)
Below we are calling API (Adding Request headers using add_headers)
require(httr)
result <- POST("https://westus.api.cognitive.microsoft.com/text/analytics/v2.0/sentiment",
body = request_body_json,
add_headers(.headers = c("Content-Type"="application/json","Ocp-Apim-Subscription-Key"="my_subscrition_key")))
Output <- content(result)
Show Output
Output

sending POST request to azure ML Web service using poster

I have successfully deployed a web service using Azure ML and am able to get output both on Azure ML as well as a sample R client application.
I would like to however get response using the firefox poster.
I have followed the instructions from the Azure page on deploying the web service and tried using the same request headers and parameters as follows
Instructions from azure page
this is what I've tried on Poster
Error message
My R Code which works
library("RCurl")
library("rjson")
# Accept SSL certificates issued by public Certificate Authorities
options(RCurlOptions = list(cainfo = system.file("CurlSSL", "cacert.pem", package = "RCurl")))
h = basicTextGatherer()
hdr = basicHeaderGatherer()
req = list(
Inputs = list(
"input1" = list(
"ColumnNames" = list("Smoker", "GenderCD", "Age"),
"Values" = list( list( "1", "M", "8" ), list( "1", "M", "8" ) )
) ),
GlobalParameters = setNames(fromJSON('{}'), character(0))
)
body = enc2utf8(toJSON(req))
api_key = "hHlKbffejMGohso5yiJFke0D9yCKwvcXHG8tfIL2d8ccWZz8DN8nqxh9M4h727uVWPz+jmBgm0tKBLxnPO4RyA=="
authz_hdr = paste('Bearer', api_key, sep=' ')
h$reset()
curlPerform(url = "https://ussouthcentral.services.azureml.net/workspaces/79f267a884464b6a95f5819870787918/services/e3490c06c73849f8a78ff320f7e5ffbc/execute?api-version=2.0&details=true",
httpheader=c('Content-Type' = "application/json", 'Authorization' = authz_hdr),
postfields=body,
writefunction = h$update,
headerfunction = hdr$update,
verbose = TRUE
)
headers = hdr$value()
httpStatus = headers["status"]
if (httpStatus >= 400)
{
print(paste("The request failed with status code:", httpStatus, sep=" "))
# Print the headers - they include the requert ID and the timestamp, which are useful for debugging the failure
print(headers)
}
print("Result:")
result = h$value()
print(fromJSON(result))
My API key
hHlKbffejMGohso5yiJFke0D9yCKwvcXHG8tfIL2d8ccWZz8DN8nqxh9M4h727uVWPz+jmBgm0tKBLxnPO4RyA==
How can I form a correct URL which works?
The "Content to Send" section is incorrect, you have specified URL-encoded, while you need to put application/json.

Resources