Facebook Login API: How to unconditionally request an email? - facebook-login

Facebook Login allows websites to request a specific set of information from Facebook users (referred to as "scopes"). There is a mandatory scope (public_profile), but we are allowed to request optional ones (such as email) which the user can reject.
My question is, how do I make the optional scopes mandatory? I do not want users to sign up without their email. They are free to reject the entire request, but I do not want them to sign up without all the necessary scopes. All or nothing.
I have seen sites do this:
There is no option to revoke specific scopes. How do they do it?

Edit: I'm guessing the key is using the API v1.0, as the permission selecting was introduced in v2.0. This is most likely what the Guardian does. Whether it's intentional or not, I don't know. By April 30th, 2015 all apps will be required to use the v2.0
A possible workaround:
I don't think there's a specific callback of the Facebook login where the status is returned. You can however use /{user-id}/permissions and loop through the result after the login has been initiated. If any status is not flagged as granted, deny the user access. As you didn't specify a language, I will write an example in PHP:
$res = $facebook->api('/v2.0/me/permissions', array('fields' => 'status'));
$granted = true;
for($i=0;$i<count($res['data']);$i++)
{
echo $res['data'][$i]['status'];
if($res['data'][$i]['status']!="granted")
{
$granted = false;
}
}
if($granted == true)
{
//Login
}else{
//Deny access
}
Did not yet try this with an app I declined specific permissions with. But any flag other than granted should change the process.

Related

How do I get the Amazon Cognito hosted UI to prompt for TOTP?

I am assuming that I would be prompted based off of the documentation, which specifically states:
If your app is using the Amazon Cognito hosted UI to sign in users, the UI shows a second page for your user to enter the TOTP password after they submit their user name and password.
Under the "MFA and Verifications" section of the user pool, I have checked the following:
Do you want to enable Multi-Factor Authentication (MFA)?
Optional
Which second factors do you want to enable?
Time-based One-time Password
I have added a single test user that is verified.
From there, I followed the documentation to both Associate the TOTP Token and Verify the TOTP Token, confirming I got the secret code in the response for calling AssociateSoftwareToken and a 'SUCCESS' in the response for VerifySoftwareToken.
At this point, I believe when I use the hosted UI sign-in page, I should be prompted to enter a one-time-password after submitting my username/password, and upon successful verification of that, be redirected to the signin callback URL specfied in my app client.
However, I am being redirected immediately after submitting the username and password and there is no prompt for entering a TOTP.
I was able to get this to work by explicitly calling SetUserMFAPreference after setting up TOTP for the test account. My assumption that associating and verifying TOTP automatically changed Cognito's behavior with respect to the authentication flow of the user was mistaken. It also required me to tell Cognito to enable and use the TOTP for the user.
The crux of my original confusion was that generating and associating a software token to generate OTPs for a user did not enable it for the user. A call to SetUserMFAPreference to enable it for the user was also required. Once that was done, it worked as expected. For instance, to enable software MFA and set it as preferred:
{
"AccessToken": "xyz123",
"SoftwareTokenMfaSettings": {
"Enabled": true,
"PreferredMfa": true
}
}
There is also an admin version of the API call that can achieve the same result.
For anyone else who stumbles upon this and still isn't getting prompted for their TOTP, you may also need to clear your cookies. Even if your pool is not set up to remember user devices, without clearing the cookies you may still be able to log in without the TOTP.
After messing around with this problem, I reckon that AWS just gave up on this and moved towards using Amplify.
Use the Amplify libraries and their Amplify UI components.
The Auth component will prompt the user at first login with a QR code.
https://docs.amplify.aws/lib/auth/getting-started/q/platform/js/#option-1-use-pre-built-ui-components

How to get user's username in v2.0 or later of Facebook's Graph API

I used to get the user's username in the API 1.0 fairly easily, using /me and getting the username property of the response object.
Now I'm getting this error with API 2.0:
"(#12) username is deprecated for versions v2.0 and higher"
The only way I found to get this until now was to use FQL, but now it seems deprecated.
Is there a way around this?
I don't mean to be unhelpful, but it appears access to username has been removed from the API, as far as I can tell. Places where an app may have been using username, such as in the old share dialogs, can no longer do that when used with the 2.0 API. I think its also a way of preventing apps from having access to usable unique identifiers outside of the app scope - any user IDs you retrieve under 2.0 API are specific to your app alone.
I found a simple workaround that involves a get request to Facebook. Instead of the username, Facebook will give you an ID that is unique to your application.
I have found that making a request to https://www.facebook.com/[profile_id] will then redirect to the user's real profile. The username can be extracted from the redirect URL.
Example:
> curl -i https://www.facebook.com/710290539
HTTP/1.1 301 Moved Permanently
Location: https://www.facebook.com/colinskow
(Note: Since I am the owner of the app in test mode, this could possibly be an exception. Please let me know in comments if you are able to confirm this in a production environment.)
As a workaround you can use the email as a unique identifier. Email address can be retrieved using "email" as the permission scope.
Facebook has removed the username field from the new API version. It is not possible to retrieve the username. But Facebook provides an application specific unique ID. If you need to share the same user between several apps you can use the newly introduced Business Mapping API. This allows to add all the required apps to a group. In this case the ID will be unique among all the apps in the group.
More information on Business Mapping API is available at https://developers.facebook.com/docs/apps/for-business 1

Getting an Access Token Without User Login in Facebook Graph API?

I am working with facebook graph api rsvp_event. I am using javascript SDK. Everything works great when the user is logged in. But when the user is not logged in, it gives an error.
I need information about who is attending a public event. I now understand that I would need an access token to retrieve this information. So, my question is how do I get the access token if no user is logged in? Is it impossible or is there a workaround? Could it be done server side using app_id and client_secret?
I am developing a ColdFusion page, but I can use PHP if needed. I have support for both.
I have heard the term *offline_access_permission*. They have removed this feature. Could it be done when it was still available?
EDIT:
Could this be achieved by test user? Say, on server side I login via test user, get the event information (Just a "get" request to read who is attending an event) and then log off. On the client side I do the rest ( user login, rsvp to an event).
I don't know much about "test user" or its purpose. Can anyone confirm whether this can be achieved or not?
Thanks in advance.
Are you sure you actually need the user's access token? According to documentation here you may need:
- a generic access_token for public events (those whose privacy is set to OPEN)
- a user access_token for a user who can see the event for non-public events
- an app access_token (for non-public events, must be the app that created the event)
- a page access_token (for non-public events, must be the page that created the event)
You can get info on how to get those tokens here https://developers.facebook.com/docs/concepts/login/access-tokens-and-types/
A good idea could be to store the attending users (in the DB) when you have access to the event - when some user is logged in.
UPDATE for getting the data from FileContent.
I don't know what API response exactly you are referring to, but from my experience they are returning data:
- serialized using JSON - you need to use DeserializeJSON(), for example like this:
local.returnStruct = DeserializeJSON( local.requestResult.FileContent );
or
local.returnStruct = DeserializeJSON( local.requestResult.FileContent.toString() );
send as something similar to URI. I'm using a function to get that data:
function getStructFromQueryString( queryString ) {
var ret = StructNew();
var i = 0;
var key = '';
for(i=1; i LTE ListLen(arguments.queryString,'&'); i++) {
key = ListGetAt(arguments.queryString, i, '&');
ret[ListFirst(key,'=')] = URLDecode(ListLast(key,"="));
}
return ret;
}
Basically what you want is a refresh token that can get access tokens when the user is offline, unfortunately facebook does not provide them anymore as far as i know.
To learn more about oauth2 pleas play around with https://developers.google.com/oauthplayground/ its a very nice tool to understand the oauth2 process.

OAuth2 User Mapping and Loosing my Cookies

Wrapping my old-fashioned head around OAuth....
Aside from the request/response mechanics and the Authorize / Authenticate round trips (which I think I underdstand) I am struggling with mapping my MyUser object (whatever that may contain) to an OAuth token, if (actually when, not if) the user kills any cookies (encrypted or otherwise) I may have dropped on the browser.
I get MyUser info at the original Login (call it 'registration' for my site) but now MyUser comes back, all cookies are gone so he is just 'user'. Fair enough, user has to do an OAuth login again, but now I have no way of associating the new Token / Secret with MyUser data.
What am I missing?
--- edit Aug 2/2012 -----
Let me restate this (I am pretty sure I am being thick about this but guess thats what here is for):
As pointed out in Replies, each OAuth provider has their own mechanism. We can navigate those and get back an access Token for the user.
Lets say Hero registers on my site using Facebook. FB returns his FB UserID and Name along with the Access Token. We are clever enough to request and get his FB Email, and we ask him some other registration q's before letting him in. Then we save this in our datastore (linked to our own User record):
OurUserId : 1234
oAuthProviderName : Facebook
oAUthProviderUserId: xxxxx
oAuthProviderUserEmail: hero#mlb.com
oAuthProviderUserName: iBeHero
oAuthToken: entracingly-unique-string-of-goop
oAuthSecret: moredata
.... etc.
and set a cookie to identify him as our user# 1234.
Now Hero goes away, kills his cookies for some reason, and then comes back to us.
Now he decides to Log In with Twitter. I have no cookie so I don't know who he is, and we go through the process again.
To me he looks like a new user so once Twitter sends me a Token I start asking him Registration questions, clearly not right.
Turns out Twitter doesn't return an Email address so I can't match that, and even if they did (I think almost everyone else does) Hero likley has more than one Email.
It seems to me that the only tie I have between the two (or however many) logins is whatever cookies I set that have not been deleted.
Are we saying that the entire OAuth2.0 mechanism hangs on this? I can't belive that is right, but don't see another way, so I must be missing something , yes?
If you're using OAuth as a login mechanism as well, then make sure whichever provider you're talking to has some way of returning back a stable ID for a user. That ID is the key you'd use for looking up the user in your DB.
Different providers have different ways of doing this. For Google, details on how to do authentication with OAuth 2.0 are here. For Twitter, they use OAuth 1.0 and return the user ID when exchanging the code for an access token. Facebook has its own way of doing it as well.

Facebook app (NOT user) access token expiration

Do Facebook APP access tokens expire? These tokens are different than the USER tokens; they are acquired like this:
https://graph.facebook.com/oauth/access_token?grant_type=client_credentials&client_id={0}&client_secret={1})
as described in the App Login section of the document at http://developers.facebook.com/docs/authentication/.
Are there any circumstances under which they will become invalid?
NB: This is NOT a question about USER access tokens (which are clearly documented). There was an identical question http://facebook.stackoverflow.com/questions/7322063/does-app-login-access-token-expire wrongly closed as duplicate of another question about USER access tokens.
Per the Facebook documentation:
An App Access Token is signed using your app secret and will not
expire; it will be invalidated if you re-key/reset your application
secret.
Creating an APP_ACCESS_TOKEN is really easy.
You can use your App ID/API Key and App secret
access_token = YOUR_APP_ID|YOUR_APP_SECRET
Example: 1234587968 | bghyuifjk3438483249235903502035023504305
I do know that one condition that will cause them to become invalid is if you reset the Application Secret using the Facebook developer tool.
I do not know if using the OAuth method to produce an App Token will cause it to have an expiration. However, if you scan Facebook's PHP SDK, you may notice that a non-expiring app token is made by concatenation app_id and secret:
/**
* Returns the access token that should be used for logged out
* users when no authorization code is available.
*
* #return string The application access token, useful for gathering
* public information about users and applications.
*/
protected function getApplicationAccessToken() {
return $this->appId.'|'.$this->apiSecret;
}
WARNING: I would never use this in client-code as it would publish your app secret. However, in a trust server environment, it seems like the way to go.
To test this, I went to the OpenGraph tool and erased my Access Token and typed in the concatenated value from the code sample. I then accessed my app's insights to verify that it would work:
<APP_ID>/insights/application_active_users
For me, the answer is not to find a token that doesn't expire, (since I do not trust Facebook), but to catch the expiring token and reset without taking up my users time. I found this and thought you might want to check it out.
"To ensure the best experience for your users, your app needs to be prepared to catch errors for the above scenarios. The following PHP code shows you how to handle these errors and retrieve a new access token.
When you redirect the user to the auth dialog, the user is not prompted for permissions if the user has already authorized your application. Facebook will return you a valid access token without any user facing dialog. However if the user has de-authorized your application then the user will need to re-authorize your application for you to get the access_token." Resource: https://developers.facebook.com/blog/post/2011/05/13/how-to--handle-expired-access-tokens/