Ionic Custom Auth not working on fail


#1

I have a custom php script I wrote for authenticating users using the ionic custom auth. I am trying to get a response back with the inAppBrowser hidden so I am not using a web form. I can successfully login if the user credentials are correct, but if the user enters invalid credentials or there is an exception in the script, the ionic auth fail function is not called.

$scope.login = function (userLogin) {
        var loginOptions = {'inAppBrowserOptions': {'hidden': true}};
        $ionicAuth.login('custom', userLogin, loginOptions).then(function (data) {
            Alert.showAlert('Success',JSON.stringify(data));
        },function(err){
            Alert.showAlert('Failed:',JSON.stringify(err));
        });
}

PHP Auth Script

<?php
// custom authentication for Ionic Apps
/**
 * @param string GET parameter token.
 * @param string GET parameter state.
 * @param string GET parameter redirect uri.
 * @return string Redirect URI.
 * @throws Exception
 */

require_once('../vendor/autoload.php');

use \Firebase\JWT\ExpiredException;
use \Firebase\JWT\JWT;

include($_SERVER['DOCUMENT_ROOT']."/connect/config.php");	

try {
	if (isset($_GET['token']) && isset($_GET['state']) && isset($_GET['redirect_uri'])) {

		$token 			= $_GET['token'];
		$state 			= $_GET['state'];
		$redirect_uri 	= $_GET['redirect_uri'];
		
		$decoded 	= JWT::decode($token, SECRET_KEY, array('HS256'));

		$email 		= $decoded->data->email;
		$password 	= $decoded->data->password;
		 
		$results 	= mysqli_query($dbc, "SELECT userID, fname, lname, userName, password, active FROM v_311users WHERE email='".$email."' LIMIT 1");
		$res_match  = mysqli_num_rows($results);
		$res 		= mysqli_fetch_assoc($results);
		 
		if ($res_match == 1){
			
			$userID		= $res['userID'];
			$active		= $res['active'];
			$pw 		= $res['password'];
			$fname 		= $res['fname'];
			$lname 		= $res['lname'];			
		
			if (password_verify($password, $pw)) {			 
			 		
				if($active == 1){			
                     
					$custom->name = $fname.' '.$lname;
					$custom->email = $email;
                    $payload = ['user_id'   => $userID,  'custom' => $custom];
					
					$token = JWT::encode($payload, SECRET_KEY); 				
					
					$url = $redirect_uri . '&' . http_build_query([
            			'token' => $token,
            			'state' => $state,
            			# TODO: Take out the redirect_uri parameter before production
            			//'redirect_uri' => 'https://api.ionic.io/auth/integrations/custom/success',
        			]);
					
					header('Location: '.$url);
					exit();
				} else {
					throw new Exception('Account Not Activated', 40);	
				}
			} else {
				throw new Exception('Invalid Credentials', 30);
			}
		} else {
			throw new Exception('Account Not Found', 20);
		}
	} else {
		// something failed with POST, should never get here!
		 throw new Exception('Missing Parameters', 10);
	}
	
} catch (Exception $e) {
	header('Content-type: application/json');
	header("HTTP/1.1 401 Unauthorized");
	echo json_encode(['error' => $e->getMessage(), 'code' => $e->getCode()]);
}

?>

Thanks for any help.

RGecy


#2

Did you find a solution? I’m having the same issue.


#3

No, apparently it is an issue they know about and will be working on, I assume. I think it has to do with the inAppBrowser and how it handles page errors.

I have a temporary workaround where I call a custom auth service I created to verify if the user is valid from my db, and in the sucess callback I call the ionic auth login function. This way I can get there error message back from my custom service if the user credentials are invalid. Once they are valid, the ionic auth login should work fine and will log the user in to Ionic and return the token.

Here is my Auth Service

loginUser: function (loginData) {
	var deferred = $q.defer(),
	promise = deferred.promise;
	$http({
		url: {{url-to-my-REST-login}},
		method: "POST",
		data: loginData,
		headers: {
			'Content-Type': 'application/json'
		}
	})
	.then(function (response) {
			console.log("User login check valid! " + JSON.stringify(response.data));
			var loginOptions = {
				remember: true,
				'inAppBrowserOptions': {
					'hidden': true
				}
			};
			$ionicAuth.login('custom', loginData, loginOptions).then(function (resp) {
				storeUserCredentials(resp.data);
				deferred.resolve(resp.data);
			}, function () {
                                // if Ionic Auth login fails for some reason, store the data coming back from my custom login
                                // User will not be logged in with Ionic but will be logged in to app. 
                                // App cant receive targeted push if fails
				storeUserCredentials(response.data);
				deferred.resolve(response.data);
			});
		}, function (error) {
		console.log("Login Error: " + JSON.stringify(error));
		deferred.reject(error);
	});

	promise.success = function (fn) {
	promise.then(fn);
		return promise;
	};
	promise.error = function (fn) {
		promise.then(null, fn);
		return promise;
	};
	return promise;
}

#4

Thanks for the update. That’s exactly what i’m doing right know. :slight_smile:


#5

hi please help me, i have a custom login. and thats ok i did it.

but when for example i go to home page i injected a ionicUser,

when i try to access $ionicUser.details or $ionicUser.data nothing is shown.

in my server i return this.

$payload = [
‘user_id’ => (string) $user->id,
‘custom’ => [
‘username’ => $user->username,
‘email’ => $user->email,
‘first_name’ => $user->first_name,
‘last_name’ => $user->last_name,
‘avatar’ => $user->avatar,
‘active’ => $user->active,
‘id_empresa’ => $user->idempresa,
]
];


#6

@ivgiil
How are you loading your data? Can you share some more code. Show me your http.get from the app and the php script to retrieve the data. I assume what you posted is part of it, but having the whole functioning script will help.

RGecy


#7

I am also struggling with the original problem… Hope it gets fixed!


#8

I’m having the same problem! :rage: using a Rails backend.

I’m going to use your solution :confused: