Google Calendar Data API Integration - ruby-on-rails

We're using Oauth to grab Calendar event data. I have successfully authorized the token and exchange it for an access token. When I perform a get request to the API endpoint I get a page that says "Moved Temporarily" with a link to something like https://www.google.com/calendar/feeds/default?gsessionid=xxxxxxxxxxxx
I'd like to interpret the response, whether it's json or xml but I can't get beyond the redirect it's throwing out. Any idea how to follow this?
Here's my call to the feed:
access_token = current_user.google.client
response = access_token.get(ConsumerToken::GOOGLE_URL).body

Yep, just dealt with this myself. It says "Moved Temporarily" because it's a redirect, which the oauth gem unfortunately doesn't follow automatically. You can do something like this:
calendar_response = client.get "http://www.google.com/calendar/feeds/default"
if calendar_response.kind_of? Net::HTTPFound # a.k.a. 302 redirect
calendar_response = client.get(calendar_response['location'])
end
This might be worthy of a patch to oauth...

Related

Twitter API v1.1 media INIT error code 32

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#");

YouTube Authorization Code exchange fails with redirect_uri_mismatch

I'm trying to exchange an authorization code for access code, but I'm getting an error saying "redirect_uri_mismatch".
I waited ~8 hours just in case it needs to update, but no luck so far.
The redirect uri's are set correctly, as you can see from the image here.
Initial Front-End redirect/request:
GET => https://accounts.google.com/o/oauth2/v2/auth
?scope=https://www.googleapis.com/auth/youtube.readonly
&include_granted_scopes=true
&state=state_parameter_passthrough_value
&redirect_uri=http://localhost:4200/profile?platform=youtube
&access_type=offline
&response_type=code
&client_id=[HIDDEN]
After code is parsed, I exchange the code for access code:
POST => https://oauth2.googleapis.com/token
?client_id=[HIDDEN]
&client_secret=[HIDDEN]
&code=[HIDDEN]
&grant_type=authorization_code
&redirect_uri=http://localhost:2222/youtube/oauth
Response:
data: {
error: 'redirect_uri_mismatch',
error_description: 'Bad Request'
}
Apparently, the redirect_uri has to match the initial request's uri.
Problem solved, feel free to upvote for visibility - thanks.
Source: https://www.rfc-editor.org/rfc/rfc6749#section-4.1.3

Desire2Learn Valence API | JSON not loading

I'm using the Python Requests library with the Valence-provided Python SDK to attempt to do a GET request. Something odd is happening with the URL and I'm not sure what. The response I get is 200 (which leads me to believe that the authentication is working), but when I try to print the JSON from the Request object, it instead prints the HTML of the page instead of the JSON.
I'm using modified code that I read from http://docs.valence.desire2learn.com/clients/python/auth.html.
Here's the Python code:
import requests
import auth as d2lauth
from auth import *
app_creds = { 'app_id': '----', 'app_key': '----' }
ac = d2lauth.fashion_app_context(app_id=app_creds['app_id'], app_key=app_creds['app_key'])
auth_url = ac.create_url_for_authentication('ugatest2.view.usg.edu', 'http://localhost:8080')
redirect_url = "https://localhost:8080?x_a=3----&x_b=3dMRgCBAHXJDTA2E6DJIfdWq-gYl-pk77fF_3X5oDUuqc"
uc = ac.create_user_context(auth_url, 'ugatest2.view.usg.edu', True)
route = 'ugatest2.view.usg.edu/d2l/api/versions/'
url = uc.create_authenticated_url(route)
r = requests.get(url)
print(r.text)
The output is the HTML of a page instead of JSON. If I do print(r), I get a status of 200. I think my redirect URL may be the issue, but I'm not sure what exactly is wrong. Thanks for any help!
Two things look off to me:
Using auth_url to create a user context isn't going to work, that's the URL you need to send the user to so they can authenticate. You need to use the URL you were redirected to after authenticating to build the user context. Assuming redirect_url is that URL, you should be passing that to create_user_context and not auth_url.
ugatest2.view.usg.edu/d2l/api/versions/ is not a valid value for passing to create_authenticated_route, /d2l/api/versions is probably what you want. The SDK will prepend the scheme, domain, and port so including those in the value passed is going to result in an incorrect URI.
Once your app is working properly, you'll be able to access a JSON response by using r.json() rather than r.text.

Google docs API: can't download a file, downloading documents works

I'm trying out http requests to download a pdf file from google docs using google document list API and OAuth 1.0. I'm not using any external api for oauth or google docs.
Following the documentation, I obtained download URL for the pdf which works fine when placed in a browser.
According to documentation I should send a request that looks like this:
GET https://doc-04-20-docs.googleusercontent.com/docs/secure/m7an0emtau/WJm12345/YzI2Y2ExYWVm?h=16655626&e=download&gd=true
However, the download URL has something funny going on with the paremeters, it looks like this:
https://doc-00-00-docs.googleusercontent.com/docs/securesc/5ud8e...tMzQ?h=15287211447292764666&amp\;e=download&amp\;gd=true
(in the url '&amp\;' is actually without '\' but I put it here in the post to avoid escaping it as '&').
So what is the case here; do I have 3 parameters h,e,gd or do I have one parameter h with value 15287211447292764666&ae=download&gd=true, or maybe I have the following 3 param-value pairs: h = 15287211447292764666, amp;e = download, amp;gd = true (which I think is the case and it seems like a bug)?
In order to form a proper http request I need to know exectly what are the parameters names and values, however the download URL I have is confusing. Moreover, if the params names are h,amp;e and amp;gd, is the request containing those params valid for obtaining file content (if not it seems like a bug).
I didn't have problems downloading and uploading documents (msword docs) and my scope for downloading a file is correct.
I experimented with different requests a lot. When I treat the 3 parameters (h,e,gd) separetaly I get Unauthorized 401. If I assume that I have only one parameter - h with value 15287211447292764666&ae=download&gd=true I get 500 Internal Server Error (google api states: 'An unexpected error has occurred in the API.','If the problem persists, please post in the forum.').
If I don't put any paremeters at all or I put 3 parameters -h,amp;e,amp;gd, I get 302 Found. I tried following the redirections sending more requests but I still couldn't get the actual pdf content. I also experimented in OAuth Playground and it seems it's not working as it's supposed to neither. Sending get request in OAuth with the download URL responds with 302 Found instead of responding with the PDF content.
What is going on here? How can I obtain the pdf content in a response? Please help.
I have experimented same issue with oAuth2 (error 401).
Solved by inserting the oAuth2 token in request header and not in URL.
I have replaced &access_token=<token> in the URL by setRequestHeader("Authorization", "Bearer <token>" )

Reading x-access-Level header for Twitter REST API using omniauth-twitter / twitter Gem

I'm using Omniauth to authenticate users with Twitter through OAuth (using omniauth-twitter gem). I plan to allow normal users to login with just 'read' permissions, and only authorise 'read-write' permissions if/when they decide to create things within the site.
In my Identity model I'm analysing the AuthHash omniauth passes to the create_with_omniauth action, and I'm making separate logic for each provider type, so that I can look deeper into the returned hash schema if necessary.
If I raise auth.to_yaml to output the structure, I see the 'x-access-level' header that I'd like to read, but I don't know how to look into the response: Net::HTTPOK object in order to get to the next level of the structure.
This is the auth structure, cutting out some of the unnecessary details
--- !ruby/hash:OmniAuth::AuthHash
provider: twitter
...
extra: !ruby/hash:Hashie::Mash
...
access_token: !ruby/object:OAuth::AccessToken
...
response: !ruby/object:Net::HTTPOK
http_version: '1.1'
code: '200'
message: OK
header:
x-access-level:
- read-write
x-ratelimit-limit:
- '350'
x-ratelimit-remaining:
- '348'
x-ratelimit-reset:
- '1330798604'
So far I can get to the response with auth["extra"]["access_token"].response but putting .header at the end returns the same response structure, and ["header"] is empty when I raise it.
I'm ok with using the Twitter gem if necessary to do a verify_credentials call inside the Identity model (since Twitter adds the x-access-level header to every response, but even with this approach I wouldn't know how to read the returned headers to read the x-access-level header.
I know this is not the same ruby twitter client but it might help other that arrive here after looking for the same question with the ruby twitter client (gem "twitter").
So going from this call:
twitter_client = Twitter::Client.new(:oauth_token => token, :oauth_token_secret => secret)
twitter_client.verify_credentials
That will give you only the user info json. You can actually get the twitter api response and then check the x-access-level contained in the header
resp = twitter_client.get, "/1.1/account/verify_credentials.json"
resp[:response_headers]["x-access-level"] # "read-write" in my case
Hope this helps others...

Resources