Social Login using Facebook in Node
Tags: facebook, sociallogin, node, authentication
Published: 2020-01-12 01:04:26

Social login has become an expected feature in web apps today.
Facebook login can be integrated into node app using the JS SDK. Since I drowned in the Facebook documentation for a considerable time to get my head around what to and what not to expect out of facebook login, I am writing down the way I designed it, expecting it might help someone. If you know a better way, let me know in comments :)


### 1. Create a Facebook app for your application
Go to https://developers.facebook.com/, create a developer account, create an app - which is a `www` type app since it is a web application we need the integration for.

### 2. Add the JS SDK
Follow the steps Facebook walks you through, which are pretty easy and you will end up having a code snippet that is the JS SDK. Add the script tag next to the opening body tag. Which will look very similar to

```
<script>
  window.fbAsyncInit = function() {
    FB.init({
      appId      : '{YOUR-FB-APP-ID}',
      cookie     : true,
      xfbml      : true,
      version    : '{api-version}'
    });

    FB.AppEvents.logPageView();   

  };

  (function(d, s, id){
     var js, fjs = d.getElementsByTagName(s)[0];
     if (d.getElementById(id)) {return;}
     js = d.createElement(s); js.id = id;
     js.src = "https://connect.facebook.net/en_US/sdk.js";
     fjs.parentNode.insertBefore(js, fjs);
   }(document, 'script', 'facebook-jssdk'));
</script>

```
If you need to change the language of the Facebook window that opens, replace `en_US` with the country language code from https://developers.facebook.com/docs/accountkit/languages/

### 3. Check login status
Now its good to check the login status of the user using 

```
FB.getLoginStatus(function(response) {
    statusChangeCallback(response);
});
```

This can be added now with the snippet from step 2. Try logging the response and you will see the connection status.

Later, this method can be moved to a better place, say when your app loads, you can get the status of facebook login of the user. If already logged in and if permissions are given for your app earlier, you can login the user right away.

### 4. Add a login button

Three ways to do it :

1. Since I am using a react app, I would use [react-facebook-login](https://www.npmjs.com/package/react-facebook-login) package which wraps my html button as a react component.

```
import FacebookLogin from 'react-facebook-login';


<FacebookLogin
        appId={AppID}
        autoLoad={true}
        callback={loggedInCallback}
        icon="fa-facebook-square"
        cssClass="fb-customisation"
        textButton={'Continue with facebook'}
      />
```

2. If it suits the need, just grab the button from [Facebook Button generator](https://.facebook.com/docs/facebook-login/web/login-button) and bind click handlers.

3. Create a button you like and give it the required click handlers from facebook SDK.

```
const manualLogin = () => {
const FB = (window as any).FB;
 FB?.login((response: any) => {
   response.authResponse && 
 updateSocialLoginSuccess(response.authResponse.accessToken)},
   { scope: 'email' });
};
```

Once user clicks login, a window pops up and asks for username and password. If successful login happens, the user is asked permission for sharing the user data requested by the app.

### 5. Is all the data accessible?
Username and profile picture are public information and will be shared once you request it. When email is requested, user has to approve the sharing. Any other data needed has to be reviewed by facebook before your facebook app goes live. Note that now it is in Development mode. You can try to toggle the development mode and see the procedures needed to authorize the app to go live.


### 6. Logged in - is that all?
The idea is that, social logins will enable the user to login to our app without creating and remembering another set of username and password. However, our application should still know this user somehow, to save some data about him. For example, what if my application needs to save the items that the user added to cart in the db and retrieve later when the user logins again using Facebook. So basically, we still need to create an user in the application side using the Facebook data.

### 7. Meet User Access Tokens
My application will identify the user using the email. I can retrieve it in the client side but I don't like to send the users info over a request. 

```
FB.getLoginStatus(function(response) {
 console.log(response.authToken);
});
or 
FB.login(function(response) {
 console.log(response.authToken);
});
```

What I would rather do is that, I would send the userToken received from FB in the client side to the backend and let the server retrieve the user details there and save it to db. Ensure HTTPS for safety during this time transfer.

Basically -
1. user access tokens are portable. 
2. JS user access tokens are valid for approximately two hours since last user login

Read more here - ['User Access Token'](https://developers.facebook.com/docs/facebook-login/access-tokens/).

### 8. Retrieve user information at the backend
The server retrieves the user data using the Facebook graph API
`  https://graph.facebook.com/v5.0/me?fields=email,id,first_name,name&access_token={ACCESS-TOKEN-HERE};
`
### 9. Create a user id
The data retrieved is saved in the db. Now we have a user actually created in our system and any info can be stored for him/her and retrieved later. You may use the facebook userid or create a new user id from the retrieved data and save it.

### 10. Next login
Ok, we have a user in our system now, who can login using his facebook credentials. How would I identify the user, the next time he logs in and retrieve his details from the db? The user access token can be send to backend and can be used to get the email and retrieve his data. 

### 11. Subsequent requests
When further requests come in to the system - say, the user adds a new item to his cart or deletes one. How will we ensure that the incoming request is from the same user? You could use the user access token - but its not efficient to go around the whole procedure every time.

A clean solution would be to use an authentication mechanism of your own once the user has successfully logged in and authenticated on our side - something like a JWT token or a cookie - what ever suits the need. So for a given period of time, the user can authenticate himself using the JWT token and retrieve the data. Of course, you should ensure proper security by signing the JWT with your private key, using secure cookies or what ever that would make your authentication mechanism secure. 
 

[Read more on using JWT here] (https://dev.to/lek890/authentication-strategy-application-fastify-typescript-jwt-52nb#authentication)