I am trying to use survey monkey APIs to pull data from a survey we launched last week but I keep getting error. I already registered an app in the developer portal. I added 'OAuth Redirect URL' in this format "https://api.surveymonkey.com/oauth/authorize?response_type=code&redirect_uri=https%3A%2F%2Fapi.surveymonkey.com%2Fapi_console%2Foauth2callback&client_id=SurveyMonkeyApiConsole&api_key=u366xz3zv6s9jje5mm3495fk" as mentioned in Survey Monkey OAuth developer Cheat Sheet (https://gist.github.com/api-admin/11302313). I also set scopes and marked app status as 'public'.
Here is my code to call an API .
import requests
url = "https://api.surveymonkey.net/v3/surveys/%s?api_key=%s" % (survey_id, YOUR_API_KEY)
s = requests.Session()
s.get(url).text
This is the error I get.
Out[41]: u'{"error": {"docs": "https://developer.surveymonkey.com/api/v3/#error-codes", "message": "The authorization token was not provided.", "id": "1010", "name": "Authorization Error", "http_status_code": 401}}'
What else needs to be done to download data using APIs? I am using SELECT annual plan subscription.
You need to set the access token in the header. I just checked the example in the docs and that is missing. The docs should be fixed.
OAuth example is here. So for that request in particular you'll need to do:
headers = {
'Content-Type': 'application/json',
'Authorization': 'bearer ACCESS_TOKEN_HERE'
}
s.get(url, headers=headers)
That should work for you.
Related
I need to read and import google people contacts but I get the following error:
"Request had invalid authentication credentials. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project."
"status": "UNAUTHENTICATED"
This is the script (classic asp) I am using:
StrURL="https://people.googleapis.com/v1/people/get"
ApiKey="my api key"
Set objXMLHTTP = CreateObject("Msxml2.ServerXMLHTTP.6.0")
objXMLHTTP.Open "GET", StrURL, False
On Error Resume Next
objXMLHTTP.setRequestHeader "Authorization", "Bearer " & ApiKey
If Err.Number<>0 Then Response.Write "Error:" & Err.Description & "<br>"
On Error GoTo 0
objXMLHTTP.send
content = CStr(objXMLHTTP.ResponseText)
statuscode = objXMLHTTP.Status
How can I get the token using classic asp? Can anyone help me?
objXMLHTTP.setRequestHeader "Authorization", "Bearer " & ApiKey
You appear to be sending an api key. An api key is not a bearer token. Api keys only grant you access to public data, not private user data.
In order to access private user data you need to request authorization from that user to access that data that is done using Oauth2
Once you have been grated consent of the user to access their data you will have an access token. This access token can then be sent to the api in the authorization header.
I haven't used asp classic in years. These videos may help you understand how to make the authorization request.
Google 3 Legged OAuth2 Flow
How to create web app credetinals
Understanding oauth2 with curl
I am trying to get the media_id for a media upload. See docs here.
When using postman, my request is processed successfully and I get a response like this:
{
"media_id": 1222234872222222401,
"media_id_string": "1222734822222102201",
"expires_after_secs": 86399
}
Unfortunately, using postman for our app is not an option. However, when I post a tweet with just text, the tweet is posted successfully using our own native code. I have also recreated the request from postman, and can successfully recreated the same oauth_signature needed for the media upload authorization. So I know that the backend is working in that I can create valid credentials, but I think I need some help structuring the POST request itself.
Here is the code (Lucee ColdFusion):
mediaEndpoint = "https://upload.twitter.com/1.1/media/upload.json?command=INIT&total_bytes=10240&media_type=image/jpg&oauth_consumer_key=consumerKeyHere&oauth_token=tokenHere&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1653075352&oauth_nonce=UU5V18WLaPN&oauth_version=1.0&oauth_signature=verifiedSignature";
cfhttp(url=mediaEndpoint, method="POST", result="init") {
cfhttpparam(type="header", name="Content-Type", value="application/x-www-form-urlencoded");
cfhttpparam(type="header", name="Accepts", value="*/*");
cfhttpparam(type="header", name="Accept-Encoding", value="gzip, deflate, br");
cfhttpparam(type="header", name="Connection", value="keep-alive");
cfhttpparam(type="body", value="command=INIT&media_type=#mediaParameters.media_type#&total_bytes=#mediaParameters.total_bytes#");
}
But I keep getting the following 401:
{"errors":[{"code":32,"message":"Could not authenticate you."}]}
I believe you're supposed to send your authorization token in the header. You're sending it in the URL as a query string. Twitter's documentation would indicate you need to include an authorization header as such:
cfhttpparam(type="header", name="Authorization", value="Bearer: #YourAccessToken#");
I'm adding the ability to post todos to my Todist list via a simple app. At the moment I am getting the response "error"=>"invalid_grant" when exchanging my code for an access_token.
I'm unsure exactly what 'invalid_grant' is referring too in this context. Other answers I find seem to be regarding various Google APIs. The Todoist API documentation makes no mention of it.
The post request for token exchange is:
uri = URI('https://todoist.com/oauth/access_token')
result = Net::HTTP.post_form(uri, client_id: ENV['TODOIST_CLIENT_ID'], client_secret: ENV['TODOIST_CLIENT_SECRET'], code: params[:code])
json_body = JSON.parse(result.body) # <- prints error
Any help understanding and solving this is much appreciated.
Update
After reading Takahiko Kawasaki's answer, I have updated the request to the following, but have the same error message.
uri = URI('https://todoist.com/oauth/access_token')
data = {
:client_id => ENV['TODOIST_CLIENT_ID'],
:client_secret => ENV['TODOIST_CLIENT_SECRET'],
:code => params[:code],
:grant_type => 'authorization_code',
}
result = Net::HTTP.post_form(uri, data)
json_body = JSON.parse(result.body)
Add the following.
grant_type: 'authorization_code'
See RFC 6749, 4.1.3. Access Token Request for details.
Additional comment for the revised question.
It seems that the OAuth implementation by Todoist is not mature. I took a look at their API document and soon found some violations against RFC 6749.
For example, (1) scopes must be delimited by spaces but their document says commas should be used. (2) Their token endpoint does not require the grant_type request parameter, which is required by the specification. (3) The value of the error parameter in the response from a token endpoint should be invalid_grant when the presented authorization code is wrong, but their API document says the value will be bad_authorization_code, which is not an official value.
In addition, this is not a violation, but the specification of their API to revoke access tokens implies that they don't know the existence of the official specification for access token revocation, RFC 7009.
For public clients (RFC 6749, 2.1. Client Types), e.g. smartphone applications, the client_secret request parameter of a token endpoint should be optional, but their API document says it is required.
Because their OAuth implementation does not comply with the specification, it would be better for you to ask Todoist directly.
The latest version of the Todoist API (v8) does not require the grant_type parameter so this is not currently the issue.
Two possible reasons for receiving the invalid_grant error are:
The code was not used within a certain length of time and has expired
The code has already been used to generate an access token and so is no longer valid
In both cases, generating a new code before making the POST request should sort the problem.
I am having a hard time understanding Oauth verification. I'm trying to use bing's search api. They request oauth verification. I have a primary key that they gave me. The issue I am running into it how to make a request, providing the oauth verification key.
For example, if I try to make a get request by the following:
http//api.datamarket.azure.com/Bing/Search?Query=%27xbox%27
I receive an error
The authorization type you provided is not supported. Only Basic and OAuth are supported
So the question is, do I embed my key into the URL, something like
http//api.datamarket.azure.com/Bing/Search?Query=%27xbox%27&authetication="myautherizationkey"
How do I provide my credentials in order to access their api?
This isn't a complete answer, because I'm still getting a "401 Unauthorized" error, but here is how I configured my OAuth for AngularJS. This is for a Bing image search.
var accountKey = '/*Your Account Key*/';
var base64EncodedKey = btoa(accountKey);
$http({
method: 'GET',
url: 'https://api.datamarket.azure.com/Bing/Search/v1/Image?Query=%27Pizza%27&$format=JSON',
headers: {'Authorization': 'Bearer ' + base64EncodedKey}
}).success(function(json) {
console.log('Returned: ' + JSON.stringify(json));
}).error(function(err) {
console.log('There was an error retrieving the image JSON: ' + err);
});
This at least gets rid of the authorization type error, but I still seem to have an error with the way I am providing the account key. Hope it helps point you in the right direction!
I have an app that uploads Video to YouTube to a specific YouTube channel (meaning, not to any individual user's channel, but to a single channel, for which I have the Username and Password).
In the ClientLogin my server-side process provided YouTube with the U/P and everything moved ahead. However, that's being deprecated and I'm looking to upgrade to OAuth 2.0 (as per their recommendation), however, the documentation insists on there being a redirect URI, for when the user has logged in. It doesn't seem to explain how to bypass the user login (since the user has nothing to log into, or any credentials to log in *with... the app is designed to take their video and upload it to OUR channel). So, what I need is to bypass the user being asked anything, and for YouTube to simply take my channel credentials and give me back the token for me to do the upload with.
I realize that this is a totally standard and non-controversial procedure, so I *MUST be missing something obvious, but I just can't suss out what that is.
So, my question is, how do I skip the user dialog-> redirect and just provide youtube with credentials for it to accept and then upload my video in OAuth 2.0?
What I'm really after is to do follow the DirectUpload approach here:
https://developers.google.com/youtube/2.0/developers_guide_protocol#AuthSub_Authentication_Flow
And to have retrieved the user Token silently behind the scenes.
TIA
There really is no way (that I've found) to completely bypass visiting an external page to authorize the OAuth2.0 access.
The closest I have come is to create an "Installed Application" project on code.google.com/apis/console and use the device methodology.
You will receive a Client ID and Client Secret. These will be used later.
Ideally you would generate a developer key, though I don't believe this to be required at this time, through code.google.com/apis/youtube/dashboard/
I use JSON notation for headers and responses, it should be easy to adapt to your language of choice.
First make a POST request to accounts.google.com/o/oauth2/device/code with the headers
{
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': post_data.length,
'X-GData-Key': 'key=YOUR_DEVELOPER_KEY'
}
and the data containing:
{
client_id: 'YOUR_CLIENT_ID',
scope: 'https://gdata.youtube.com'
}
where YOUR_CLIENT_ID is the client ID you obtained for the google apis project you set up earlier.
You will get a response like this:
{
"device_code" : "4/Pj8m71w5XuEMTT0ZwOJVgvlTfF4Q",
"user_code" : "5wtw67wm",
"verification_url" : "http://www.google.com/device",
"expires_in" : 1800,
"interval" : 5
}
If you don't visit www.google.com/device (defined by the "verification_url" field) within 30 minutes (1800 seconds per the "expires_in" response field), you will have to perform this first request again.
On the www.google.com/device page, you will be asked to login if you aren't already and then enter the verification code (defined by the "user_code" response field). You will be presented with a request to authorize the application and a list of permissions the app is requesting.
You want to store (at least temporarily) the value for the "device_code" field. This will be used when requesting an access token and refresh token.
Now that the permission has been granted, we can request an access/refresh token pair. This only needs to happen once provided you store the refresh token.
To request the access/refresh token pair you must make a POST request to accounts.google.com/o/oauth2/token with the headers
{
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': post_data.length,
'X-GData-Key': 'key=YOUR_DEVELOPER_KEY'
}
and the data
{
client_id: 'YOUR_CLIENT_ID',
client_secret: 'YOUR_CLIENT_SECRET',
code: 'YOUR_DEVICE_CODE',
grant_type: 'http://oauth.net/grant_type/device/1.0'
}
The response will look like this
{
"access_token" : "YOUR_ACCESS_TOKEN",
"token_type" : "Bearer",
"expires_in" : 3600,
"refresh_token" : "YOUR_REFRESH_TOKEN"
}
This specifies that the access token expires in 3600 seconds (60 minutes) and what your current access token is and what the refresh token is.
You want to store the access token for use with your current session and the refresh token for future sessions.
When making an API request, you will want to include the access token in the Authorization header field as well as including the developer key as we have been all along.
For uploading a video, I used these headers:
{
'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
'X-GData-Key': 'key=YOUR_DEVELOPER_KEY',
'Slug': 'video.mp4',
'Content-Type': 'multipart/related; boundary="f897a6d"',
'Content-Length': post_length,
'Connection': 'close'
}
You can refresh your access token at any time, not just when the old one expires. To refresh your access token, you make a POST request to accounts.google.com/o/oauth2/token with the headers
{
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': post_data.length,
'X-GData-Key': 'key=YOUR_DEVELOPER_KEY'
}
and the data
{
client_id: 'YOUR_CLIENT_ID',
client_secret: 'YOUR_CLIENT_SECRET',
refresh_token: 'YOUR_REFRESH_TOKEN',
grant_type: 'refresh_token'
}
You will get a response like this
{
"access_token" : "YOUR_NEW_ACCESS_TOKEN",
"token_type" : "Bearer",
"expires_in" : 3600
}
where YOUR_NEW_ACCESS_TOKEN is the new token for you to use in your future requests.