Menu hamburger icon

Creating Twitter Single Sign On App with Monaca using Angular 1 and Onsen UI v2

Authentication and Profile Pages

In this article, you will learn how to use Twitter Single Sign On (SSO) with Monaca Cloud IDE using Angular 1 and Onsen UI. The authentication is done by using twitter-connect-plugin. This plugin uses Twitter’s Fabric SDK to enable SSO with your Android and iOS apps. After a successful authentication, the user’s basic information will be displayed in the app.

Tested Environments: Android 6.2 & iOS 10.1

Prerequisite

Getting Twitter Consumer Key and Consumer Secret

You are required to obtain Consumer Key and Consumer Secret by registering your Monaca app with Twitter Apps page. Please do as follows:

  1. Go to Twitter Apps page and sign in with a valid Twitter account.
  2. Click on Create New App button.
  3. Fill in the information of your app such as: Name, Description, Website and Callback URL (optional). Then, tick Yes, I have read and agree to the Twitter Developer Agreement. and click Create your Twitter application button.
  4. Go to Settings tab and tick Allow this application to be used to Sign in with Twitter. Then, click Update Settings button.
  5. Go to Keys and Access Tokens tab, you will find the Consumer Key and Consumer Secret here.

Getting Fabric API Key

In order to get Fabric API key, please do as follows:

  1. Login to Fabric account and open Crashlytics page. If you are new to Fabric, please sign up here.
  2. Find your API Key in inside <meta-data> code block in AndroidManifest.xml file (see the screenshot below).

Fabric API Key

Step 1: Creating a Project

From Monaca Cloud IDE, create a new project with a template called Onsen UI v2 Angular 1 Minimum.

Step 2: Adding the Plugin

  1. From Monaca Cloud IDE, please import twitter-connect-plugin. For more details, please refer to Add/Import Cordova Plugins.
  2. Add the Fabric API Key to the plugin’s configuration.

Plugin Configuration

Step 3: Editing config.xml File

  1. Open the config.xml file and add the following code within the <widget> tag. Please remember to replace your own Twitter Consumer Key and Twitter Consumer Secret.

    <preference name="TwitterConsumerKey" value="<Twitter Consumer Key>" />
    <preference name="TwitterConsumerSecret" value="<Twitter Consumer Secret>" />
    
  2. Save the file.

NOTE: For iOS, the deployment target needs to be at least 7.0. You can set this in the config.xml file like so:

<preference name="deployment-target" value="7.0" />

Step 4: It’s Coding Time!

File Tree

In this sample application, there are 4 main files such as:

  • index.html and home.html: Each one of these pages is a combination of HTML, Onsen UI v2 and Angular 1 elements.
  • style.css: This is a stylesheet for the application.
  • app.js: An Angular 1 file containing a service and a controller used in the application.

index.html

This is, of course, the main page of the application, the one loaded by default. Replace the following code to index.html file:

<!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 >
    <ons-navigator id="myNavigator" page="home.html"></ons-navigator>
</body>
</html>

As you can see, inside the body there is only an component. It provides page stack management and navigation. The attribute page is used to identify the first page in the stack. Since we have only one main page in this sample application, home.html (will be described in the next section) is of course the first in the page stack and will be loaded as soon as the index.html file is completed.

home.html

Please create a home.html file with the following content:

<ons-page ng-controller="HomeCtrl as home" ng-init="CheckLoginStatus()">
    <ons-toolbar>
        <div class="center">Twitter Demo</div>
        <div class="right" ng-show="login_status">
            <ons-toolbar-button ng-click="Logout()">
                <ons-icon icon="fa-sign-out"></ons-icon>
            </ons-toolbar-button>
        </div>
    </ons-toolbar>
    <div class="page">
        <div ng-hide="login_status">
            <p class="center">
                Welcome to Twitter Demo with Monaca using Onsen UI and AngularJS!
            </p>
            <ons-button ng-click="Login()">                    
                Connect to Twitter
            </ons-button>        
        </div>
        <div ng-show="login_status">
            <p class="center">
                <p>Currently, logged in as <b>{{user.name}}</b></p>
                <img src="{{user.profile_url}}" class="profile">
                <p>(@{{user.screen_name}})</p>
                <p>{{user.description}}</p>
                <p><ons-icon icon="fa-map-marker"></ons-icon> {{user.location}}</p>
            </p>
        </div>
    </div>
</ons-page>

This page contains two sections which is shown based on the login status (login_status variable) of the user in the application:

  1. Login section: This section is shown if there is no existing login information found in the device.

    Login Section

  2. Profile section: When the existing login info is found, this section will be displayed.

    Profile Section

style.css

There is a default empty style.css file after you creating a project with the specified template. Add the following code to it. The main purpose of this sheet is simply for the page and Twitter profile image.

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: #1da1f2;
}

.button {
    background-color: #1da1f2;
}

app.js

This is an Angular 1 file containig a service and a controller used in the application. Add the following code to app.js file:

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) {
    $scope.CheckLoginStatus = function(){
        $scope.user = StorageService.getLoginUser();
        console.log(JSON.stringify($scope.user));
        //check if there is any stored information of a login user
        if(JSON.stringify($scope.user) === "{}"){
            console.log('No login info!');
            $scope.login_status = 0;
        } else {
            console.log('Login info is found!');
            $scope.login_status = 1;

        }
    }

    $scope.Login = function(){
        TwitterConnect.login(
            function(result) {
            console.log('Successful login!');

            TwitterConnect.showUser(
                function(user) {
                    //Get larger profile picture
                    user.profile_url = user.profile_image_url.replace("_normal", "");
                    StorageService.setLoginUser({
                        name: user.name,
                        screen_name: user.screen_name,
                        location: user.location,
                        description: user.description,
                        profile_url: user.profile_image_url.replace("_normal", "")
                    });
                    myNavigator.pushPage('home.html');
                }, function(error) {
                    console.log('Error retrieving user profile');
                    console.log(error);
                }
            );

            }, function(error) {
                console.log('Error logging in');
                console.log(error);
            }
        );   
    }

    var LogoutFromTwitter = function(){
        TwitterConnect.logout(
            function() {
                console.log('Successful logout!');
                StorageService.setLoginUser({});
                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: 'Twitter Demo',
            buttonLabels: ["Yes", "No"],
            callback: function(idx) {
            switch (idx) {
                case 0:
                    LogoutFromTwitter();
                case 1:
                    break;
                break;
            }
          }
        });
    }
});

Inside this file, there is service called StorageService to store the login information of the user using the device’s Local Storage.

There is also one controller called HomeCtrl which consists of two main functions such as Login() and Logout(). Inside the Login() function, TwitterConnect.login() is called asking the user the login with a valid Twitter account information.

NOTE: If you have logged in with a Twitter application on your device, the information of that account will be shown automatically (see the screenshot below as example). If you want to login with a different account, please go to your Twitter application and change the account there.

Authentication

After a successful login, StorageService is called to store the login information and you will be directed back to home.html page showing the profile information of the logged in user. Inside the Logout() function, a confirmation dialog is shown to confirm the activity (see the screenshot below). If the user selects Yes, the TwitterConnect.logout() function is called and StorageService is also called to remove the login information.

NOTE: This Logout() function can only log the user out of this application, not the Twitter application.

Confirmation

Conclusion

Until this point, you have completed a Twitter SSO app with Monaca. Now, you can start testing your app with Monaca Debugger. Then, try to build it and install on your device.

Comments