Using a WebViews cookies with an HTTP Client - basic4android

This is with reference to using Google Contacts Data API.
It requires that the application gets authentication view a WebBrowser/WebView (in the case of android).
Therefore the RequestTokenUrl is passed to the webview which will show a Google Sign-in page and then ask the user if it allows the application to access their account.
Once authorized, there needs to be some kind of callback to the activity.
The activity will then use the WebViews cookie (which should contain the AccessToken) with an HTTP client to request data from Google Data API. This could be anything, in our case it is the Google Contacts.
Any ideas on how this can be done?
EDIT: Found another way around the problem by using OAuth 2.0.
This still required getting the AuthorizationCode from the WebView but that is accessed through the pagetitle instead of a cookie.
The selected answer still addresses the original question correctly.

The following code which uses the reflection library will print a line with the cookies:
Sub WebView1_PageFinished (Url As String)
Dim r As Reflector
r.Target = r.RunStaticMethod("android.webkit.CookieManager", "getInstance", Null, Null)
Log(r.RunMethod2("getCookie", Url, "java.lang.String"))
End Sub

Related

Retriving data from facebook events

I have to create an webpage where i need to show all the events from the past or upcoming ones from an facebook page. I have to retrive the title, description, image, time and place of every single one and make a box with it.
After that, i have to retrive all the interested people.
I'm a beginner trying to make big things! Thank you very much.
This isnt a simple problem - I have just done this so will give you a start.
You need to use Facebooks Graph API to get the data, you will need to read up on the Graph API and how to use it. Documentation can be found here. Its worth noting due to a security breach the API isn't offering all of its services to new developers currently but you can get most - read about this here.
You can query the API using any language but I suggest do it with python and use the requests module. Alternatively you could use this SDK which makes things a lot easier, trust me! With the SDK you need to get a user access token which you can get from here.
SDK
With the SDK its possible to do this
import facebook
graph = facebook.GraphAPI(access_token="your_token", version="2.12")
event = graph.get_object(id='event_id',
fields='attending_count,declined_count')
print(event['attending_count'])
print(event['declined_count'])
You can add more fields to the fields list. However you can use any language you choose to request the data, as you can just construct your own URL's.
Graph API & Requests
This is how I did it in python using requests to query the API.
import requests, json
#Make a requests session to fetch data from URL's
session = requests.Session()
session.mount('https://', requests.adapters.HTTPAdapter(max_retries=10))
#API base URL
baseUrl = 'https://graph.facebook.com/v2.11/'
#Fields you want to get
fields = ['id', 'name', 'start_time', 'end_time', 'description', 'place']
#replace CLIENT_ID and CLIENT_SECRET with ones from a facebook app (make one)
tokenPath= 'oauth/access_token?client_id={0}&client_secret={1}&&'\
'grant_type=client_credentials'.format(CLIENT_ID, CLIENT_SECRET)
#Get the generated token
token = session.get(baseUrl + tokenPath).json()['access_token']
event = session.get(baseUrl, params={
"ids": "event_id",
"fields": ",".join(fields),
"access_token": token,
}
).json()
print(event["name"])
print(event["place"])
You can make a facebook app here which is where the CLIENT_ID & CLIENT_SECRET come from.
Why would you use URL requests and not the SDK?
Using the SDK the generated user access tokens expire every day, its possible to extend them but only for 60 days. If you want to use the SDK it has a method built in which allows you to extend the token, in order to extend the token you also need to create a facebook app. Its also possible to extend tokens using this website, though I cant vouch for its security - it could potentially access and exploit your data.
To extend the token with SDK:
import facebook
graph = facebook.GraphAPI(user_access_short_lived_token)
extended_token = graph.extend_access_token(app_id, app_secret)
print(extended_token)
Using the URL approach, you create a client access token at runtime (read about user access token vs client access token here) and the token is valid so long as your app is active. So if you are going to use this a lot or want to create it and not have to change/extend tokens then use the URL approach.
Hope this gets you started.

Docusign Embedded Signing returnUrl issue

I am displaying an Embedded Signing view in an iFrame. I am able to get the embedded signing view to display correctly using templates. I am calling an internal service (server-side) from the client (browser) and the internal service calls the Post Recipient View endpoint in the Docusign API.
In order to redirect the user to the correct view in my web app after the Signing view redirects to the returnUrl, I need to have query string parameters on the returnUrl. Here is an example of the returnUrl:
{
...
"returnUrl": "http://localhost:5000/#/my/path/redirect?sname=MY_VALUE&debug=foo,baz"
}
I am using the sname query parameter to hold the value for a string I will use to route to a view once the user is redirected from the Docusign Signing view.
The Problem:
When the iframe is redirected to the returnUrl after the Signing view is complete, the query string in the returnUrl is cutoff and the url of the iframe is:
http://localhost:5000/#/my/path/redirect?sname
when it should be
http://localhost:5000/#/my/path/redirect?sname=MY_VALUE&debug=foo,baz
I also read in the api documentation that an event parameter should also be present in the query string when redirecting, but that is not there either.
Is there a step that I am missing or is this a bug in the api?
I've tried a few tests using Postman and the resulting returnUrl is working for me. I even tried using yours directly (even though I obviously won't be able to connect to it) and it came up correctly as
http://localhost:5000/#/my/path/redirect?sname=MY_VALUE&debug=foo,baz&event=signing_complete
I even tried using an iframe for the signing session like you, still seems to be using the right URL when it redirects. So I've not been able to replicate your problem.
Are you attempting this in the demo environment?

pass data back to facebook app after authorisation

I am authotizing my app in the following way:
// authorize app!
$('#authApp').click(function(){
var oauth_url = 'https://www.facebook.com/dialog/oauth/';
oauth_url += '?client_id=#{app.id}';
oauth_url += '&redirect_uri=' + encodeURIComponent('https://www.facebook.com/pages/null/#{fbPageId()}/?sk=app_#{app.id}');
oauth_url += '&scope=user_likes,user_photos';
oauth_url += '&app_data=7B%27game%27%3A+%27key%27%7D';
oauth_url += '&state=sbSbsbSb';
As you can see I am setting the 'state' param as part of the query string.
Now when the user authorizes the app he is redirected to the redirect url.
However the data passed in the state parameter is not posted to my app nor is it part of my app's iframe query string. I was expecting to find it as part of the signed request, but no. This is the deserialized signed request posted back after authorisation
{ algorithm: 'HMAC-SHA256',
expires: 1348927200,
issued_at: 1348921162,
oauth_token: 'AAA...',
page: { id: '490...', liked: true, admin: false },
user: { country: 'ec', locale: 'en_US', age: { min: 21 } },
user_id: '1...' }
I do see that the state is included of the parent page's query string. I need to access that parameter from my app (running inside an iframe). I believe that I cannot just access the parent page's window location because of same origin policy restrictions.
I have read through the documentation and searched online. Persisting data across an app authotization needs to be done using the state parameter. However it is nowhere stated how to retrieve that state param once redirected back to your app.
This is from the facebook doc's regarding the state param:
A unique string used to maintain application state between the request
and callback. When Facebook redirects the user back to your
redirect_uri, this parameter's value will be included in the response.
You should use this to protect against Cross-Site Request Forgery.
Am I supposed to get the state data back from the parent's page query string?
Or am I doing something wrong?
* EDIT *
I am storing the user to user request Id in the state parameter. For example A invites B to participate in the app via a facebook request. Once B authorises the app A needs to be rewarded. So I need to know that B came to the app following A's invitation. Therefore I store the requestId in the state param, so once B has authorised the app I can take appropriate action.
* EDIT 2 (SOLUTION) **
If your redirect_uri is pointing to the Page Tab URL then facebook will NOT send back the state parameter! It will only be sent back if you redirect to the Canvas URL !!!!!
The Facebook documentation you referenced is a bit confusing. The only thing you should be doing with the state parameter is making sure you are not a victim of CSRF. Facebook's server side authentication flow gives an example of this in PHP. In short, you should be storing the state value in the session and then verifying that the session value is the same as what Facebook passes back to you in the request. The key line in their PHP example is:
if($_SESSION['state'] && ($_SESSION['state'] === $_REQUEST['state'])) {
// Continue with application logic here because state matches.
// Otherwise, exit immediately because you're a victim of CSRF!
So back to your problem. From your redirect URL and the response you are getting, it's obvious your app is on a Facebook Page Tab. See the authentication flow for page tabs for how you should be doing this. Note they are not using the state parameter in step 2 and that the state parameter is never mentioned in page tab authentication flow. So even if you wanted to use the state parameter for something other than its intended use, you are out of luck.
Based on your edits, I suggest you check out the documentation on requests. Note that the user clicking on the request will be redirected to your canvas app, not the page tab. "The canvas URL will also contain an additional GET parameter request_ids, which is a comma delimited list delimited list of Request IDs that a user is trying to act upon." So there is no need for you to be trying to do this yourself.
Am I supposed to get the state data back from the parent's page query string?
No, not when authenticating within a canvas/page tab app. The only query string parameter that gets passed to your app in this scenario is the content of the app_data parameter.
But you don’t need the state parameter in this scenario – verifying the signed_request is absolutely sufficient, because it’s signed with your app secret, that only you and Facebook know. So that is enough protection against “manipulated” requests right there already.
See https://developers.facebook.com/docs/authentication/canvas/ resp. https://developers.facebook.com/docs/authentication/pagetab/ for more details. (And see how they do not mention the state parameter at all.)
Edit:
I am storing the user to user request Id in the state parameter. For example A invites B to participate in the app via a facebook request. Once B authorises the app A needs to be rewarded. So I need to know that B came to the app following A's invitation. Therefore I store the requestId in the state param, so once B has authorised the app I can take appropriate action.
That’s a misuse of the state parameter … it’s supposed to achieve something completely different (CSRF protection, as the docs say).
While this might work in your scenario – why are you not using the app_data parameter to transmit this piece of information? That’s the designated way of transferring info to canvas/page tab apps.

Refresh expired access tokens using serverside flow automatically

Well there seems to be quite a bit of confusion on this topic and I am struggling to get a clear answer, so here is my question...
I am using the serverside flow to obtain access tokens for my web app, I previously used offline_access which is now being depreciated so I need a way to refresh the token in the following situations:
1) User changes FB password
2) Token expires naturally
My app posts results to users FB walls so the refresh needs to be done automatically by our server (no cookies or OAuth dialogs)
I thought I could try to use the new endpoint described here
http://developers.facebook.com/roadmap/offline-access-removal/
, with the following piece of code (Java):
public static String refreshFBAccessToken(String existingAccessToken)
throws Exception{
//Currently not working
String refreshUrl = "https://graph.facebook.com/oauth/access_token?
client_id="+FacebookApp.appId+"
&client_secret="+FacebookApp.appSecret+"
&grant_type=fb_exchange_token
&fb_exchange_token="+existingAccessToken;
URL url = new URL(refreshUrl);
URI uri = new URI(url.getProtocol(), url.getHost(), url.getPath(),
url.getQuery(), null);
String result = readURL(uri.toURL());
String[] resultSplited = result.split("&");
return resultSplited[0].split("=")[1];
}
But this doesnt seem to work (I get a response 400), and when I re-read the documentation it seems this endpoint is used for tokens obtained using the client-side flow only...
So what about the serverside flow....?
Can someone tell me if the approach above is correct or there is another way?
Many thanks
From what I understand there is no server side flow for refreshing tokens.
The refresh token call needs to include the response of the user authentication process which is a short lived token.
You will need to include the refresh token process as part of the user login flow or if this doesn't work for your setup you will need to email the user asking them to come back!
I dont know java but syntax is very much like C#, so I can say,you are doing everything right.
But I doubt what does this function readURL do ?
If it works like get_file_contents() of php (i.e. if it does an HTTP get) , I guess thats not a right way to do .
Based on my experience on google's refresh token method, I think you should do an HTTP POST instead of HTTP GET to given url.

Google Data/OAuth/AppEngine/Python - Properly Registering a Web Application

I'm creating a webapp with this combination of tools. I'm authenticating with App Engine in the following manner:
class googleLogin(webapp.RequestHandler):
def get(self):
callbackURL = 'http://%s/googleLoginCallback' % getHost()
#Create a client service
gdClient = gdata.docs.service.DocsService()
gdata.alt.appengine.run_on_appengine(gdClient)
gdClient.SetOAuthInputParameters(gdata.auth.OAuthSignatureMethod.HMAC_SHA1,
_GoogleConsumerKey,
consumer_secret=_GoogleConsumerSecret)
#Get a Request Token
requestToken = gdClient.FetchOAuthRequestToken(scopes=_GoogleDataScope,
extra_parameters={'xoauth_displayname': APP_NAME})
#Persist token secret
self.session = Session()
self.session[TOKENSECRETKEY] = requestToken.secret
gdClient.auto_set_current_token = True
gdClient.SetOAuthToken(requestToken)
authUrl = gdClient.GenerateOAuthAuthorizationURL(callback_url=callbackURL)
self.redirect(authUrl)
I authenticated my domain with Google at https://www.google.com/accounts/ManageDomain, entering a target URL and am using the given Consumer Key/Secret. For instance, if my domain was 'juno.appspot.com', I am using http://juno.appspot.com as the target url path prefix.
The process is working; however, Google presents this message to the user in a yellow security box:
"The application that directed you
here claims to be 'xxxxxx'. We are
unable to verify this claim as the
application runs on your computer, as
opposed to a website. We recommend
that you deny access unless you trust
the application."
I don't think I should be getting this error, since my server is getting the request token and creating the authorization URL. Does anyone have any insight on how to get rid of this warning?
Google's domain registration has an option to upload a certificate, but I shouldn't need to do that because I'm using OAuth with the HMAC_SHA1 signature method.
Also, not that it should matter, but I'm doing all this through a UIWebView on the iPhone. I'm specifically trying to do all authentication server-side to avoid exposing my Consumer Key/Secret.
Thank you for any tips :)
Solved.
The culprit is this line from above:
extra_parameters={'xoauth_displayname': APP_NAME})
Setting this value for a registered application intentionally triggers a warning to users, as indicated by the Google documentation:
xoauth_displayname:
(optional) String identifying the
application. This string is displayed
to end users on Google's authorization
confirmation page. For registered
applications, the value of this
parameter overrides the name set
during registration and also triggers
a message to the user that the
identity can't be verified. For
unregistered applications, this
parameter enables them to specify an
application name, In the case of
unregistered applications, if this
parameter is not set, Google
identifies the application using the
URL value of oauth_callback; if
neither parameter is set, Google uses
the string "anonymous".
Removing this line no longer allows me to use a 'nice' name in place of the domain, but it gets rid of that annoying yellow box :)
I'm not sure exactly where the issue may be in your code, but I've got a one page oauth/appengine/gdata example which may at least set you in the right direction. Have you tried to navigate to the site directly from the iPhone/desktop browser to see what message is delivered?
Hope it helps.
Alternatively, is it possibly to do with the user agent the UIWebView sets?