When trying the live API explorer and using my api key I can get a good response. However when using the same URI link generated from the explorer within my application, I get a 403 error. However, the application makes only 1 request.
url = URI.parse("http://api.espn.com/v1/sports/basketball/nba/athletes/355?
apikey=xxxxxxxxxxxxxxxx")
req = Net::HTTP::Get.new(url.path)
res = Net::HTTP.start(url.host, url.port) {|http|
http.request(req)
}
puts res.body
Here's the response in the terminal:
{
"status": "error",
"code": 403,
"message" : "Account Inactive"
}
403 should mean I'm exceeding my limit, but the message says Account Inactive. This is a new account and I got confirmation that it was active. Plus my API key works in the web interface.
Any ideas?
Related
I'm currently creating a Twitter bot in Ruby. This bot must tweet the result of a web scraping everyday. Everything works perfectly but I have a problem with the API part. I got all of my API keys from Twitter and I can tweet from Postman. I got the request directly from Postman but for some reason, when I try to execute my script in my terminal, I got this message :
{
"title": "Unauthorized",
"type": "about:blank",
"status": 401,
"detail": "Unauthorized"
}
I'm currently testing my script from my terminal but it will be executed from heroku with the scheduler in the future.
Do you understand where the problem comes from? I read that I might need to create callbacks URL in Twitter Dashboard but I have no idea what I need to enter as I'm testing my script in the terminal.
Thanks :)
Here's my script (I skipped the scraping part):
require "json"
require "net/http"
require "open-uri"
require "nokogiri"
#Tweeting result
url = URI("https://api.twitter.com/2/tweets")
https = Net::HTTP.new(url.host, url.port)
https.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = "OAuth oauth_consumer_key='#{ENV['CONSUMER_KEY']}',oauth_token='#{ENV['ACCESS_TOKEN']}',oauth_signature_method='HMAC-SHA1',oauth_timestamp='1644297052',oauth_nonce='yxABTHBJyWM',oauth_version='1.0',oauth_signature='pWxeExVF46ueXyblWfz4vzzuRCg%3D'"
request["Content-Type"] = "application/json"
request["Cookie"] = "guest_id=v1%3A164429705219615684"
request.body = JSON.dump({
"text": "Nombre d'adhérents : #{total}"
})
response = https.request(request)
puts response.read_body
I've been using the code below to call a third party API . This code works fine (i've changed the url and the credentials but the structure of the code is the same) :
require 'base64'
require 'httparty'
require 'json'
######################################################################
# Get the token first
######################################################################
consumer_key = "my_key"
consumer_secret = "my_secret"
credentials = Base64.encode64("#{consumer_key}:#{consumer_secret}").gsub("\n", '')
url = "https://mysite/token"
body = "grant_type=client_credentials"
headers = {
"Authorization" => "Basic #{credentials}",
"Content-Type" => "application/x-www-form-urlencoded;charset=UTF-8"
}
r = HTTParty.post(url, body: body, headers: headers)
bearer_token = JSON.parse(r.body)['access_token']
######################################################################
# Use the token in a call as authorisation header
######################################################################
api_url = "https://apisite/the_value_i_am_looking_for_in_the_api"
url = URI.parse(api_url)
req = Net::HTTP.new(url.host, url.port)
req.use_ssl = true
# If we are just passing a key that doesn't need to be in the token format
headers = {
'Authorization' => "Bearer #{bearer_token}"
}
# Get the response back (he data is in the response body: resp.body )
resp = req.get(url, headers)
My issue is that the API providers have changed their API so you now need to pass an "accept" into the call via the header. I used POSTMAN to make the call, added the accept to the header and was able to get it working without issue. So far so good.
I then changed my ruby code to extend the headers section to include the accept, using the code below:
headers = {
'Authorization' => "Bearer #{bearer_token}",
'Accept' => 'application/vnd.bluebadge-api.v1+json'
}
I've not added an accept to a header before so I may have gotten the syntax wrong.
However, this returns an unauthorised 401 response code:
#<Net::HTTPUnauthorized 401 Unauthorized readbody=true>
I thought I might have the credentials wrong so remove the accept, try again and this changes to a 406 response code:
#<Net::HTTPNotAcceptable 406 Not Acceptable readbody=true>
If I examine the response I get the message I would expect that the accept header is not the supported version. So I know the credentials are correct (and the fact they match the postman credentials which works):
"{\"apiVersion\": \"1\",\"context\": null,\"id\": null,\"method\": null,\"error\": {\"code\": null,\"message\": null,\"reason\": \"Accept header version is not a currently supported version.\",\"errors\": null}}\n"
So I know all my credentials are correct because I've copied them into the postman request which works with no errors. The value for the accept header is correct because I copied that from a working postman request too.
I am at a loss for why this wouldn't work.
I've looked through the NET HTTP library and cant find anything to help me there. I've seen a couple of posts elsewhere which I've tried and they haven't worked either.
I appreciate any help in trying to solve this.
Found the problem. I was using the credentials from the production environment to get the token then trying to query the test environment API. In my defence they look very similar (only 3 characters different). I think I had a case of the code blindness.
The code I posted does work when I put the correct URL for the environments.
I also found that I could use this:
uri = URI.parse("https://myapi/some_text")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Get.new(uri.request_uri)
request["Authorization"] = "Bearer #{bearer_token}"
request["Accept"] = "application/vnd.bluebadge-api.v1+json"
response = http.request(request)
Or using HTTParty like this:
response = HTTParty.get('https://myapi/some_text', {
headers: {"Authorization" => "Bearer #{bearer_token}", "Accept" => "application/vnd.bluebadge-api.v1+json" }
})
I would prefer the format of my orginal code or the HTTparty code because it is easy to see from the code that you're passing headers. Hopefully this will help others to double check their authorization credentials...
I am trying to use the grafana api (doc here http://docs.grafana.org/http_api/alerting/) to get the list of all the alerts in grafana.
Here's what I tried:
uri = URI("http://example:3000")
headers = {
'Authorization'=>'Bearer test',
'Content-Type' =>'application/json',
'Accept'=>'application/json'
}
http = Net::HTTP.new(uri.host, uri.port)
request1 = Net::HTTP::Get.new("/api/dashboards/uid/uKH1CKVmk")
response1 = JSON.parse(http.request(request1).body)
This one works, it returns the json of the dashboard, but when I try :
request2 = Net::HTTP::Get.new("/api/alerts?state=ALL") or
request2 = Net::HTTP::Get.new("/api/alerts?dashboardId="+response1["id"].to_s+"")
request2['Authorization'] = "Bearer test"
request2['Content-Type'] = "application/json"
request2['Accept'] = "application/json"
I get an empty json.
Any ideas what I am doing wrong ?
Thanks,
Nicu
Found the problem, when I created the API token I selected "Viewer" permissions, I was thinking its enough to just make a get request on alerts, but apparently it is not, made a new API token with "Admin" permissions and it works.
Following on from https://lists.hyperledger.org/g/composer/message/91
I have adapted the methodology described by Caroline Church in my IOS app.
Again I can authenticate with google but still get a 401 authorization error when POSTing.
I have added the withCredentials parameter to the http header in my POST request.
does the rest server pass back the token in cookie ? I don't receive anything back from the rest server.
where does the withCredentials get the credentials from ?
COMPOSER_PROVIDERS as follows
COMPOSER_PROVIDERS='{
"google": {
"provider": "google",
"module": "passport-google-oauth2",
"clientID": "93505970627.apps.googleusercontent.com",
"clientSecret": "",
"authPath": "/auth/google",
"callbackURL": "/auth/google/callback",
"scope": "https://www.googleapis.com/auth/plus.login",
"successRedirect": "myAuth://",
"failureRedirect": "/"
}
}'
the successRedirect points back to my App. After successfully authenticating I return to the App.
Got this working now. The App first authenticates with google then exchanges the authorization code with the rest server.
The Rest server COMPOSER_PROVIDERS needs to be changed to relate back to the app.
clientID is the apps ID in google,
callbackURL and successRedirect are reversed_clientID://
The App calls http://localhost:3000/auth/google/callback with the authorization code as a parameter.
this call will fail, but an access_token cookie is written back containing the access token required for the rest server.
The user id of the logged in user is not passed back, when exchanging the code for a token with google we get back a JWT with the details of the logged in user. We need this back from the rest server as well as the token. Is there any way to get this ?
changing the COMPOSER_PROVIDERS means that the explorer interface to the Rest server no longer works.
func getRestToken(code: String) {
let tokenURL = "http://localhost:3000/auth/google/callback?code=" + code
let url = URL(string:tokenURL);
var request = URLRequest(url: url!);
request.httpMethod = "GET";
request.setValue("localhost:3000", forHTTPHeaderField: "Host");
request.setValue("text/html, application/xhtml+xml, application/xml;q=0.9, */*;q=0.8", forHTTPHeaderField: "Accept");
request.setValue("1", forHTTPHeaderField: "Upgrade-Insecure-Requests");
request.httpShouldHandleCookies = true;
request.httpShouldUsePipelining = true;
let session = URLSession.init(configuration: .default);
session.configuration.httpCookieAcceptPolicy = .always;
session.configuration.httpShouldSetCookies=true;
session.configuration.httpCookieStorage = HTTPCookieStorage.shared;
let task = session.dataTask(with: request) { (data, response, error) in
var authCookie: HTTPCookie? = nil;
let sharedCookieStorage = HTTPCookieStorage.shared.cookies;
// test for access_token
for cookie in sharedCookieStorage! {
if cookie.name == "access_token"
{
print(“Received access token”)
}
}
guard error == nil else {
print("HTTP request failed \(error?.localizedDescription ?? "ERROR")")
return
}
guard let response = response as? HTTPURLResponse else {
print("Non-HTTP response")
return
}
guard let data = data else {
print("HTTP response data is empty")
return
}
if response.statusCode != 200 {
// server replied with an error
let responseText: String? = String(data: data, encoding: String.Encoding.utf8)
if response.statusCode == 401 {
// "401 Unauthorized" generally indicates there is an issue with the authorization
print("Error 401");
} else {
print("HTTP: \(response.statusCode), Response: \(responseText ?? "RESPONSE_TEXT")")
}
return
}
}
task.resume()
}
have you authorised the redirect URI in your Google OAUTH2 configuration ?
This determines where the API server redirects the user, after the user completes the authorization flow. The value must exactly match one of the redirect_uri values listed for your project in the API Console. Note that the http or https scheme, case, and trailing slash ('/') must all match.
This is an example of an Angular 5 successfully using it Angular 5, httpclient ignores set cookie in post in particular the answer at the bottom
Scope controls the set of resources and operations that an access token permits. During the access-token request, your application sends one or more values in the scope parameter.
see https://developers.google.com/identity/protocols/OAuth2
The withCredentials option is set, in order to create a cookie, to pass the authentication token, to the REST server.
Finally this resource may help you https://hackernoon.com/adding-oauth2-to-mobile-android-and-ios-clients-using-the-appauth-sdk-f8562f90ecff
The question is:
Where can I see the http requests my browser (Chrome) sends?
Somehow I think this is a very basic question, but I just can't find a good source to get the information I need. I want to know in order to use the Pipedrive API. I need to make a http put request to this URL with a json-type body: "https://api.pipedrive.com/v1/persons/1&api_token=d32c1ca664720eefbd5db15f5d70fd9ebb95e996"
. On their api doc page they have a tool to make example calls but I only see the URL-Part, which only contains the API-key. The other data is in the body and I can't seem to set the request up right. Therefor the initial question about where to see the requests send from my browser. I could then inspect the test-api-call..
My request approach so far:
uri = URI("https://api.pipedrive.com/v1/persons/{p_id}&api_token=12345ca664720eefbd5db15f5d70fd9ebb95e996")
Net::HTTP.start(uri.host, uri.port,
:use_ssl => true,
:verify_mode => OpenSSL::SSL::VERIFY_NONE ) do |http|
request = Net::HTTP::Put.new(uri)
request.add_field('Content-Type', 'application/json')
request.body = {'name' => 'XXXXXXXX'}.to_json
response = http.request(request) # Net::HTTPResponse object
puts response.body
end
Not sure if this is what you need, but open the Developer Tools in Chrome, go to the "Network" tab and hit record, then send the request. You'll see this request, and the subsequent ones (if any) listed. Click on it and you'll be able to browse the details.
If you want to see what the data you send looks like when it's received by the server, you can try pointing your code at httpbin, which will return it back to you, like so:
$ curl -X PUT http://httpbin.org/put -d 'this is a test'
{
"args": {},
"data": "",
"files": {},
"form": {
"this is a test": ""
},
...etc...
So then examine the contents of your response and you'll see what the server received from you and can check if it's right.