Facebook Login without JSSDK, how to get token if already authorized previously - vb.net

So I am updating an older desktop app (written in VB, .net 4.0) with facebook integration and followed the guide found here, and have been able to successfully get a token (by parsing the uri of the embedded webview if it contains "token="). Now my problem is if I try to login with a facebook account that has already approved the app in a prior session, the webview just gets redirected to https://www.facebook.com/connect/login_success.html without any token information.
Do I HAVE to log all of the tokens I generate manually (ie on successful token generation, I can call their profile info, use their FB ID as key and save the token)? Even if I do, since the email and password is input directly into the facebook login window, how do I check if the user already has a token?
Thanks in advance

The access token can change any time, you need to get it everytime. After getting the token, I immediately get the user information https://graph.facebook.com/me?access_token=??? and use that ID to find their database information.
I couldn't quickly find facebook information but on google's oauth information it says "The access token is also associated with a limited scope that define the kind of data the your client application has access to (for example "Manage your tasks"). An important goal for OAuth 2.0 is to provide secure and convenient access to the protected data, while minimizing the potential impact if an access token is stolen."
https://code.google.com/p/google-api-php-client/wiki/OAuth2

Ok so I finally figured it out myself. My mistake was apparently requesting the access_token directly (ie https://www.facebook.com/dialog/oauth?response_type=token...) to try and save time.
I fixed it by making a request for a 'code' instead (ie https://www.facebook.com/dialog/oauth?response_type=code), which I then use to make a second request to retrieve an access token as documented here: https://developers.facebook.com/docs/facebook-login/login-flow-for-web-no-jssdk/, "Exchanging code for an access token" section a bit lower on the page.
Hope this helps someone in the future, this was very frustrating on my part.
Regards,
Prince

Related

How is the access_type=online oauth mode (no refresh token) supposed to work?

This question is has a lot in common to the previous question Google OAuth: can't get refresh token with authorization code (and I won't be offended if it's considered a duplicate) but there are some differences: that question uses the Javascript and PHP libraries, and I'm using neither of those. That question wants to know how to get a refresh token, and I want to know if I should want a refresh token, or how the mode with no refresh tokens is intended to work.
I'm following this guide:
https://developers.google.com/identity/protocols/OAuth2WebServer
The goal is to allow users to upload files from Google Drive to my web application.
I'm not using one of Google's favored programming languages, so I don't have a library abstracting away all the interaction with Google. I need to know what the HTTP requests should actually should look like.
One of the parameters in the authorization request is access_type. The description says
Set the value to offline if your application needs to refresh access tokens when the user is not present at the browser.
I won't need to do that (I'll only want to retrieve a file on my server immediately after the user selects it) so in the spirit of not asking for more privileges than you really need, I used access_type=online. This gives me an access token and no refresh token. I've successfully used the access token to make some requests to Google Drive.
The user comes back the next day and tries to upload another file. While processing this request from the user, I make a request to Google Drive. The access token is expired, so I get a 401. What's supposed to happen next?
My guess is I should pretend this is a completely new user and send them through the full authorization process again. That would mean I have to abort whatever the user was trying to do, redirect them to https://accounts.google.com/o/oauth2/auth with all the parameters (scope, client_id, etc.) and embed enough information in the state parameter that I can resume the original request when the user gets back from their detour.
This seems rather difficult (in particular the part about saving and resuming the state of my application at some arbitrary point). It's a big enough obstacle that it should be explained somewhere. But the description of the access_type parameter didn't say anything about needing to insert authorization redirects everywhere. It just said the user must be "present".
You are using the right implementation. You don't need offline access if you aren't going to make requests when the user is not using the application. The thing is that access tokens expire in 1 hour. So you need to generate new access tokens if a user leaves the application and come back later.
If users have authorized your application, calling this URL with your configuration should return a new valid access token:
https://accounts.google.com/o/oauth2/v2/auth?
scope=scopes&
include_granted_scopes=true&
state=state_parameter_passthrough_value&
redirect_uri=http://oauth2.example.com/callback&
response_type=token&
client_id=client_id

Replace "via Graph API Explorer" label by my application name

I am quite new in Facebook application development. I was playing the all day with "how to post a message on the wall of a page?". I finally succeeded but each message got "via Graph API Explorer". I tried to find how to change it to my application name without success. I tried to see if I could force the value of application in the api command but it did not take it into account. Maybe I miss something :( If someone can help, that would be great!
I am still quite confused. Let me try to explain what I want to do: I would like to automatically publish on a page (as the page) some event that are defined on a website (in a kind of agenda). What I miss, I think, is how everything is working together on Facebook side:
1. the login process: as the application will run in a cron, this should not display a login dialog box.
2. the access token: application or page one?
3. the permissions: from my understanding, I need manage_pages (and publish_stream) but not clear how this should be set.
Thx for any clarification and maybe a clear example :o)
You need the user to authorise your own App using one of the Login flows and grant you one of the publishing Permissions -
If it says 'via Graph API Explorer' on the posts your app makes you're using the access token you retrieved when you were testing the API using the Graph API Explorer tool, not one produced by your own app
OK I think I have finally found the way to do it. I needed a page access code and not an application access code. The token must be generated outside the application as a long live one.
Get a code using:
https://www.facebook.com/dialog/oauth?client_id={app_id}&redirect_uri={my_url}&scope=manage_pages,publish_stream
app_id is your application ID
my_url is your application URL
scope is the permission you want to be granted
In the redirected URL, you will have a code parameter. Copy it.
Generate the user access code using:
https://graph.facebook.com/oauth/access_token?client_id={app_id}&redirect_uri={my_url}&client_secret={app_secret}&code={code}
app_secret is your application secret key
code is the code from step 1
You will get as output the user access token. This one is a short live one.
convert the short live to a long live user access token using:
https://graph.facebook.com/oauth/access_token?grant_type=fb_exchange_token&client_id={app_id}&client_secret={app_secret}&fb_exchange_token={short live access token}
Replace the "short live access token" by the one you got on step 2
You will get as output the infinite user access token.
Get the page access token (this one will be infinite access token as
the user access token is now an infinite access token too):
https://graph.facebook.com/me/accounts?access_token={infinite user access token}
Replace the "infinite user access token" with the value you got on step 3.
This command will list all the pages you administer. The output contains the page access token you need in field "access_token". You can so use this token in any API command in your application.
The best of the best is to do all those steps via a server side program (PHP for me) as the application secret key should remain "secret".

When is access_type = Online appropriate? :OAuth2 - Google API

When requesting OAuth credentials, I can specify the access_type to be Offline or Online.
Opting for the Online access type forces the users to approve access to my app each time they login. Why is that? Hasn't the user already approved my app?
Update #1:
I have my approval_prompt set to 'auto'.
If I just log out of Google without deleting any cookies, it doesn't prompt me again. But deleting the cookies brings back the grant screen.
Update #2:
It works fine through the OAuth Playground. http://code.google.com/oauthplayground/
Using OAuth 2.0 for Web Server Applications
https://developers.google.com/accounts/docs/OAuth2WebServer
Update #3:
Relevant code snippets
Helper method to generate OAuth URL
def build_auth_uri
return #client.authorization.authorization_uri(
:access_type => :online,
:approval_prompt => :auto
).to_s
end
Calling the Helper method in the View
Connect Me!
Generated OAuth URL on the webpage
https://accounts.google.com/o/oauth2/auth?access_type=online&approval_prompt=auto&redirect_uri=http://localhost:3000/gclient/gcallback&response_type=code
There is one other parameter that comes into play in these flows and I suspect you're running into it. It's the approval_prompt parameter.
When access_type=online you are also allowed to specify a value for approval_prompt. If it is set to approval_prompt=force, your user will always be prompted, even if they have already granted.
On the other hand, when access_type=offline, approval_prompt can only be set to approval_prompt=force, but to make up for this restriction you're also provided a refresh_token which you can use to refresh your access token.
Check the URL that your access_type=online is opening. Try setting approval_prompt=auto. The grant screen should only appear the first time.

How can I use Google's OpenID and/or OAuth services to login and allow access to APIs with only ever one prompt to the user?

I am attempting to create a login system for my website that permits both authentication via Google's API and access to any of the OAuth-supported Google Data APIs while ideally only showing the user one prompt ever, no matter if he's creating an account or logging into his existing one. I want to minimize the number of times he's asked for approval.
I am aware that Google provides Hybrid OpenID/OAuth for this purpose, but the issue is that every time I add OAuth extensions to my OpenID request, it never remembers the user's approval for that request. Is there any way for the approval to be remembered when I am doing Hybrid OpenID/OAuth? If I just do OpenID without OAuth extensions, everything is remembered just fine and it doesn't keep bugging the user with the prompt.
Here are the pertinent extensions I'm sending in addition to my OpenID request, which result in me getting an OAuth request token (good) but cause the approval to never get remembered (bad).
PHP syntax:
$args["openid.ns.ext2"] = 'http://specs.openid.net/extensions/oauth/1.0';
$args["openid.ext2.consumer"] = 'www.MYSITE.com';
$args["openid.ext2.scope"] = 'http://www-opensocial.googleusercontent.com/api/people/';
$args["openid.mode"] = 'checkid_setup';
$args["openid.realm"] = 'http://www.MYSITE.com/';
Is it normal for Hybrid OpenID/OAuth to act this way (not remembering the last OAuth authorization)? What is the best way to get around this? I have thought of storing cookies on the user's computer to link to somewhere in my database so I could use the last access token again, etc... (the issue here being I don't know whose token to look up unless I know who the user is...a circular problem). And doing an OpenID-only request to get his user ID to see if he has an account in order to look up his access token, followed by an OpenID+OAuth request (if an access token for him isn't stored) would result in two prompts, which really wouldn't help.
It also seems like Hybrid only supports OAuth 1.0, which I think is fine until 2015, so it's not an issue right now for me. I am assuming they will support OAuth 2.0 in the future.
Is checkid_immediate relevant to this in any way? I'm just not sure how to use this to accomplish what I want.
I would suggest using OAuth 2.0. This supports getting both identity and access to APIs -- so accomplishes the same end goal, but is much easier than OAuth 1 Hybrid.
Take a look here:
https://developers.google.com/accounts/docs/OAuth2Login
The scopes you're trying to access are included in the URL (see "Forming the URL"). The referenced doc lists the scopes required for getting identity/profile information. You can simply add additional scopes to the string, comma-delimited in order to request access to other APIs. The resulting access token will access both the APIs and identity information (via the UserInfo API endpoint mentioned).
That said, what you're trying to do with OpenID 2.0/OAuth 1 hybrid should work-- and the user should see a checkbox for "remembering" the authorization. If you really want to debug this further, it'd be helpful to have a webpage you can point to which kicks off this authentication+authorization flow so we can see what's happening.
I figured out that checkid_immediate (and x-has-session, not sure if that's needed or even working) is allowing me to determine whether or not a user is logged in without prompting him, and if he is, it is giving me a claimed_id by which I can identify the user. That's exactly what I needed. The original question is solved, but I do want to figure out how to use identify with OAuth 2.0 because I have already implemented that.
Furthermore, I've noticed that when using OpenID/OAuth that the user still gets asked to authorize OAuth even after he's authorized OpenID. I can't see the advantage to the hybrid approach from the user's perspective.
If the user is logged out of Google, that's a total of three prompts just to sign up for my website and grab his name and profile image.
If anyone wondered, here are the steps necessary to get Hybrid OpenID/OAuth completely working (an overview). I was confused thoroughly throughout this process, so I hope this helps someone.
Do normal OpenID handshake and add on AX extensions for OAuth 1.0.
Use 'checkid_immediate' to permit probing for an active Google session without prompting the user. Use *claimed_id* as a unique identifier to link the user to your database.
If 'setup_needed' is returned, use 'checkid_setup' so the user is prompted and verified before continuing.
This leaves you with two possibilities. *checkid_immediate* returning immediately giving you a claimed_id, or a claimed_id coming through after *checkid_setup* (basically sign-up) succeeds.
Hybrid OpenID/OAuth 1.0 will give you an authorized request token.
Use the authorized request token to get an access token (you only need to call OAuthGetAccessToken)
Use that OAuth 1.0 access token to do whatever you want.
I was successful in using OAuthGetAccessToken to get an access token from the authorized request token my Hybrid OAuth dance, omitting the 'oauth_verifier' parameter (irrelevant to Hybrid).
I was successful in using OAuthGetAccessToken to get an access token after my Hybrid OAuth dance, omitting the 'oauth_verifier' parameter (irrelevant to Hybrid).
In a PHP/Zend environment:
$config = array(
'accessTokenUrl' => 'https://www.google.com/accounts/OAuthGetAccessToken',
'consumerKey' => $consumer_key,
'consumerSecret' => $consumer_secret
);
$consumer = new Zend_Oauth_Consumer($config);
$zendRToken = new Zend_Oauth_Token_Request(); // create class from request token we already have
$zendRToken->setToken($requestToken);
try{
$accessToken = $consumer->getAccessToken(array(
'oauth_token' => $requestToken,
// 'oauth_verifier' => '', // unneeded for Hybrid
'oauth_timestamp' => time(),
'oauth_nonce' => md5(microtime() . mt_rand()),
'oauth_version' => '1.0'
), $zendRToken);
} catch (Zend_Oauth_Exception $e){
echo $e->getMessage() . PHP_EOL;
exit;
}
echo "OAuth Token: {$accessToken->getToken()}" . PHP_EOL;
echo "OAuth Secret: {$accessToken->getTokenSecret()}" . PHP_EOL;

Authorizing for Google ToDo List (AuthToken, secid)

I'm trying to get access to the Google's todo feed with this url:
https://www.google.com/calendar/tdl?secid=<SECID>&tdl={%22action_list%22%3A[{%22action_type%22%3A%22get_all%22%2C%22action_id%22%3A%221%22%2C%22list_id%22%3A%2215052708471047222911%3A0%3A0%22%2C%22get_deleted%22%3Afalse}]%2C%22client_version%22%3A-1}
If I open this in my browser with a correct secid, it shows me right what I want.
Now, the question is: how do I get secid programmatically (specifically, in a java program)? I have access to the authToken (from CalendarService), but I have no clue how to use it to authorize my access to the URL above.
I tried to use the url http://google.com/accounts/ServiceLogin, but I didn't find any examples.
Any help, please?
From what I read secid is a session ID obtained from browser's cookies. Whereas your case uses Java which implies a server app. If that is the case, you want to drop the idea of using secid entirely.
Instead, you want to check out Google's OAuth2 documentation. If you are using Java, most likely you would be interested in the web-server OAuth flow. Pay special attention to the sequence diagrams.
The key steps include:
1) Obtain an authorization code from Google OAuth with the user's consent. For that, you redirect the user to Google with the appropriate scope. Check the list of calendar scopes for your case. Once the user consents, Google redirects back to you with an authorization code.
2) Call Google OAuth with the authorization code and your app's credentials to exchange for an access token.
3) Call Google's Calendar API using the access token.
And if you use Google's Java client as suggested by #ChaosPredictor, chances are some of the steps are already wrapped into the Java client (and your code will be much simpler).