# Facebook Single Sign-on App

In this page, you will learn how to use Facebook's Single Sign-On (SSO) with Monaca Cloud IDE using Angular 1 and [Onsen UI](https://onsen.io/). The authentication is done by [cordova-plugin-facebook4](https://github.com/jeduan/cordova-plugin-facebook4). This plugin will use the native Facebook app to perform Single Sign On for the user; otherwise, the sign on will degrade gracefully using the standard dialog based authentication.

{% hint style="info" %}

* To check third party cordova plugins, you need to create a custom build debugger ( [Android version](https://en.docs.monaca.io/products_guide/debugger/installation/debugger_android#build-and-install-custom-monaca-debugger) or [iOS version](https://en.docs.monaca.io/products_guide/debugger/installation/debugger_ios#how-to-build-custom-monaca-debugger)
* The following settings are required in config.xml.

`<platform name="android">`\
&#x20;    `<preference name="android-minSdkVersion" value="22"/>`\
&#x20;`</platform>`
{% endhint %}

## Demo

[Import Facebook Single Sign-on App to your Monaca Account](https://monaca.mobi/directimport?pid=591abc668034513c335e2ecf)

**Tested Environment**

* Android 11.0
* iOS 14.3

![](https://3091308003-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MfWe1U2tFctp8FkP9W8%2F-MfajZI-CU9Oiq6FhCqs%2F-MfampHeVm6WUFZ0Bfae%2Fimage.png?alt=media\&token=5d3a2183-8d52-4553-b877-3083137847ee)

## Prerequisite

`APP_ID` and `APP_NAME` are required by the `cordova-plugin-facebook4` plugin. These two values can be found in the Facebook for Developer console after registering your app. To do so, please proceed as follows:

1. Go to [Facebook for Developers](https://developers.facebook.com/) and log in with your Facebook account.
2. Go to `My Apps → Add a New App`.

![](https://3091308003-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MfWe1U2tFctp8FkP9W8%2F-MfajZI-CU9Oiq6FhCqs%2F-MfaneWmNW2QNBIxQoGu%2Fimage.png?alt=media\&token=66fd1ca8-43fc-4ede-962a-b9bbb1b2f087)

&#x20;   3\. Input the necessary information of your app and click `Create App ID`.

![](https://3091308003-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MfWe1U2tFctp8FkP9W8%2F-MfajZI-CU9Oiq6FhCqs%2F-Mfanm5wO_Vy71Us85Ib%2Fimage.png?alt=media\&token=f1493a43-f662-45ed-be05-8deb7d2d5a7f)

&#x20;    4\. From the Dashboard, go to *Settings* and you will be able to find the `APP_ID` (App ID) and `APP_NAME` (Display Name).

&#x20;    5\. Now it’s time to add the platform(s) of the devices which will run your app by clicking `+ Add Platform` button.

![](https://3091308003-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MfWe1U2tFctp8FkP9W8%2F-MfajZI-CU9Oiq6FhCqs%2F-Mfanwv35HM4iLxOBUH9%2Fimage.png?alt=media\&token=bbce28c5-6dbd-4b33-a20c-94ad2d6ada0a)

&#x20;    6\. If your app will run on Android, select `Android`.

![](https://3091308003-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MfWe1U2tFctp8FkP9W8%2F-MfajZI-CU9Oiq6FhCqs%2F-Mfao3A5Ifb-n-UO5qSL%2Fimage.png?alt=media\&token=8708ec59-0a44-43b4-8a89-8c7aac0c177f)

&#x20;    7\. Fill in the necessary information as shown below and click `Save Changes` :

* `Google Play Package Name`: is the Android’s Package Name you configured in Monaca Cloud IDE for Android App Settings.
* `Key Hashes`: is the SHA-1 fingerprint of the KeyStore you configured in Monaca Cloud IDE for Android KeyStore Settings. Please refer to [How to get SHA-1 fingerprint of a keystore created in Monaca Cloud IDE](https://en.docs.monaca.io/faq/application#how-to-get-sha-1-fingerprint-of-a-keystore-created-in-monaca-cloud-ide).
* Enable `Single Sign On` option.

![](https://3091308003-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MfWe1U2tFctp8FkP9W8%2F-MfajZI-CU9Oiq6FhCqs%2F-Mfar7wzSS_Cxtw0pgpu%2Fimage.png?alt=media\&token=611ad8c9-9656-47a6-9408-c8c598b53d5c)

&#x20;    8\. If your app will run on iOS as well, Click `+ Add Platform` and select `iOS`.

&#x20;    9\. Fill in the necessary information as shown below and `Save Changes` :

* `Bundle ID`: is the iOS’s App ID you configured in Monaca Cloud IDE for iOS App Settings.
* Enable `Single Sign On` option.

![](https://3091308003-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MfWe1U2tFctp8FkP9W8%2F-MfajZI-CU9Oiq6FhCqs%2F-MfarGJ4kfXX_iNpxr0S%2Fimage.png?alt=media\&token=8e8a2c8e-8053-4feb-b8ba-fba456b79bc2)

## Importing the Project to Monaca Cloud IDE

[Import Facebook Single Sign-on App to your Monaca Account](https://monaca.mobi/directimport?pid=591abc668034513c335e2ecf)

## Configuring the Plugin

The authentication is done by [cordova-plugin-facebook4](https://github.com/jeduan/cordova-plugin-facebook4). This plugin will use the native Facebook app to perform Single Sign-on for the user; otherwise, the sign on will degrade gracefully using the standard dialog based authentication.

Before starting to use the plugin, you are required to input the `APP_ID` and `APP_NAME` values within the plugin’s configuration as follows:

1. From Monaca Cloud IDE menu, go to `Configure → Cordova Plugin Settings`.
2. Under the E*nabled Plugins* section, hover over `cordova-plugin-facebook4` and click `Configure` button.

![](https://3091308003-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MfWe1U2tFctp8FkP9W8%2F-MfajZI-CU9Oiq6FhCqs%2F-MfarNeQjSIitS9vprWp%2Fimage.png?alt=media\&token=fbfe56ad-1eff-48a9-9162-9fd81a90cfb7)

&#x20;   3\. Input the `APP_ID` and `APP_NAME` values you got in the [Prerequisite](#prerequisite) section. See the screenshot below as an example:

![](https://3091308003-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MfWe1U2tFctp8FkP9W8%2F-MfajZI-CU9Oiq6FhCqs%2F-MfarUBiyYRUIhvIv9dP%2Fimage.png?alt=media\&token=6912dce1-f637-4c79-b1f0-d02edc2b3b56)

&#x20;   4\. Click `OK` to complete the configuration.

## Application Explanation

### File Components

![](https://3091308003-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MfWe1U2tFctp8FkP9W8%2F-MfajZI-CU9Oiq6FhCqs%2F-MfarZMtX4TTLjQSyphj%2Fimage.png?alt=media\&token=f5cc752f-ddab-4d54-bd95-cbba4d56a81f)

| File            | Description                                             |
| --------------- | ------------------------------------------------------- |
| `index.html`    | The startup Page                                        |
| `home.html`     | Login Page                                              |
| `profile.html`  | User profile Page                                       |
| `css/style.css` | A stylesheet file for the application                   |
| `js/app.js`     | A JavaScript file for implementation of the application |

### HTML Explanation

#### index.html

```markup
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<meta http-equiv="Content-Security-Policy" content="default-src * data:; style-src * 'unsafe-inline'; script-src * 'unsafe-inline' 'unsafe-eval'">
<script src="components/loader.js"></script>
<script src="lib/angular/angular.min.js"></script>
<script src="lib/onsenui/js/onsenui.min.js"></script>
<script src="lib/onsenui/js/angular-onsenui.min.js"></script>
<script src="js/app.js"></script>

<link rel="stylesheet" href="components/loader.css">
<link rel="stylesheet" href="lib/onsenui/css/onsenui.css">
<link rel="stylesheet" href="lib/onsenui/css/onsen-css-components.css">
<link rel="stylesheet" href="css/style.css">
</head>
<body>
  <body >
      <ons-navigator id="myNavigator" page="home.html"></ons-navigator>
  </body>
</body>
</html>
```

This file is the startup page of the application. As you can see within the `<body>` tag, there is only one [ons-navigator](https://onsen.io/v2/docs/angular1/ons-navigator.html) component. It provides page stack management and navigation. The attribute page is used to identify the first page in the stack.

#### home.html

```markup
<ons-page ng-controller="HomeCtrl">
  <ons-toolbar>
      <div class="center">Facebook Demo</div>
  </ons-toolbar>
  <div class="page">
      <p class="center">
          Welcome to Facebook Authentication Demo with Monaca using Onsen UI and AngularJS!
      </p>
      <ons-button ng-click="Login()">
          Connect to Facebook
      </ons-button>
  </div>
</ons-page>
```

This page is a login page. If there is existing login information found in the device, it will be automatically redirected to `profile.html` page.

#### profile.html

```markup
<ons-page ng-controller="ProfileCtrl">
  <ons-toolbar>
      <div class="center">Facebook Profile</div>
      <div class="right">
          <ons-toolbar-button ng-click="Logout()">
              <ons-icon icon="fa-sign-out"></ons-icon>
          </ons-toolbar-button>
      </div>
  </ons-toolbar>
  <div class="page">
      <p class="center">
          <img src="{{user.profile_url}}" class="profile">
          <p>{{user.name}}</p>
          <p>(@{{user.id}})</p>
          <p>{{user.email}}</p>
      </p>
  </div>
</ons-page>
```

This page is a user's Facebook profile page.

### Stylesheet Explanation

This file consists of the CSS style for the navigation bar and Facebook profile image.

```css
div.page {
 padding: 5%;
 text-align: center;
}

p.center {
  text-align: center;
}

img.profile {
  width: 40%;
  border: solid 1px #1da1f2;
  border-radius: 5px;
}

.navigation-bar {
  background-color: #4267b2;
}

.button {
  background-color: #4267b2;
}
```

### JavaScript Explanation

```javascript
ons.bootstrap()
.service('StorageService', function() {
  var setLoginUser = function(user_info) {
      window.localStorage.login_user = JSON.stringify(user_info);
  };

  var getLoginUser = function(){
      return JSON.parse(window.localStorage.login_user || '{}');
  };

  return {
      getLoginUser: getLoginUser,
      setLoginUser: setLoginUser
  };
})

.controller('HomeCtrl', function($scope, StorageService, $http, $q) {
  var CheckLoginStatus = function(){
      window.facebookConnectPlugin.getLoginStatus(
          function(data){
              if(data.authResponse){
                  console.log('Login info is found!');
                  myNavigator.pushPage('profile.html');
              }else{
                  console.log('No login info is found!');
              }
          },
          function(e){
              LoginError(e);
          }
      );
  }

  ons.ready(function() {
      CheckLoginStatus();
  });

  var GetProfileInfo = function (authResponse) {
      var info = $q.defer();

      facebookConnectPlugin.api('/me?fields=email,name&access_token=' + authResponse.accessToken, null,
          function (response) {
              info.resolve(response);
          },
          function (response) {
              info.reject(response);
          }
      );
      return info.promise;
  };

  var LoginSuccess = function(response){
      var authResponse = response.authResponse;

      GetProfileInfo(authResponse).then(function(user) {
          StorageService.setLoginUser({
              name: user.name,
              id: user.id,
              email: user.email,
              profile_url: "http://graph.facebook.com/" + authResponse.userID + "/picture?type=large"
          });
          myNavigator.pushPage('profile.html');
      }, function(error){
          console.log('Error retrieving user profile' + JSON.stringify(error));
      });

  };

  var LoginError = function(error){
      console.log('Login Error: ' + JSON.stringify(error));
      // When "User cancelled dialog" error appears
      if (error.errorCode === "4201"){
          CheckLoginStatus();
      }
  };

  $scope.Login = function(){
      facebookConnectPlugin.login(['email', 'public_profile'], LoginSuccess, LoginError);
  }


})
.controller('ProfileCtrl', function($scope, StorageService, $http, $q) {
  $scope.user = StorageService.getLoginUser();

  var LogoutFromFacebook = function(){
      facebookConnectPlugin.logout(
          function() {
              console.log('Successful logout!');
              myNavigator.pushPage("home.html");
          },
          function(error) {
              console.log('Error logging out: ' + JSON.stringify(error));
          }
      );
  }

  $scope.Logout = function(){
      ons.notification.confirm({
          message: "Are you sure you want to log out?",
          title: 'Facebook Demo',
          buttonLabels: ["Yes", "No"],
          callback: function(idx) {
          switch (idx) {
              case 0:
                  LogoutFromFacebook();
              case 1:
                  break;
              break;
          }
        }
      });
  }
});
```

Inside this file, there is a service, called `StorageService`, to store the login information of the user using the device's Local Storage. There are also two controllers such as `HomeCtrl` and `ProfileCtrl` which are the controllers for `home.html` and `profile.html` pages, respectively.

`HomeCtrl` controller consists of several functions used within the `home.html` page. Once, the page is loaded, the `CheckLoginStatus()` function is triggered to check if there is any existing login information. If the login information is found, the `myNavigator.pushPage()` function is called to navigate to `profile.html` page showing the user's Facebook profile as found in the login information. When the user clicks on `Connect to Facebook` button, the `Login()` function is triggered. In this function, the `facebookConnectPlugin.login()` function is called to show the native Facebook authentication dialog. If the login is successful, the login information will be stored in the device's local storage via `StorageService.setLoginUser()` function and then the `myNavigator.pushPage()` function is called to navigate to `profile.html` page.

{% hint style="info" %}
If you have logged in with a Facebook app on your device, the information of that account will be automatically grabbed and used in this app. If you want to login with a different account, please go to your Facebook app and change the account there.
{% endhint %}

However, if you do not have a Facebook app on your device or you have not logged in the existing Facebook app on your device, the authentication screen will appear:

In the `ProfileCtrl` controller, there are 2 functions: `Logout()` and `LogoutFromFacebook()`. The `Logout()` function is called when the user clicks on the Logout icon on the top-right corner of the Profile page. Inside the `Logout()` function, a confirmation dialog is shown. If the user selects `Yes`, both `LogoutFromFacebook()` function `StorageService` service are called to log the user out and remove the login information from the device's local storage, respectively.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://en.docs.monaca.io/sampleapp/samples/facebook_sso.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
