Auth
Facebook Connect provides the great benefit of removing the registration process by allowing the User to login to your site with their Facebook account. This is achieved by sharing the logged-in user state between http://www.facebook.com/ and your site http://www.example.com/. A Connected user remains logged-in to your site as long as they are logged-in to Facebook.
This means you get to skip a lot of the boring stuff when you're building your hot new application. No need for a registration flow, or uploading a new Profile Picture, or remembering your username. But not only that, you also get the user's social graph, and many other useful pieces of information. Facebook Connect can also be used with your existing User management system as many sites already do.
Status & Sessions
FB.loginStatus(), FB.login() and FB.logout() return a response object containing these properties:
| Property | Description |
|---|---|
| status | Status of unknown, notConnected or connected. |
| session | Session Object. |
| perms | Comma separated list of permission names (perms). |
Example:
FB.login(function(response) {
alert(
'Status: ' + response.status +
'\nUID: ' + (response.session ? response.session.uid : 'unavailable') +
'\nPerms: ' + response.perms
);
}, 'email');
Status
The status allows you to distinguish between 3 possible states:
| Status | Description |
|---|---|
| unknown | Facebook doesn't know who the user is. |
| notConnected | Known user who hasn't authorized your application. |
| connected | Known user who has authorized your application. |
Session
Sessions are how you identify users, gain access to their data and perform interactive actions. Facebook is the authority for Sessions, and shares login state with your Connect enabled site. Sessions are attached to your API key, and will only be issued to your application's domain. The session is comprised of:
| Property | Description |
|---|---|
| uid | The User ID. |
| session_key | Session Key for making API calls. |
| secret | Session Secret for making API calls. |
| expires | Unix Timestamp of Session expiry time. |
| signature | Signature for the Session based on your API Secret. |
Perms
Currently this is a comma separated list of perms names granted for a specific call. This will be changing soon.
Flows
Its convenient to think of various independent flows with respect to authentication. This makes it easy to understand common flows and approaches and how to handle them.
- The code shown below is for conceptual understanding rather than literal examples. There are real examples too.
- The DOM access and event handlers in the JavaScript are using the lowest common denomination in browsers to focus on the Mu aspects of the code. For a real world site, you probably want to use one of the various JavaScript libraries instead.
- The code uses a unit test style approach to indicate what behaviours are expected in a given flow.
Logged Out User
- User is not logged into www.facebook.com
- User visits www.example.com
- www.example.com does not get a session
This is the unknown status. If www.facebook.com does not know who the user is, it cannot tell www.example.com anything about them. The user may be Connected with your site, just not logged in. Or they may be someone new to www.example.com as well as www.facebook.com. Example:
FB.loginStatus(function(response) {
assert(!response.session, 'a session object will not be available');
assert(response.status == 'unknown', 'status is unknown');
});
notConnected User
- User is logged into www.facebook.com
- User has not authorized www.example.com
- User visits www.example.com
- www.example.com does not get a session
This is the notConnected status. In this case www.facebook.com knows who the user is, but it cannot tell www.example.com anything about them because the User has not authorized this action. Example:
FB.loginStatus(function(response) {
assert(!response.session, 'a session object will not be available');
assert(response.status == 'notConnected', 'status is notConnected');
});
Connected User
- User is logged into www.facebook.com
- User has authorized www.example.com
- User visits www.example.com
- www.example.com gets a session
This is the connected status. In this case www.facebook.com knows who the user is, and the user has authorized www.example.com. So it will return a session to www.example.com. Example:
FB.loginStatus(function(response) {
assert(response.session, 'a session object will be available');
assert(response.status == 'connected', 'status is connected');
});
Connect with Facebook
- User visits www.example.com
- www.example.com does not get a session
- www.example.com shows User a Connect with Facebook button
Typically, you will not differentiate between the Logged Out User status and the notConnected User status. You should ignore the status property of the response, and use the session property to decide what to do. Example:
FB.loginStatus(function(response) {
if (response.session) {
showUserInfo();
} else {
showConnectWithFacebookButton();
}
});
If a session is not available, you should show the user a Connect with Facebook button. For example, using the large button which triggers the login flow when clicked:
<img
id="facebook-login"
style="cursor: hover;"
src="http://static.ak.fbcdn.net/images/fbconnect/login-buttons/connect_white_large_long.gif">
<script>
document.getElementById('facebook-login').onclick = function() {
FB.login(function(response) {
if (response.session) {
alert('Thank you for logging in.');
} else {
alert('You need to login to use www.example.com');
}
});
};
</script>
Login to www.facebook.com and www.example.com
- User has a Facebook account
- User is not logged into www.facebook.com
- User visits www.example.com
- www.example.com does not get a session
- www.example.com shows User a Connect with Facebook button
- User logs into www.facebook.com and www.example.com
Once you showed the user the Connect with Facebook button, and they clicked on it, they will be promped to login. Here's what the login popup looks like:
Here the user can login into Facebook, and grant your application a session in one step. This works for both a User that has never used www.example.com or a returning user.
Authorize www.example.com
- User has a Facebook account
- User is logged into www.facebook.com
- User visits www.example.com
- www.example.com does not get a session
- www.example.com shows User a Connect with Facebook button
- User Authorizes www.example.com
If the User is already logged in to Facebook, but has not authorized www.example.com, then clicking on the Connect with Facebook button will trigger a dialog confirming the user wants to authorize www.example.com. Here's what the Authorization dialog looks like:
New User Sign-Up
- User does not have a Facebook account
- User visits www.example.com
- www.example.com does not get a session
- www.example.com shows User a Connect with Facebook button
- User sign's up for a new account and authorizes www.example.com
If the user does not have a Facebook account, they can click on the Sign up for Facebook link on the bottom left of the login screen (from the Login to www.facebook.com and www.example.com flow) to sign up and authorize your site in one step. Here's what the sign-up process looks like:
Coding Approaches
Depending on how your application is built, there are a few different techniques that can be applied to help manage the user state.
I only make API calls on the Server using a Session from the Cookie
This is by far the most popular usage scenario, where you want to minimize the JavaScript you need to write, and do full page generation on the server (in PHP, Python, Ruby or any language of your choice). In addition, you make all your API calls on the server.
Suppose you have 3 URLs:
| URL | Description |
|---|---|
| /profile | Profile of the current User (hence, user required) |
| /news | News section that does not require a User |
| /login | Where you show the user a Connect with Facebook button |
On each request to the server, one of a few things can happen:
- You get a session in the cookie, you make an API call to facebook, all good. You have a Connected user.
- You get a session in the cookie, you make an API call to facebook,
and you get a session expired error.
- If this was the /news page, you'd render the logged out view.
- If this was the /profile page, you'd redirect the user to /login.
- You do not get a session in the cookie.
- If this was the /news page, you'd render the logged out view.
- If this was the /profile page, you'd redirect the user to /login.
Here's an example where you simply want to refresh the page every time the session changes. This should be included on every page, and will handle setting the cookie, clearing the cookie and reloading the page to let the server know if session changes:
// initialize the library
FB.init({
apiKey: 'YOUR API KEY',
cookie: true // enable cookie support
});
// if the session changes, we simply want to refresh the page. this
// will allow the server to notice the new cookie and do the right
// thing.
FB.Event.subscribe('auth.sessionChange', function(response) {
window.location.reload(true);
});
I want to store the session on the server, no Cookies please
Advanced Technique.
If you are very performance concious, then you may not want the Cookie overhead if you are already using server sessions identified via your own Cookie. In this case, you may have a server end point which can accept a Facebook session and store it against your server session. Don't forget the Signature Validation process on the server.
On each page load, you must return the session (or null) to the front end. This is required as Mu needs the active user session to allow using its functionality. Here's an example, which initializes Mu with the session returned by your server, and sets up a status handler to call a hypothetical updateSessionOnServer function to notify the server of the change in session:
// session from the server
var serverSession = { ... };
// initialize the library
FB.init({
apiKey: 'YOUR API KEY',
cookie: false, // disable cookie support
session: serverSession // provide the default session (can be null)
});
// if the session changes, we update it on the server (not shown here).
FB.Event.subscribe('auth.sessionChange', function(response) {
updateSessionOnServer(response.session);
serverSession = response.session;
// do something else, or maybe refresh the page
});
Signature Validation
TODO