Facebook login to existing user database, and access tokens - facebook

Trying to add facebook login to an existing login system on a project I am working on. Built with angular, using the FB JS SDK. This is primarily to allow frictionless login, and not currently that fussed about using the access tokens to make further calls with the FB API.
So as a new user, they hit the FB login, accept permissions etc, and it fires me back an access token etc. The new user is created in my DB, along with the accesstoken, FB userid, etc.
How do I now authenticate the user with the userid and accesstoken now stored in my DB? As far as I can see, the access token changes on virtually every page load / request, so next time the user hits the FB login, or I check the FB login status the only constant thing I have is the userid.
Have done various reading on SO and FB docs eg:
https://developers.facebook.com/docs/facebook-login/web
https://developers.facebook.com/docs/facebook-login/multiple-providers
https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow#checktoken
How should a Facebook user access token be consumed on the server-side?
... although that has only served to confuse things further.
I imagine I would take that stored accesstoken then check its validity, however due to the various instances of access tokens expiring and being invalidated, this also seems like an incomplete solution.
So my question: How do I securely authenticate my FB users with their counterpart user in my own DB?

The Facebook login request returns user id + short lived access token (client side).
Use the server side Facebook SDK to check the validity of the access token (will return user_id and app_id fields if valid).
You can trust the user_id field returned from the Facebook API to check against your existing user database.

Related

Facebook authentication without storing an access token?

I'm writing a React app that needs to have a login with Facebook button.
The React app is already communicating with a PHP API that already has a system in place for registering and logging in users with a username/password. The API generates a JWT and sends it to the front-end, which stores it in local storage and uses it to authenticate the user on subsequent API calls.
I've gotten my front-end app to the point where I'm successfully opening the FB permissions dialog, and receiving a response from FB that contains a userID & accessToken after the user grants permission.
My question is:
Do I need to store the FB accessToken if I don't need to access FB's API afterwards? Can I simply store the userID and use it for authentication?
My proposed auth flow would look something like this:
User clicks login with Facebook button, grants permissions in the dialog.
My React app sends the userID to my PHP API.
The API looks up the user in our DB by FB userID. If it finds one, it sends back a valid JWT, logging in the user.
If no user is found, the userID will be stored in the app's state, and it will begin the registration process, passing the FB userID along with the rest of the registration data when the user completes registration. The API then generates a JWT and proceeds with login like normal.
Would this be wildly insecure and a would be hackers easiest-day-ever?
Or is it safe to implement?

Facebook login API: avoid user hijacking

I am using FB js SDK to allow logging in on my platform. A user permits the needed access and I save his ID in my DB. The data is sent to my server via AJAX. Since the login is with FB, I can identify the user only by his ID.
Now, lets say I know someones FB ID and I know he has an account on my platform. In runtime, I can place his ID in the auth request and obtain a legit session of that user. How could that be avoided?
First of all, those are App Scoped IDs, it is very unlikely that someone would know the ID of a user who authorized your App, because it´s not the "real" ID.
That being said, you can (and should) send the User Token to the server and confirm the ID by calling the /me endpoint with that Token. You should also use appsecret_proof for API calls, more information can be found in the docs: https://developers.facebook.com/docs/graph-api/securing-requests

Is redirect to Facebook needed when the access token has expired?

Let's suppose there is a website which wants to post on Facebook in the users' name. First, when the user is linked to Facebook, he will have an access token and read access so he can log in with Facebook to the website, for instance. On a given event, the user will have write access on Facebook with the access token.
After a while, the Facebook access token expires (as it seems, but if there is a way to create Facebook access tokens which will never expire I would be glad to hear about), so on the website whenever a post to Facebook is about to be made, a request has to be sent to Facebook to check the validity of the access token. If the access token is invalid, then a redirect is needed to Facebook where a new access token is generated, then Facebook redirects back to the page.
I think there are no permanent Facebook access tokens. If there are permanent Facebook access tokens, how can one create them?
If a Facebook access token expires, is there any other solution to the problem than redirecting to Facebook for access token generation and redirecting back?
EDIT:
Here: https://developers.facebook.com/docs/opengraph/howtos/publishing-with-app-token/
I have read the section with the title of "Making API Calls to Publish with an App Access Token".
It states that I need the user's FacebookID and the publish_action privilege granted by the user to be able to post in their name on Facebook. However, I am puzzled about the way I can get the user's FacebookID and how the user grants the website publish_action privilege. Also, this section mentions that
"You will be unable to retrieve information about the status update post with the given ID using the app access token. Instead, you should use a user access token for such purposes."
I do not really understand what information is impossible to be retrieved with this possibility. I do not really understand the cause of inferiority of this strategy compared to the strategy with access tokens.
The short answer is yes, you have to redirect to Facebook (or use the Javascript SDK) to get FB to give you a new access token. If the user is already logged in to Facebook and hasn't deleted your application, then the process will be mostly invisible to your user.
You can, however, extend the length of time you're allowed to use your access token from 1-2 hours to a much longer period (I can't find the time reference, but I seem to remember it being a 3-6 month period). You can read about that process in the Access Tokens Documentation.
edit
First, you have to understand the difference between an App access token and a User access token. An app access token is a very simple token that facebook uses to verify that your app is making a request that you intended it to make. Your app access token consists of your app id and your app secret as a string and separated by a | character. This token doesn't grant you access to any user information, and isn't really usable for a whole lot of things (it's basically used for the authentication methods to ensure that when you request the token, the request is coming from you and not some 3rd party masquerading as you). Though, like you found above - you can also use it to make posts to the user's feed, providing they gave you access.
A user access token identifies an actual user, and their session, to your application. The user access token typically lasts a couple of hours and then expires. You can exchange this token for an extended access token which as I stated above, I believe to last for several months.
A user token (either the temporal 1-2 hour version, or the extended version) allows you to access the FB graph API as the user to which the user belongs. So, using these tokens you can access the user's friend list, photos, likes, interests, etc (presuming you requested permission to do so upon application install). You can check which permissions you have by using the user access token and making a request to /me/permissions on the graph api.
The Javascript SDK is unique, as it doesn't require you to redirect your user away from your application. The JS SDK allows you to use a pop-up to allow the user to authenticate with facebook, install your application, or to allow (or deny) permissions that you are requesting.
The FB.login method takes 2 parameters. Parameter 1 is the callback which is executed after the user responds to your authentication prompt (either by accepting or rejecting your application install request). Parameter 2 is for options which are passed as a javascript object, the only one of which you care about here is the scope parameter. The scope parameter is the way you ask for extended permissions (such as publish_action) so in order to acquire the publish stream permission from a user you use code that looks like this
<script type="text/javascript">
FB.login(function(response)
{
//check to see if they accepted or rejected, and do something
}, { scope: "publish_action });
</script>
Once the user accepts, any subsequent calls to the FB JS SDK will automatically include your user's access token, you don't have to manage it yourself. You can make calls to the graph API on behalf of the user without having to explicitly specify the user's user id - you can just reference them as me. So, for example, you could publish to your user's feed via the JS SDK like so:
<script type="text/javascript">
FB.api('/me/feed', 'post', { message: 'test!' }, function(response)
{
//do things
});
</script>
However, if you'd rather make calls to the Graph API from your server on behalf of the user to publish to their feed (or your needs require you to do so), you'll have to store the user's FB User ID along with your user data so you can access it later. That User ID is available in the argument that is passed to the FB.login callback (response.authResponse.userID). Once you store that, you'll be able to make Graph API calls on behalf of your user from your server simply by POSTing to /<user_id>/feed with the appropriate data:
$ curl -d "message=test&access_token=<app_access_token>" /<user_id>/feed
Finally, re-authenticating your user. THE FB JS SDK exposes 3 methods for authentication.
FB.getAuthResponse
FB.getLoginStatus
FB.login
The primary difference between FB.getAuthResponse and FB.getLoginStatus is that getAuthResponse waits for a response from Facebook before any further javascript is called (it's blocking, or synchronous). FB.getLoginStatus will allow other javascript to run and will call your supplied callback when it gets a response, allowing you to do other things while you wait for a response. Either of these methods can be used to determine if your user is currently logged in to Facebook and if the user has your application installed. You can then use FB.login (if they're not logged in to FB, or not users of your app) to prompt them to login, or install, so you can access their information. Both of these methods pass you back the user's access token if they're installed and have authorized your app (response.authResponse.accessToken).
FB.login does a check for the login status of the user, but it always will pop up a login/install dialog, regardless of the status (and if they're logged in/installed, it will hide the pop-up immediately). The FB.login method is also used if you need to request additional permissions from the user (Say you just get a "vanilla" install at first, and then later the user says they want you to post to their feed. When they initiate that option, you can then request the extended permission from them). In order to utilize that functionality, you use FB.login just as you would if they were a new user, except you add the extended permissions that you want/need in the scope property of the options variable you pass as the 2nd argument.
tl;dr
Use FB.getAuthResponse or FB.getLoginStatus to determine if your user is logged in and has your application installed. These methods can also be used to fetch new access tokens as your user is using your application.
Use FB.login to get new/unauthenticated users to install your application.
Once your user logs in, fetch their user id and store it your database somewhere. This can be used to post on their behalf with your app access token once you acquire the publish_action permission from the user
If you want to store a long-lived user access token to access the user's profile and other information, later, use the link above for exchanging your user access token for an extended access token. This is a server-side process, and you can store the resulting access token in your database with the user's other credentials.
Sorry this so long and wordy - I just wanted to provide you with some solid information about access tokens, how they're used, and how to use the JS SDK to maintain them. Hope this helps.

is it possible to access user's wall info without passing his/her access token?

I wonder is it possible to access user's wall info without passing his/her access token?
for example, I will just pass my app secret token and app id. and FB user already allows to access his/her info from my app. Facebook does the checking and matching of my app and my app's user by just using my app secret token and app id.
Because I found some topics similar to that.
http://forum.developers.facebook.net/viewtopic.php?pid=9172
When I check Rest FB doc,it says like that.
http://restfb.com/javadoc/index.html
public DefaultFacebookClient()
Creates a Facebook Graph API client with no access token.
Without an access token, you can view and search public graph data but can't do much else.
I doubt that it will work or not without access token.
can everyone share me ideas or any possible similar approaches ?
Thanks.
You will need to ask the users to authorize your app for offline access. You will be able to access the user's wall even if the user is offline, but you still need the access token. It is part of Facebook's security measures.
There are two types of access tokens:
Session based: expires in a short term, are used when the user will be logged to FB every time you need to perform an operation.
Offline access: do not expire and allow the app to perform operations for the user in any moment. This requires the offline_access permission when the app is authorized.
Check here: http://developers.facebook.com/docs/authentication/ for the oauth mechanism and here: http://developers.facebook.com/docs/authentication/permissions/ for the permissions list.
The REST API is deprecated and it is strongly suggested that you don't use it anymore. Furthermore, from this October you will be allowed to use only the Oauth2 authentication (see When is Facebook turning off their session based auth?)
Without token you can only access public information.
Public data
From RestFB homepage :
// It's also possible to create a client that can only access
// publicly-visible data - no access token required.
FacebookClient publicOnlyFacebookClient = new DefaultFacebookClient();
If the user does not protect his posts, then you can access everything without token. But most of user do protect their data and then you need a valid user access token to read the data.
Private data
When you say "FB user already allows to access his/her info from my app" it means that the user has clicked on "Allow app" in the web browser and at that moment here Facebook will give you a token. You can after use that token with RestFB :
FacebookClient facebookClient = new DefaultFacebookClient(USER_ACCESS_TOKEN);
User user = facebookClient.fetchObject("me", User.class);
out.println("User name: " + user.getName());
By default, the token will expire a few hours later. If you ask for the offline_access permission, the token will be valid for ever (as long as the user does not remove the permission for your app in his settings). You should store that token in your database to be able to use it when you need.
Get the user token
You cannot get the user token with RestFB. On the RestFB homepage, you can read :
Non-goals: [...] Providing a mechanism for obtaining session keys or OAuth access tokens
Because you need a browser to do so : the user has to authenticate and authorize your app on Facebook website (the popup that shows).
What you can do is to have a PHP page on which your users have to go to authorize your app. You can read this stackoverflow answer that explains how to use the Facebook PHP SDK to do so.
Hope that helps !

Facebook Javascript API: matching a login to a user

When using the Javascript API login, it returns to the page with a number of parameters, like the access token, the user ID, and other details. If I wanted to associate a user in my database with this Facebook user, which would be the piece of data I want to store to be able to look it up later for authentication?
In other words, which token should I store, so that next time the user logs in, I can look in the database for this token and authenticate the user?
I would use the UID, but it seems easy to spoof another UID and impersonate someone else.
Thanks!
Client side spoofing is not your concern. If you are displaying FB content based upon FB authentication, then FB is responsible for the integrity of that process.
If you are using this info server side, then you need to follow the OAuth 2.0 flow which is not spoofable (to my knowledge) because you are going directly to FB for authentication.
You can't mix the two flows because you leave yourself vulnerable to attacks.
And to answer your other question, yes, you should link your DB to the UID because the access_token will change.
You can validate the fb access token with the fb js sdk. So you can take the fb-uid as save. The tokens you get from fb are only valid for a limited time, so you shouldn't save them.
UPDATE:
Regarding the saveness of the fb-uid: Your PHP script gets a signed request from facebook. That request is signed with your app's secret so that no one else can read that data. The request contains a fb-session for the current user (including the uid) and an access token.