API Tutorials - TextKey APIs

How to integrate TextKey

Standard authentication involves entering a login name and password and validating those credentials. TextKey adds a second layer of security above standard authentication. Integrating TextKey's 2nd level of securiy involves 4 steps.


This working PHP example is available on github. The package will include instructions on what configuration options need to be changed to use to use your own API Key and local setup.


Step 1 - Handling First Level Authentication - User/Password Verification

Most of the sample code in Step 1 is being used to show how to integrate the TextKey server side request for a valid TextKey with an existing login form and how to pass control onto the TextKey Javascript handler to display the TextKey message.

The three key elements in this Step are:

  • Integrating getting a TextKey after validating the username/password
    • This involves passing in the userid used when registering the user with TextKey
  • Saving the TextKey values for later validation (i.e. in Session Variables)
    • TextKey
    • TextKey Validation Code
    • Short Code
  • Returning the TextKey values back so that they can be used/displayed to the user
    • TextKey
    • Short Code

NOTE: This is strickly being used an a example and you can use whatetever first pass authentication handling you prefer.

Login Form - tutoriallogin.php

This is a basic login form. It uses jQuery, Simple Modal (i.e. a jQuery plugin to dispay messaging), and login.js (i.e. a Javascript login handler specific to this code example).

NOTE: There is nothing in this form that is TextKey specific.

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US" lang="en-US">
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<head>
    <title>TextKey Tutorial Login</title>
    <!-- Basic styling -->
    <link type='text/css' rel="stylesheet" href="css/textkey.css">

    <!-- jQuery -->
    <script src="http://code.jquery.com/jquery-latest.min.js"></script>
    
    <!-- TextKey JS Include to manage the Login Form -->
    <script type="text/javascript" src="js/login.js"></script>
    
    <!-- SimpleModal jQuery Include - Used for modal display -->
    <script type="text/javascript" src="js/jQuery.simplemodal-1.4.4.js"></script>
    
    <!-- TextKey JS Include to handle Polling -->
    <script type="text/javascript" src="js/textkey.js"></script>
    
    <!-- TextKey JS Include to customize the TextKey modal and callback handlers -->
    <script type="text/javascript" src="js/textkey_custom.js"></script>
</head>
<body>
    <form class="form-textkey" id="form-textkey">
      <h1>Login</h1>
      <p>
        <label for="login">Username</label>
        <input type="text" name="name" id='login-name' placeholder="Username">
      </p>
      <p>
        <label for="password">Password</label>
        <input type="password" name='password' id='login-password' placeholder="Password">
      </p>
      <p>
        <input type="submit" name="submit" value="Login" class='login-send' onClick="return login.handlelogin();">
      </p>
    </form>
</body>
</html>

Javascript Form Handler - login.js

login.js is a Javascript login form handler and handles both the login form and subsequent responses. The entire code sample is displayed below however here is the TextKey specific code which will trigger the display of the TextKey SMS message.

The key elements consist of a POST request to server side code that will verify the username/password are valid and then return back the key TextKey fields to be displayed in a modal dialog for the user (i.e. the TextKey and Short Code to send the text to).

    // Submit the form													   
    $.ajax({
        url: 'login.php',
        data: $('form').serialize(),
        type: 'post',
        cache: false,
        dataType: 'html',
        success: function (jsondata) {
            // Convert to an object
            data = eval(jsondata);
            
            if (typeof(console) !== 'undefined' && console != null) {
                console.log("data: " + jsondata);
                console.log(data);
            };

            // Check for a valid login
            if (data.error == "") {
                // Set the flag
                login.loggedin = true;
                
                // Set the textkey values
                login.textkey = data.textkey;
                login.textkeyVC = data.textkeyVC;
                login.shortcode = data.shortcode;

                // Handle the textkey login
                if (login.loggedin) {
                    textKeyHandler(login.textkey, login.shortcode);
                };
            }
            else {
                // Set the error message
                login.message = data.error;
                
                // Show the error message
                login.showError();
            };
        },
        error: login.error
    });

login.js

Here is the entire login.js source code.

/*
** 
** login.js
**
** This is the basic framework for the login page. 
**
** The key here is that the back end login code returns with a payload containing the TextKey to be displayed to the user.
**
*/

var login = {
	message: null,
	textkey: null,
	textkeyVC: null,
	shortcode: null,
	loggedin: false,
	init: function () {
		$('#form-textkey').bind('keypress', function (e) {
			if (e.keyCode == 13) {
				$('#form-textkey .login-send').trigger('click');
			}
		});
		return false;
	},
	handlelogin: function () {
		// validate form
		if (login.validate()) {

			// Submit the form													   
			$.ajax({
				url: 'login.php',
				data: $('form').serialize(),
				type: 'post',
				cache: false,
				dataType: 'html',
				success: function (jsondata) {
					// Convert to an object
					data = eval(jsondata);
					
					if (typeof(console) !== 'undefined' && console != null) {
						console.log("data: " + jsondata);
						console.log(data);
					};

					// Check for a valid login
					if (data.error == "") {
						// Set the flag
						login.loggedin = true;
						
						// Set the textkey values
						login.textkey = data.textkey;
						login.textkeyVC = data.textkeyVC;
						login.shortcode = data.shortcode;

						// Handle the textkey login
						if (login.loggedin) {
							textKeyHandler(login.textkey, login.shortcode);
						};
					}
					else {
						// Set the error message
						login.message = data.error;
						
						// Show the error message
						login.showError();
					};
				},
				error: login.error
			});
		}
		else {
			// Show the error message
			login.showError();
		}
		return false;
	},
	handlelogout: function (refresh) {
		$.ajax({
			url: 'logout.php',
			type: 'post',
			cache: false,
			dataType: 'html',
			success: function (data) {
				if (data == "") {
					if (refresh) {
						location.reload(true);
					}
				}
				else {
					if (typeof(console) !== 'undefined' && console != null) {
						console.log("data: " + data);
					};
				};
			}
		});
		return false;
	},
	error: function (xhr) {
		showModal('Login Error...', xhr.statusText, closeModal);
		return false;
	},
	validate: function () {
		login.message = '';
		if (!$('#form-textkey #login-name').val()) {
			login.message = 'Username is required.';
			return false;
		};

		if (!$('#form-textkey #login-password').val()) {
			login.message = 'Password is required.';
			return false;
		};

		return true;
	},
	showError: function () {
		showModal('Login Error...', login.message, closeModal);
	}
};

login.init();

PHP Tutorial Configuration Settings - config.php

You will need to replace YOUR_API_KEY with your API Key.

/*
** config.php
*/

/*
** TextKey Settings
*/
define('TK_API', 'YOUR_API_KEY');
define('TK_DISPLAY_API', TK_API);

// Whether or not the passwords are being hashed
define('TK_ISHASHED', '0');

PHP Login Handler - login.php

login.php is a PHP login form handler. The key elements consist of validating the user/password, getting a valid TextKey for that specific user, and then passing that back to the client side handler to display the TextKey message.

// Include configuration settings
include_once("config.php");

// Add TextKey PHP REST Library
include_once("textkey_rest.php");

// Add TextKey Session Handler
require_once("textkeysite.php");

// Code to handle the login for the specific site
function user_password_login($name, $password) {
	$userid = "";

	//
	// NOTE: This is where you would hook into your own internal authentication handler and return back the user id to 
	// handle assigning a TextKey
	//
	return $name;
}

// Validate the user login and get the TextKey dialog to display in the browser
function login_user() {
	global $textkeysite;

	// Setup
	$error_msg = '';

	// Create the textkey object
	$tk = new textKey(TK_API);
		
	// Get the passed in info.
	$name = isset($_POST["name"]) ? $_POST["name"] : "";
	$password = isset($_POST["password"]) ? $_POST["password"] : "";
	
	// HANDLE THE USER/LOGIN AUTHENTICATION HERE
    // NOTE: The $textkey_userid value should be the user id that was used to register the specific user in the 
    // TextKey Database (i.e. via the TextKey Administration Application or via the  registerTextKeyUser API Call 
	// or registerTextKeyUserCSA API Call).
	$textkey_userid = user_password_login($name, $password);

    // If the username/password combination is validated then continue
	if ($textkey_userid != "") {
	
		// Handle setting the sesssion info.
		$textkeysite->setPassedLoginCheck($name, $textkey_userid);

		// Handle getting a valid TextKey using the user id
		$textkey_result = $tk->perform_IssueTextKeyFromUserId($textkey_userid, TK_ISHASHED);
		if ($textkey_result->errorDescr == "") {
			// No error so setup the return payload
			$reply_msg = '({"error":"", "textkey":' . json_encode($textkey_result->textKey) . ', "textkeyVC":' . json_encode($textkey_result->validationCode) . ', "shortcode":' . json_encode('81888') . '})';
	
			// Handle setting the textkey sesssion info.
			$textkeysite->setTextKeyInfo($textkey_userid, $textkey_result->textKey,  $textkey_result->validationCode, '81888');
	
			// Return the valid info. 
			return $reply_msg;
		}
		else {
			$error_msg = $textkey_result->errorDescr;
		}
	}
	else {
		$error_msg = "The name or password did not match. Please try again...";
	};
	
	// Handle clearing the sesssion info.
	$textkeysite->endSession();

	// Return the error
	$error_msg = '({"error":' . json_encode($error_msg) . '})';
	return $error_msg;
}

// Create the session handling object
$textkeysite = new textkeysite();

// Init the session values
$textkeysite->initSessionInfo();

// Login the user
$login_payload = login_user();

// Return the resulting payload
echo $login_payload;

exit;

textkeysite.php

Here is the entire textkeysite.php source code which consists of a class that sets and holds session information.

class textkeysite
{
	/*
	** Init the session information
	*/
    function initSessionInfo()  {
		// Start the login session
        if (!isset($_SESSION)) { 
			session_start(); 
		};

		// User login Info.
		$_SESSION['username'] = NULL;
		$_SESSION['userid'] = NULL;

		// TextKey info.
		$_SESSION['textkeycheckuserid'] = NULL;
		$_SESSION['textkey'] = NULL;
		$_SESSION['textkeyvc'] = NULL;
		$_SESSION['shortcode'] = NULL;

		// 2 pass flags
		$_SESSION['passedcheck1'] = false;
		$_SESSION['passedcheck2'] = false;
    }

	/*
	** Set the session info. after the user passes the first check (i.e. Login/Password)
	*/
    function setPassedLoginCheck($username, $userid)  {
		// Start the login session
        if (!isset($_SESSION)) { 
			session_start(); 
		};

		// User login Info.
        $_SESSION['username'] = $username;
        $_SESSION['userid'] = $userid;
		
		// 2 pass flags
        $_SESSION['passedcheck1'] = true;
    }
	
	/*
	** Set the textkey session info. after the user passes the first check (i.e. Login/Password)
	*/
    function setTextKeyInfo($textkeycheckuserid, $textkey,  $textkeyvc, $shortcode)  {
		// Start the login session
        if (!isset($_SESSION)) { 
			session_start(); 
		};

		// TextKey info.
		$_SESSION['textkeycheckuserid'] = $textkeycheckuserid;
		$_SESSION['textkey'] = $textkey;
		$_SESSION['textkeyvc'] = $textkeyvc;
		$_SESSION['shortcode'] = $shortcode;
    }

	/*
	** Set the session info. after the user passes the second check (i.e. textkey authentication)
	*/
    function setPassedTKCheck($username, $userid)  {
		// Start the login session
        if (!isset($_SESSION)) { 
			session_start(); 
		};
		
		// 2 pass flags
        $_SESSION['passedcheck2'] = true;
    }
	
	/*
	** Check to see if the first check passed (i.e. Login/Password)
	*/
    function getPassedLoginCheck()  {
		// Start the login session
		if (!isset($_SESSION)) { 
			session_start(); 
		}
		
		// If the username/login check has not passed them return false
		if ($_SESSION['passedcheck1'] != true) {
			return false;
		}
		
		return true;
    }

	/*
	** Check to see if the second check passed (i.e. textkey authentication)
	*/
     function getPassedTKCheck()  {
		// Start the login session
		if (!isset($_SESSION)) { 
			session_start(); 
		}
		
		// If the TextKey check has not passed then return false
		if (($_SESSION['passedcheck1'] != true) || ($_SESSION['passedcheck2'] != true)) {
			return false;
		}
		
		return true;
    }

	/*
	** End the entire session
	*/
    function endSession() {
		// Start the login session
		if (!isset($_SESSION)) { 
			session_start(); 
		}
        
		// Clear out all of the session variables
		$_SESSION['username'] = NULL;
		$_SESSION['userid'] = NULL;
		$_SESSION['textkeycheckuserid'] = NULL;
		$_SESSION['textkey'] = NULL;
		$_SESSION['textkeyvc'] = NULL;
		$_SESSION['shortcode'] = NULL;
		$_SESSION['passedcheck1'] = false;
		$_SESSION['passedcheck2'] = false;
    }

	/*
	** Session get function calls
	*/
    function get_userName() {
        return isset($_SESSION['username'])?$_SESSION['username']:'';
    }
    
    function get_userId() {
        return isset($_SESSION['userid'])?$_SESSION['userid']:'';
    }

    function get_tkuserId() {
        return isset($_SESSION['textkeycheckuserid'])?$_SESSION['textkeycheckuserid']:'';
    }

    function get_textkey() {
        return isset($_SESSION['textkey'])?$_SESSION['textkey']:'';
    }

    function get_textkeyvc() {
        return isset($_SESSION['textkeyvc'])?$_SESSION['textkeyvc']:'';
    }

    function get_textkeyshortcode() {
        return isset($_SESSION['shortcode'])?$_SESSION['shortcode']:'';
    }
}

Step 2 - Displaying the TextKey message.

The callback from the Login form submit now needs to handle displaying a message telling the user what TextKey to send and the Short Code to use. While that message is being displayed, the code will poll for a valid TextKey every 5 seconds until either a text has been received or the alloted time to send the text completes.

The three key elements in this Step are:

  • Making a call to the textKeyHandler(textkey, shortcode) JS function with the TextKey
  • Customizing how you want the modal dialog to look
  • Setting up a success and failure JS callback handler

The ajax response from the Login form will trigger the modal display via the textKeyHandler(textkey, shortcode) call. This function is defined in the textkey.js file and allows for customization of the modal look and feel, time to poll and how to handle the success and failed callbacks.

success: function (jsondata) {
    // Convert to an object
    data = eval(jsondata);
    
    if (typeof(console) !== 'undefined' && console != null) {
        console.log("data: " + jsondata);
        console.log(data);
    };

    // Check for a valid login
    if (data.error == "") {
        // Set the flag
        login.loggedin = true;
        
        // Set the textkey values
        login.textkey = data.textkey;
        login.textkeyVC = data.textkeyVC;
        login.shortcode = data.shortcode;

        // Handle the textkey login
        if (login.loggedin) {
            textKeyHandler(login.textkey, login.shortcode);
        };
    }
    else {
        // Set the error message
        login.message = data.error;
        
        // Show the error message
        login.showError();
    };
},

These are the 5 key JS includes that are used to both display the TextKey modal as well as handle the polling for a valid text.

The 5 JS includes in this Step are:

  • jQuery - no need to include if this is already part of your application/site
  • jQuery SimpleModal - jQuery plugin to handle modal dialogs
  • login.js - handles the login form
  • textkey_custom.js - handles customizing and displaying the TextKey modal message and the success and failure callbacks
  • textkey.js - handles the TextKey polling for a successful or failed authentication
<!-- jQuery -->
<script src="http://code.jquery.com/jquery-latest.min.js"></script>

<!-- TextKey JS Include to manage the Login Form -->
<script type="text/javascript" src="js/login.js"></script>

<!-- SimpleModal jQuery Include - Used for modal display -->
<script type="text/javascript" src="js/jQuery.simplemodal-1.4.4.js"></script>

<!-- TextKey JS Include to handle Polling -->
<script type="text/javascript" src="js/textkey.js"></script>

<!-- TextKey JS Include to customize the TextKey modal and callback handlers -->
<script type="text/javascript" src="js/textkey_custom.js"></script>

textkey_custom.js has 3 functions that are used in the login flow.

The functions are:

  • textKeyHandler - displays the TextKey modal and defines the time to poll for a valid text message
  • loginSuccess - the callback handler for a successful login
  • loginFailed - the callback handler for a failed login

The textKeyHandler function will display a modal dialog that looks something like this:

bootstrap theme

The elements that can be customized via JS functions are:

Function Name Description
setTextKeyHTML This is the HTML content displayed in the TextKey Modal.
setTextKeyContainerCss This is the container styling for the TextKey Modal.
setTextKeyDataCss This is the data styling for the TextKey Modal.
setTextKeyOverlayCss This is the overlay styling for the TextKey Modal.
setPollTime This defines the time the user is given to send the TextKey code for authentication (in Seconds - Max is 180 seconds).

NOTE: The server side handling should validate true authentication. The callback functions should facilitate that final authentication. See Step 4 for an example.

/*
**
** textkey_custom.js
**
** These are the functions to display the TextKey message and subsequent success or failure callbacks.
** 
*/

// Call to handle the successful authentication
function loginSuccess(tkTextKeyMessage, tkTextKeyStatus) {
	window.location = 'index.php'
};

// Call to handle the failed authentication
function loginFailed(tkTextKeyMessage, tkTextKeyStatus) {
};

// Simple Call to handle the login
function textKeyHandler(textKey, shortcode) {

	// Customize the look and feel
	setTextKeyHTML('<div id="tkmessage-container"><h1>Mobile Authentication...</h1><div class="poweredby"><img src="images/poweredbylocked.gif" alt="Powered by TextPower" border="0" align="absmiddle"></div><div id="tkSound"></div><div id="tkTime"></div></div>');
	setTextKeyContainerCss({'height':'260px', 
							'width':'625px', 
							'font': '16px/22px \'Raleway\', \'Lato\', Arial, sans-serif',
							'color':'#000000', 
							'background-color':'#000', 
							'padding':'10px', 
							'background-color':'#F1F1F1', 
							'margin':'0', 
							'padding':'0',
							'border':'4px solid #444'});
	setTextKeyDataCss({'padding':'8px'});
	setTextKeyOverlayCss({'background-color':'#AAA', 'cursor':'wait'});
	// Set the total time to wait for TextKey to 120 seconds
	setPollTime(120);
	
	// Show the TextKey Modal and handle the checking
	showTKModal(textKey, shortcode, loginSuccess, loginFailed);
};

textkey.js contains all of the polling handling code and just needs to be included. The textKeyHandler function call in textkey_custom.js will take care of everything.

/*
**
** textkey.js
**
** These are the TextKey js handling functions. They handle the interaction with the backend handler code as well as the client side interaction/integration.
** 
*/

/*
**
** TextKey modal default options
**
** These settings define what shows up in the TextKey Modal dialog.
**
** NOTES:
**
** urlTextKeyAuth: This is the polling handler which checks to see if the TextKey has been received or not.
** pollFreq: This defines how often to poll the back end handler (in Milliseconds).
** pollTime: This defines the time the user is given to send the TextKey code for authentication (in Seconds - Max is 180 seconds).
** tkHTML: This is the HTML content displayed in the TextKey Modal. Overide this with the setTextKeyHTML call.
** tkcontainerCss: This is the container styling for the TextKey Modal. Overide this with the setTextKeyContainerCss call.
** tkdataCss: This is the data styling for the TextKey Modal. Overide this with the setTextKeyDataCss call.
** tkoverlayCss: This is the overlay styling for the TextKey Modal. Overide this with the setTextKeyOverlayCss call.
**
** See Simple Modal Documentation for more info: http://www.ericmmartin.com/projects/simplemodal/
**
** The remaining elemtns are used to hold inforation/state.
**
*/
error_message = '';
tkSettings = {
	urlTextKeyAuth: 'textkeycheck.php?callback=?',
	pollFreq: 5000,
	pollTime: 120,
	tkHTML: '<div id="simplemodal-container"><h3>Waiting for TextKey Authentication...</h3><div id="tkTime"></div></div>',
	tkcontainerCss: {'height':'100px', 'width':'600px', 'color':'#bbb', 'background-color':'#333', 'border':'4px solid #444', 'padding':'12px'},
	tkdataCss: {'padding':'8px'},
	tkoverlayCss: {'background-color':'#000', 'cursor':'wait'},
	tkTextKey: '',
	tkShortCode: '',
	tkTextKeyUnloackSound: 'audio/door_open.mp3',
	tkTextKeySuccess: false,
	tkTextKeyMessage: '',
	tkTextKeyStatus: false,
	tkFnSuccess: null,
	tkFnFail: null
};

/*
** Standard modal dialog handling
*/
function closeModal() {
	$.modal.close();
};

function showModal(title, msg, md_closeProc, md_height, md_width) {
	if (typeof(md_height) === "undefined") { md_height = 160; };
	if (typeof(md_width) === "undefined") { md_width = 625; };
	
	// Build the hmtl to display
	tkModalHTML = ('<div id="basic-modal-content"><h3>'+title+'</h3><p>'+msg+'</p><div class="modal-buttons"><span><a class="modal-button" onclick="javascript:$.modal.close();">Close</a></span></div></div><!-- preload the images --><div style="display:none"><img src="./images/x.png" alt="" /></div>');

	$.modal(
		tkModalHTML, 
		{
			onClose: md_closeProc,
			containerCss:{
					height:md_height, 
					width:md_width
		},
	});
	
	return true;

};

/*
 * TextKey Change Standard Settings
 *
 */
function setTextKeyAuth(urlTextKeyAuth) {
	tkSettings.urlTextKeyAuth = urlTextKeyAuth;
}

function setPollFreq(pollFreq) {
	tkSettings.pollFreq = pollFreq;
}

function setPollTime(newpollTime) {
	tkSettings.pollTime = newpollTime;
	pollTime = tkSettings.pollTime;
}

function setTextKeyHTML(tkHTML) {
	tkSettings.tkHTML = tkHTML;
}

function setTextKeyContainerCss(tkcontainerCss) {
	tkSettings.tkcontainerCss = tkcontainerCss;
}

function setTextKeyDataCss(tkdataCss) {
	tkSettings.tkdataCss = tkdataCss;
}

function setTextKeyOverlayCss(tkoverlayCss) {
	tkSettings.tkoverlayCss = tkoverlayCss;
}

/*
 * TextKey Globals
 *
 */
var pollTime = tkSettings.pollTime;
var tkTextKeyHandled = false;
var timer_is_on = 0;
var t;

/*
 *
 * Hide and show the scoll bar
 *
 */
function hideScrollBar() {
	$("body").css("overflow", "hidden");
}

function showScrollBar() {
	$("body").css("overflow", "auto");
}

/*
 *
 * Close the TextKey dialog
 *
 */
function closeTKModal() {

	// Set the handled flag
	tkTextKeyHandled = true;

	// Reset the poll time
	pollTime=tkSettings.pollTime;
	doTimer(1);

	// Clear out the messages
	$("#tkTime").text("");

	// Hide the modal dialog
	$.modal.close();
	
	// Show the scroll bar
	showScrollBar();
}

/*
 *
 * TextKey Post Handler
 *
 */
function postRedirect(redirectURL) {
	var tkredirectform = $('<form id="tkredirectform" action="' + redirectURL + '" method="post">' +
	  '<input type="text" name="textkeymessage" value="' + tkSettings.tkTextKeyMessage + '" />' +
	  '<input type="text" name="textkeystatus" value="' + tkSettings.tkTextKeyStatus + '" />' +
	  '</form>');
	$('body').append(tkredirectform);
	$('#tkredirectform').submit();
}

/*
 *
 * TextKey Login was succesful
 *
 */
function completeLogin() {
	
	// Set flag to success
	tkSettings.tkTextKeySuccess = true;

	// Hide the modal dialog
	closeTKModal();
	
	// Handle the Client Call back or URL redirect
	if ($.isFunction(tkSettings.tkFnSuccess)) {
		tkSettings.tkFnSuccess(tkSettings.tkTextKeyMessage, tkSettings.tkTextKeyStatus);
	}
	else {
		postRedirect(tkSettings.tkFnSuccess);
	}
}

/*
 *
 * TextKey Login failed
 *
 */
function errorLogin() {
	// Handle the Session
	login.handlelogout(false);

	// Hide the modal dialog
	closeTKModal();
	
	// Handle the Client Call back or URL redirect
	if ($.isFunction(tkSettings.tkFnFail)) {
		tkSettings.tkFnFail(tkSettings.tkTextKeyMessage, tkSettings.tkTextKeyStatus);
	}
	else {
		postRedirect(tkSettings.tkFnFail);
	}
}

/*
 *
 * Show an error modal
 *
 */
function errorShow() {
	showModal('Login Error...', 'The TextKey authentication did not complete.  You can try again if you think this was an error.', closeModal);
	error_message = "";
}

/*
 *
 * Show the TextKey modal dialog
 *
 */
function showTKModal(TextKey, ShortCode, fnCallSuccess, fnCallFailed) {
	
	// Check for valid call backs
	if (typeof(fnCallSuccess) === "undefined") {
		alert("Please make sure you pass in your success and failure handler parameters...");
		return;
	};
	if (typeof(fnCallFailed) === "undefined") {
		alert("Please make sure you pass in your success and failure handler parameters...");
		return;
	};

	// Set the tkSettings values
	tkSettings.tkTextKey = TextKey;
	tkSettings.tkShortCode = ShortCode;
	tkSettings.tkFnSuccess = fnCallSuccess;
	tkSettings.tkFnFail = fnCallFailed;
	
	// Set the status & handls variables
	tkSettings.tkTextKeySuccess = false;
	tkSettings.tkTextKeyMessage = '';
	tkSettings.tkTextKeyStatus = false;
	tkTextKeyHandled = false;

	// Hide the scroll bar
	hideScrollBar();
	
	// Show the dialog
	$.modal(
		tkSettings.tkHTML, 
		{
			onClose: function (dialog) {
				dialog.data.fadeOut('slow', function () {
					dialog.container.slideUp('slow', function () {
						dialog.overlay.fadeOut('slow', function () {
							// Handle the user initiated close					 
							if (!(tkTextKeyHandled)) {	
								// Set the status values
								tkSettings.tkTextKeyMessage = 'User cancelled the TextKey check...';
								tkSettings.tkTextKeyStatus = false;
								
								// Handle the failed login
								errorLogin();
								
								// Show the dialog
								error_message = tkSettings.tkTextKeyMessage;
								setTimeout("errorShow()", 1000);
							}
							else {
								$.modal.close();
								if (error_message != "") {
									setTimeout("errorShow()", 1000);
								};
							};
						});
					});
				});
			},
			position: ["15%",],
			containerCss: tkSettings.tkcontainerCss,
			dataCss: tkSettings.tkdataCss,
			overlayCss: tkSettings.tkoverlayCss
		}
	);
	
	// Hide the close button
	$('#simplemodal-container a.modalCloseImg').hide();

	// Start the TextKey handler
	sendTextKeyCheck();
}

/*
 *
 * Handle the JS timer
 *
 */
function doTimer(clr) {
	// Handle cancelling the timer
	if(clr == 1 && timer_is_on == 1) {
		clearTimeout(t);
		timer_is_on = 0;
	};
	
	// Handle starting the timer
	if (clr == 0) {
		timer_is_on = 1;
		t = setTimeout("sendTextKeyCheck()",tkSettings.pollFreq);
	} 
}

// Validate the TextKey and finalize the login
function validateTextKey()  {
	$.ajax({
		url: 'loginvalidate.php',
		type: 'post',
		cache: false,
		dataType: 'html',
		success: function (jsondata) {
			// Convert to an object
			data = eval(jsondata);
			
			if (typeof(console) !== 'undefined' && console != null) {
				console.log("data: " + jsondata);
				console.log(data);
			};
			
			// Check for a valid login
			if (data.error == "") {
				handleUnlock();
				$("#tkTime").html('<p><span class="bigmsg colorsuccess">SUCCESS!</span></br><p>TextKey accepted. Completing login now...</p>');
				tkSettings.tkTextKeyMessage = 'SUCCESS! TextKey accepted and verified.';
				setTimeout("completeLogin()",3000);
			}
			else {
				$("#tkTime").html('<p><span class="bigmsg colorfailed">FAILED!</span></br><p>'+data.error+'</p>');
				tkSettings.tkTextKeyMessage = 'FAILED! TextKey was not verified.';
				error_message = 'ERROR: '+data.error;
				setTimeout("errorLogin()",3000);
		   };
		}
	});
};

function changeLock() {
	$(".poweredby img").attr("src", "images/poweredbyunlocked.gif");
}

// Handle the unlock image/sound
function handleUnlock() {
	// Switch to unlocked logo if there
	if (tkSettings.tkTextKeyUnloackSound != "") {
		$("#tkSound").html('<audio src="'+tkSettings.tkTextKeyUnloackSound+'" autoplay></audio>');
	};
	setTimeout("changeLock()",1500);
}

/*
 *
 * The TextKey Handler
 *
 */
function sendTextKeyCheck() {

	// Setup the data payload
	var DTO = { 'textKey': tkSettings.tkTextKey };

	// Show the results in the console
	if (typeof(console) !== 'undefined' && console != null) {
		console.log(DTO);
		console.log(JSON.stringify(DTO));
	};

	try {
		// Made a request to check for response
		$.getJSON(tkSettings.urlTextKeyAuth, 
		DTO,
		function(responseS) {
			
			if (typeof(console) !== 'undefined' && console != null) {
				console.log(responseS);
			};
			
			if (responseS.errorDescr) {
				error_message = 'ERROR: '+responseS.errorDescr;
				tkSettings.tkTextKeyMessage = error_message;
				$("#tkTime").html('<p>'+error_message+'</p>');
				doTimer(1);
				setTimeout("errorLogin()",3000);
			}
			else {
				
				// Look at the response
				tkSettings.tkTextKeyStatus = responseS.ActivityDetected;
		
				// Show the results in the console
				if (typeof(console) !== 'undefined' && console != null) {
					console.log('tkSettings.tkTextKeyStatus: ' + tkSettings.tkTextKeyStatus);
				};
				
				// Check for an expired textKey
				if (responseS.TimeExpired) {
						error_message = '<span class="bigmsg colorfailed">FAILED!</span></br><p>Time for response has expired.<p>';
						tkSettings.tkTextKeyMessage = error_message;
						$("#tkTime").html('<p>'+error_message+'</p>');
						doTimer(1);
						setTimeout("errorLogin()",10000);
				}
				else {
					// Check for activity detected
					if (responseS.ActivityDetected) {
							$("#tkTime").html('<p><span class="bigmsg colorverify">TEXTKEY RECEIVED</span></br><p>Completing verification now...</p>');
							tkSettings.tkTextKeyMessage = 'Verifying TextKey...';
							
							// Validate the TextKey to make sure it was legal
							doTimer(1);
							setTimeout("validateTextKey()",3000);
					}
					else {
						$("#tkTime").html('<p>To complete this login, text the following code to '+tkSettings.tkShortCode+':</p><p id="tkCode">' + tkSettings.tkTextKey + '</p><p>within '+pollTime+' seconds...</p>');
						pollTime -= 5;
					}
				}
			}
		});
	} catch(err) {
		error_message = 'ERROR: '+err;
		tkSettings.tkTextKeyMessage = error_message;
		$("#tkTime").html('<p>'+error_message+'</p>');
		doTimer(1);
		setTimeout("errorLogin()",3000);
	};

	// Start the timer
	doTimer(0);
}

Step 3 - User Sends the TextKey.

Once the textKeyHandler function is called, it will display a modal dialog that looks something like this:

bootstrap theme

At that point the user will need to text the TextKey to the specified Short Code.

Depending on what happens, here are some of the possible outcomes:

  • The user successfully sends the correct TextKey from the verified device
    • An success message witll be displayed and the loginSuccess callback function will be called
  • The user successfully sends the correct TextKey from a different device
    • An error message witll be displayed and the loginFailed callback function will be called
  • Nothing was texted and the polling timeframe completed.
    • An error message witll be displayed and the loginFailed callback function will be called

Step 4 - Finalizing user authentication.

A successful TextKey verification will call the loginSuccess callback function. At this point, the login can be finalized and should be handled server side.

This might include a call to the server to serve the correct page, a redirect to a successful login page (i.e. like a users profile or preferences page), or a reload of the same page where the server side code will use server side SESSION variables to make sure the 2nd level authentication was indeed valid.

An example might be to redirect to the home page and let the server side SESSION variables verify that the user is logged in and then handle the logged in case for the page.

// Call to handle the successful authentication
function loginSuccess(tkTextKeyMessage, tkTextKeyStatus) {
    // Handle the finalized login
	window.location = 'index.php'
};

Once the dialog has been displayed, the JS code will begin polling for receipt of that TextKey every 5 seconds.

Every 5 seconds, the JS function sendTextKeyCheck() in textkey.js makes a call to textkeycheck.php and then evaluates the response to decide what to do next.

    // Made a request to check for response
    $.getJSON(tkSettings.urlTextKeyAuth, 
    DTO,
    function(responseS) {

        HANDLE CHECKING THE RESPONSE TO THE POLLING CHECK
        
    });

There are 3 states that can happen when polling:

  • An error
  • A response saying that activty has been detected
  • An expiration timeout
    if (responseS.errorDescr) {
        error_message = 'ERROR: '+responseS.errorDescr;
        tkSettings.tkTextKeyMessage = error_message;
        $("#tkTime").html('<p>'+error_message+'</p>');
        doTimer(1);
        setTimeout("errorLogin()",3000);
    }
    else {
        
        // Look at the response
        tkSettings.tkTextKeyStatus = responseS.ActivityDetected;

        // Show the results in the console
        if (typeof(console) !== 'undefined' && console != null) {
            console.log('tkSettings.tkTextKeyStatus: ' + tkSettings.tkTextKeyStatus);
        };
        
        // Check for an expired textKey
        if (responseS.TimeExpired) {
                error_message = '<span class="bigmsg colorfailed">FAILED!</span></br><p>Time for response has expired.<p>';
                tkSettings.tkTextKeyMessage = error_message;
                $("#tkTime").html('<p>'+error_message+'</p>');
                doTimer(1);
                setTimeout("errorLogin()",10000);
        }
        else {
            // Check for activity detected
            if (responseS.ActivityDetected) {
                    $("#tkTime").html('<p><span class="bigmsg colorverify">TEXTKEY RECEIVED</span></br><p>Completing verification now...</p>');
                    tkSettings.tkTextKeyMessage = 'Verifying TextKey...';
                    
                    // Validate the TextKey to make sure it was legal
                    doTimer(1);
                    setTimeout("validateTextKey()",3000);
            }
            else {
                $("#tkTime").html('<p>To complete this login, text the following code to '+tkSettings.tkShortCode+':</p><p id="tkCode">' + tkSettings.tkTextKey + '</p><p>within '+pollTime+' seconds...</p>');
                pollTime -= 5;
            }
        }
    }

The server side polling code in textkeycheck.php relies on the pollForIncomingTextKey API Call to check for a received TextKey.

// Include configuration settings
include_once("config.php");

// Add TextKey PHP REST Library
include_once("textkey_rest.php");

// Get the params
$textkey = $_REQUEST['textKey'];

// Create a TK object
$tk = new textKey(TK_API);
    
// Handle the operation
$textkey_result = $tk->perform_PollForIncomingTextKey($textkey);

// Handle the results
if ($textkey_result->errorDescr == "") {
    echo $_REQUEST['callback'].'('.json_encode($textkey_result).')';
}
else {
    echo $_GET['callback'] . "({\"error\":\"". $textkey_result->errorDescr ."\"})";
}

Once we know that a TextKey has been received, a validation check takes place to finalize the TextKey verification.

// Check for activity detected
if (responseS.ActivityDetected) {
        $("#tkTime").html('<p><span class="bigmsg colorverify">TEXTKEY RECEIVED</span></br><p>Completing verification now...</p>');
        tkSettings.tkTextKeyMessage = 'Verifying TextKey...';
        
        // Validate the TextKey to make sure it was legal
        doTimer(1);
        setTimeout("validateTextKey()",3000);
}

This triggers a call to validateTextKey() which ensures that the TextKey was sent by the correct device and that the Verification Code that was provided matches.

// Validate the TextKey and finalize the login
function validateTextKey()  {
	$.ajax({
		url: 'loginvalidate.php',
		type: 'post',
		cache: false,
		dataType: 'html',
		success: function (jsondata) {
			// Convert to an object
			data = eval(jsondata);
			
			if (typeof(console) !== 'undefined' && console != null) {
				console.log("data: " + jsondata);
				console.log(data);
			};
			
			// Check for a valid login
			if (data.error == "") {
				handleUnlock();
				$("#tkTime").html('<p><span class="bigmsg colorsuccess">SUCCESS!</span></br><p>TextKey accepted. Completing login now...</p>');
				tkSettings.tkTextKeyMessage = 'SUCCESS! TextKey accepted and verified.';
				setTimeout("completeLogin()",3000);
			}
			else {
				$("#tkTime").html('<p><span class="bigmsg colorfailed">FAILED!</span></br><p>'+data.error+'</p>');
				tkSettings.tkTextKeyMessage = 'FAILED! TextKey was not verified.';
				error_message = 'ERROR: '+data.error;
				setTimeout("errorLogin()",3000);
		   };
		}
	});
};

In order to verify that the received TextKey was truly valid, the Validation Code should be matched up with the userid and TextKey.

In the code below, the following happens:

  • Check to make sure that first pass authentication happened (i.e. username/pasword authentication)
  • Get the TextKey values from the SESSION variables
  • Make a call to perform_ValidateTextKeyFromUserId to validate the TextKey
    • This is one of the class methods in the TextKey API library
    • See ValidateTextKeyFromUserId for more information on this API call
  • Finalize the SESSION variables if the validation was good
  • Return the result payload
// Include configuration settings
include_once("config.php");

// Add TextKey PHP REST Library
include_once("textkey_rest.php");

// Add TextKey Session Handler
require_once("textkeysite.php");

// Create the session handling object
$textkeysite = new textkeysite();

// Check to make sure pass 1 worked (i.e. username/pasword authentication)
$loggedIn = $textkeysite->getPassedLoginCheck();
if ($loggedIn) {
	// Get the session values from the textkey validation and check to make sure they are good
	$textkeyvc = $textkeysite->get_textkeyvc();
	$tkuserId = $textkeysite->get_tkuserId();
	$textkey = $textkeysite->get_textkey();
	
	// Create the textkey object
	$tk = new textKey(TK_API);
	
	// Validate the TextKey to ensure it was the original one with the TextKey validation code
	$textkey_result = $tk->perform_ValidateTextKeyFromUserId($tkuserId, $textkey, $textkeyvc, TK_ISHASHED);
	if ($textkey_result->errorDescr === "") {
		// Check for an error
		$validationErrors = $textkey_result->validationErrors;
		foreach($validationErrors as $key => $value) { 
			switch ($value) {
				case "textKeyNoError":
					// No error so setup the return payload
					$error_msg = '({"error":"", "validated":' . json_encode($textkey_result->validated) . '})';

					// Handle setting the sesssion info.
					$textkeysite->setPassedTKCheck();
				break;
				case "textKeyNotFound":
					$error_msg = '({"error": "The TextKey sent was not valid."})';
				break;
				case "textKeyNotReceived":
					$error_msg = '({"error": "The TextKey was never received."})';
				break;
				case "textKeyFraudDetect":
					$error_msg = '({"error": "Fraud Detected - The TextKey was not sent by the authorized device."})';
				break;
				case "noRegistrationFound":
					$error_msg = '({"error": "The TextKey was received but it was not assigned to a registered user."})';
				break;
				case "validationCodeInvalid":
					$error_msg = '({"error": "The TextKey was received but the validation code was invalid."})';
				break;
				case "textKeyTooOld":
					$error_msg = '({"error": "The TextKey was received but had already expired."})';
				break;
				case "textKeyError":
					$error_msg = '({"error": "An innternal TextKey error occured."})';
				break;
				case "textKeyNotValidated":
					$error_msg = '({"error": "The TextKey was not validated."})';
				break;
				case "pinCodeError":
					$error_msg = '({"error": "A Pin Code error occured."})';
				break;
				default:
					$error_msg = '({"error": "An error occured while trying to verify the TextKey."})';
				break;
			}
		} 			
	}
	else {
		$error_msg = $textkey_result->errorDescr;
		$error_msg = '({"error":' . json_encode($error_msg) . '})';
	}
}
else {
	$error_msg = "Error logging in user: User/Password validation was not finalized.";		
	$error_msg = '({"error":' . json_encode($error_msg) . '})';
}

error_log('error_msg: ' . $error_msg);

echo $error_msg;

exit;

The getPassedLoginCheck method checks the SESSION variables states to ensure that that the 1st pass of authentication (i.e. username/pasword authentication) has completed successfully.

This method is part of the textkeysite class in textkeysite.php

	/*
	** Check to see if the first check passed (i.e. Login/Password)
	*/
    function getPassedLoginCheck()  {
		// Start the login session
		if (!isset($_SESSION)) { 
			session_start(); 
		}
		
		// If the username/login check has not passed them return false
		if ($_SESSION['passedcheck1'] != true) {
			return false;
		}
		
		return true;
    }

The setPassedTKCheck method sets the SESSION variables state so that the 2nd level authentication was completed.

This method is part of the textkeysite class in textkeysite.php

	/*
	** Set the session info. after the user passes the second check (i.e. textkey authentication)
	*/
    function setPassedTKCheck($username, $userid)  {
		// Start the login session
        if (!isset($_SESSION)) { 
			session_start(); 
		};
		
		// 2 pass flags
        $_SESSION['passedcheck2'] = true;
    }

The getPassedTKCheck method checks the SESSION variables states to ensure that that both passes of authentication have completed successfully.

See the Login Check Code tab for an example.

This method is part of the textkeysite class in textkeysite.php

	/*
	** Check to see if the second check passed (i.e. textkey authentication)
	*/
     function getPassedTKCheck()  {
		// Start the login session
		if (!isset($_SESSION)) { 
			session_start(); 
		}
		
		// If the TextKey check has not passed then return false
		if (($_SESSION['passedcheck1'] != true) || ($_SESSION['passedcheck2'] != true)) {
			return false;
		}
		
		return true;
    }

This sample code is a server site check before rendering any page to ensure that the user is logged in and that both passes of authentication have completed successfully.

include_once("config.php");
require_once("textkeysite.php");

// Setup
$loggedIn = false;
$userName = "";

// Create the session handling object
$textkeysite = new textkeysite();

// Check to see if the user has fully logged in by passing both checks and then handle the custom code
$loggedIn = $textkeysite->getPassedTKCheck();
if ($loggedIn) {
	$userName = $textkeysite->get_userName();
};

Those variables can be used to decide what to render or not render for the page. For example, the index.php page shows this in effect. It will do a check for a logged in user and either display a button to the login page or show that the user is logged in.

<?php if (!($loggedIn)): ?>
    <form class="form-textkey" id="form-textkeygotologin" action="tutoriallogin.php">
      <p>
        <input type="submit" name="submit" value="Go To Login Page" class='login-send'>
      </p>
    </form>
<?php else: ?>
	<header>
        <h1><a href="index.php">TextPower - TextKey Demo Registraton</a></h1>
        <div class="tagdesc">
        	<br />
            <h1 align="center"><strong>SUCCESS!</strong></h1>
            <br />
            <h3 align="center">You have logged in with the user name <strong><?php echo $userName; ?></strong></h3>
            <br />
            <h2 align="center">If this was your company`s website you would now be successfully logged in.</h2>
        </div>
	</header>
    <form class="form-textkey" id="form-textkey">
      <p>
        <input type="submit" name="submit" value="Logout" class='logout-send' onClick="return login.handlelogout(true);">
      </p>
    </form>
    <div class="tagdesc">
        <h3 align="center">Want to try this again?  Click the <strong>"Logout"</strong> button to return to the login screen.</h3>
        <br />
    </div>
<?php endif; ?>