R httr MS Dataverse API: Bad Request (HTTP 400), Define scope - r

My question is closely related to this one: R httr Linkedin API: Bad Request (HTTP 400).
I have an application set up in Azure AD that I would like to use to get data out of MS Dataverse using R. I am new to APIs, so I first set it up in Postman. I was successful at getting to my data in Postman, but it did not require a Scope parameter.
I attempted to recreate what I did in Postman in R...
require(rvest)
dataverse_api = oauth_endpoint(request = NULL,
authorize = "REDACTED",
access = "REDACTED",
base_url = "REDACTED")
API.Key = "REDACTED"
API.Secret = "REDACTED"
App = oauth_app("EPS Project Development", key = API.Key, secret = API.Secret)
API.token = oauth2.0_token(dataverse_api, App)
This caused my browser to open and give me an error saying a scope was required. I have been searching through documentation to find nomenclature for scopes, but haven't been successful. I have found several documents (1, 2, etc.) that are somewhat peripheral that list options such as "ReadWrite.All" or "Files.ReadWrite.All", but my understanding is that these are permissions which are different from Scope. Because I don't know what I'm doing, I tried several of them as such:
require(rvest)
dataverse_api = oauth_endpoint(request = NULL,
authorize = "REDACTED",
access = "REDACTED",
base_url = "REDACTED")
API.Key = "REDACTED"
API.Secret = "REDACTED"
App = oauth_app("EPS Project Development", key = API.Key, secret = API.Secret)
API.token = oauth2.0_token(dataverse_api, App, scope = "User_impersonation")
The result is always the same. The browser opens with a message Authentication complete. Please close this page and return to R., but in R I get:
Waiting for authentication in browser...
Press Esc/Ctrl + C to abort
Authentication complete.
Error in oauth2.0_access_token(endpoint, app, code = code, user_params = user_params, :
Bad Request (HTTP 400). Failed to get an access token.
From the link I cited above as being a similar question, I understand that I am still missing the Scope parameter. But I do not know where to get the Scope parameter for MS Dataverse. Can anyone help with this?

I don't know if there are other options, but in case it's helpful to anyone else I was able to make it work by specifying the scope as the Dynamics 365 URL followed by .default. For me this looks like: https://org593dc393.crm4.dynamics.com/.default

Related

Error in Oauth2.0 authentication in R using HTTR (failed to connect: connection refused)

I am trying to create a simple app (in R) using GroupMe's API, which utilizes OAuth2.0. The documentation can be found here. However, I'm getting stuck on the first step of authentication/token generation for a user. See below for my code and the response I get:
access_key = ****
client_id = ****
gendpoint <- oauth_endpoint(
authorize = glue("https://oauth.groupme.com/oauth/login_dialog?client_id={client_id}"),
access = glue("http://localhost:1410/?access_token={access_key}")
)
gapp <- oauth_app(
"pingme",
key = client_id,
secret = access_key
)
t <- oauth2.0_token(
endpoint = gendpoint,
app = gapp
)
The above code is sufficient to bring in the login page, which presumably allows me to enter my credentials to obtain a token. However, when I enter my credentials, I get the following error message in R:
Authentication complete.
Error in curl::curl_fetch_memory(url, handle = handle) :
Failed to connect to localhost port 1410: Connection refused
So it looks like my authentication/login credentials worked, but somewhere an error prevented me from actually generating the token.
Could someone help me with this? This is my first time using the OAuth2.0 framework so I'm very confused. Thanks in advance!

Why does the httr package in r always give the same access token?

I have data in a Microsoft Dataverse that I'm attempting to pull into R. I don't have much background in software development / APIs / OAuth so I first used a tutorial that showed me how to work with APIs in Postman. I then used several tutorials online (most notably this one) to try to replicate what I'm doing in Postman. Doing so, I came up with the code below:
require(httr)
require(rvest)
dataverse_api = oauth_endpoint(request = NULL,
authorize = https://login.microsoftonline.com/REDACTED/oauth2/v2.0/authorize,
access = https://login.microsoftonline.com/REDACTED/oauth2/v2.0/token,
base_url = https://login.microsoftonline.com/common/oauth2/authorize?resourcehttps://org593dc393.crm4.dynamics.com)
API.Key = "REDACTED"
API.Secret = "REDACTED"
App = oauth_app("EPS Project Development", key = API.Key, secret = API.Secret)
API.token = oauth2.0_token(dataverse_api, App, scope = https://org593dc393.crm4.dynamics.com/.default)
API.AuthKey = API.token$credentials$access_token
GET.Buildings = GET(https://org593dc393.crm4.dynamics.com/api/data/v9.2/crfd0_dartbuildingses, add_headers(Authorization = paste("Bearer", API.AuthKey, sep = " ")))
The first day, the code above worked, and I was so excited! The next day, with no changes to the code, it returned a response of 401 (unauthorized). I've been going back and forth between Postman and R trying to figure out what's different, and what I realized is that every time I authenticate in Postman, I get a completely new access token (as expected); however, in R, when I keep running this code, the parameter stored in API.token$credentials$access_token is the same. I'm not really sure why this is.
Doing some more research, it seems like maybe I need a refresh token? I don't understand that because this is the same code other developers posted and no one else seems to be mentioning that it will only work once and then never again without a refresh token. Moreover, inspecting the documentation for httr makes it seem as if part of the oauth2.0_token function is to check whether or not the token needs to be refreshed. Anyway, when I look at the parameter API.token$refresh(), it tells me Error: Refresh token not available.
So now I'm attempting to get a refresh token, again without really understanding why. The documentation on the httr package details a function called oauth-refresh, but ?oauth-refresh gives an error and ?oauth_refresh says no results found. I also looked into this package by MatthewJWhittle that has a function called refresh_token, but again the help functions turn up no results after installing the package, so I guess it's no longer a valid package.
TLDR: Why is my code coming back with the same access token every time I request authorization? Did I miss a step in the code where I'm supposed to request a refresh token? Or if this is by design, how do I get a new one once this one expires?
It turns out I just needed to add cache = FALSE so that I'm not using cached tokens. If it's helpful to anyone, the full code is now:
require(httr)
require(rvest)
dataverse_api = oauth_endpoint(request = NULL,
authorize = https://login.microsoftonline.com/REDACTED/oauth2/v2.0/authorize,
access = https://login.microsoftonline.com/REDACTED/oauth2/v2.0/token,
base_url = https://login.microsoftonline.com/common/oauth2/authorize?resourcehttps://org593dc393.crm4.dynamics.com)
API.Key = "REDACTED"
API.Secret = "REDACTED"
App = oauth_app("EPS Project Development", key = API.Key, secret = API.Secret)
API.token = oauth2.0_token(dataverse_api, App, scope = https://org593dc393.crm4.dynamics.com/user_impersonation, cache = FALSE)
API.AuthKey = API.token$credentials$access_token
GET.Buildings = GET(https://org593dc393.crm4.dynamics.com/api/data/v9.2/crfd0_dartbuildingses, add_headers(Authorization = paste("Bearer", API.AuthKey, sep = " ")))

R httr Linkedin API: Bad Request (HTTP 400)

My question is closely related to this one: LinkedIn API error of redirect uri from httr
Here is my code:
library(httr)
clientid <- "MY-ID"
secret <- "MY-SECRET"
app <- oauth_app(appname = "app name", key = clientid, secret = secret)
endpoint <- oauth_endpoint(base_url = "https://www.linkedin.com/uas/oauth2",
authorize = "authorization", access = "accessToken")
token <- oauth2.0_token(endpoint = endpoint, app = app)
As I do this, the browser opens with the message Authentication complete. Please close this page and return to R.
In R I get this:
Waiting for authentication in browser...
Press Esc/Ctrl + C to abort
Authentication complete.
Error in oauth2.0_access_token(endpoint, app, code = code, user_params = user_params, :
Bad Request (HTTP 400). Failed to get an access token.
I use the client id and secret given to my app on https://www.linkedin.com/developers/ and I did set the redirect URL there to http://localhost:1410/.
I'm on Ubuntu 18.04, R version 3.6.3, httr version ‘1.4.2’.
I think you might be missing the scope argument in oauth2.0_token().
Examples of LinkedIn scopes you could use would be: scope = "r_organization_social" or scope = "rw_organization_admin".
So it could look like:
token <- oauth2.0_token(endpoint = endpoint, app = app, scope = "rw_organization_admin")
It depends on how much access you've got and what data you'd like to request through the API
I solved the problem changing :token <- oauth2.0_token(endpoint = endpoint, app = app, scope = "w_member_social")

OAuth2 authentication with R using httr

I am trying to read some data from the Polar Accesslink API. I have read the documentation and examples (I'm not that familiar with Python) as well as httr examples/demos of Oauth2.0:
https://www.polar.com/accesslink-api/#polar-accesslink-api
https://github.com/polarofficial/accesslink-example-python
Here is my code:
library(httr)
client_id <- rstudioapi::askForPassword()
client_secret <- rstudioapi::askForPassword()
# redirect_uri determined in registration to http://localhost:1410/
app <- oauth_app(appname = "polar_app",
key = client_id,
secret = client_secret)
endpoint <- oauth_endpoint(
request = NULL,
authorize = "https://flow.polar.com/oauth2/authorization",
access = "https://polarremote.com/v2/oauth2/token")
token <- oauth2.0_token(endpoint = endpoint,
app = app,
scope = "accesslink.read_all", # tested also without scope
use_basic_auth = T # tested both T and F
)
Last part of the code (token) produces the following error:
Waiting for authentication in browser...
Press Esc/Ctrl + C to abort
Authentication complete.
Error in oauth2.0_access_token(endpoint, app, code = code, user_params = user_params, :
Bad Request (HTTP 400). Failed to get an access token.
It opens browser with url localhost:1410/?state={STATE}&code={CODE} and says:
"Authentication complete. Please close this page and return to R."
Based on the API documentation and github Python examples, I can't figure out if I need to set some values for user_params or query_authorize_extra in oauth2.0_token.
Having the same issue. Sent a message off to support and they came back with making sure that you include header "Content-Type: application/x-www-form-urlencoded" and that the body gets sent as plain/raw text and contains "grant_type=authorization_code&code=<AUTHORIZATION_CODE>".
I have not tested this out but hoping it helps you out if you have not already found a solution

Quickbooks Online API Oauth2.0 using httr

I am trying to access the QuickBooks online API via R. Here is what I have so far:
library(httr)
library(httpuv)
endPoint <- oauth_endpoint(request = NULL,
authorize = "https://appcenter.intuit.com/connect/oauth2",
access = "https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer")
App <- oauth_app("Untitled",
key = "xxxx",
secret = "xxxxx",
redirect_uri = "http://localhost:1410/")
QBOtoken <- oauth2.0_token(endpoint = endPoint,
app = App,
scope = "com.intuit.quickbooks.accounting",
type = "code",
cache = T)
GET("https://sandbox-quickbooks.api.intuit.com/v3/company/193514718345164/query?query=Select * from Payment", config(token = QBOtoken))
When run the code above through QBOtoken, I go through the whole Oauth2.0 "dance" and get the response:
Waiting for authentication in browser...
Press Esc/Ctrl + C to abort
Authentication complete.
However, when I execute the GET command, it returns:
Error in self$credentials$access_token :
$ operator is invalid for atomic vectors
The .httr-oauth file that is generated is filled with 284 rows of 32 characters. Is that normal?
I have connected to the API via Postman and it generates an access token allowing me to execute queries like the GET request in my code. There is also an Oauth 2.0 playground on Intuit Developer. Somehow, in R, I am not getting the access token and refresh token.
Another concern, is that I am currently trying to connect to a development environment. For QuickBooks Online, the redirect URL can be the localhost in the development environment, but if I want to connect to the production company(my company) data I will need a https redirect URL. Will this be possible through R?
My ultimate goal for this project is for the script to automatically run on a nightly basis, connect to the API, and ETL the data into a Relational Database for reporting/analytics purposes. Any help would be greatly appreciated!
I did get this "functional," but it is by no means good code. Some of this, like storing tokens in a csv, is not best practice, just a band-aid to test the code.
I created a tokens.csv file in the structure:
"RefreshToken","AccessToken"
"<RefreshToken>","<AccessToken>"
Below is my script that retrieved customer data from the QBO api sandbox.
library(httr)
library(httpuv)
library(curl)
library(jsonlite)
library(base64enc)
#Client ID and Client Secret were retrieved from the online explorer
clientID <- "<ClientID>"
clientSecret <- "<ClientSecret>"
scope <- "com.intuit.quickbooks.accounting"
tokens <- read.csv("tokens.csv")
RefreshToken <- as.character(tokens$RefreshToken[1])
AccessToken <- as.character(tokens$AccessToken[1])
authorize <- base64enc::base64encode(charToRaw(paste0(clientID,":",clientSecret)))
oauth_refresh <- httr::POST("https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer",
add_headers('Content-Type'= "application/x-www-form-urlencoded",
'Accept'= 'application/json',
'Authorization'= paste0('Basic ',authorize)
),
body = list('grant_type'='refresh_token',
'refresh_token'=RefreshToken),
encode = "form")
oaJSON <- fromJSON(content(oauth_refresh, as = "text"))
RefreshToken <- oaJSON[["refresh_token"]][1]
AccessToken <- oaJSON[["access_token"]][1]
tokens <- as.data.frame(list('RefreshToken'=RefreshToken,'AccessToken'=AccessToken))
write.csv(tokens,file = "tokens.csv", row.names = F)
datas <- httr::GET("https://sandbox-quickbooks.api.intuit.com/v3/company/<ID>/query?query=SELECT%20%2a%20FROM%20Customer",
accept_json(),
add_headers('Authorization'= paste0("Bearer ",AccessToken))
)
#datas$status_code
j_son <- content(datas, as = "text")
customers <- fromJSON(j_son)
customer_df <- customers$QueryResponse$Customer
Hopefully this gets the ball rolling correctly for you. Let me know if you have any feedback!

Resources