FAULT = '0' [Identity cannot be null] on save if user logged in from multiple devices

In my app, on startup, I validate user token using method of UserService:

-(void)isValidUserToken:(void(^)(id))responseBlock error:(void(^)(Fault *))errorBlock;

In case it returns success, I show UI for already logged user. Persistent mode turned on:

[[Backendless sharedInstance].userService setStayLoggedIn:YES];

However, this leads to problem in the following scenario. Suppose user have 2 devices - A and B. User log in on A, but does not log out properly (e.g., session was interrupted). After that, user launches the app on device B. The validation above returns success, and I present UI for logged in user. So far so good. But, as soon as user tries to do some action, for example, tries to save some object, he’s catching the following error:

FAULT = ‘0’ [Identity cannot be null]

The worst of all, the problem persist even if user relaunches app on device B - no matter how many times! To fix this, user has to explicitly log out and then log in back (on device B) - only after that issue is fixed. In my opinion, its quite detrimental user (and developer) experience.

User log in on A, but does not log out properly (e.g., session was interrupted). After that, user launches the app on device B. The validation above returns success, and I present UI for logged in user. 

Are you saying isValidUserToken returns true on device B where the user never logged in? That does not sound right and certainly not how the API works. If the user never logged in a device, there is no token there to validate (regardless whether the user logged in elsewhere on other devices).

Mark

Of course user should be logged in device B before, otherwise thats obvious that it doesn’t make sense at all. Here is more detailed flow:

    Log in on device B Quit the app without logging out Log in on device A Quit the app without logging out Launch app on device B Validation of tokens returns true Try to do something (save new object) - the following error encounters:
FAULT = '0' [Identity cannot be null]

Hi Vasyl,

This issue cannot be reproduced.
Here is my code:

 func loginUser() {
 
 Types.tryblock({ () -> Void in
 
 let registeredUser = self.backendless.userService.login("spiday@backendless.com", password: "greeng0blin")
 print("User has been logged in (SYNC): \(registeredUser)")
 self.backendless.userService.setStayLoggedIn(true)
 },
 
 catchblock: { (exception) -> Void in
 print("Server reported an error: \(exception as! Fault)")
 })
 }

 func stayLoggedIn() {
 
 Types.tryblock({ () -> Void in
 
 if self.backendless.userService.isStayLoggedIn {
 let result = self.backendless.userService.isValidUserToken() //as NSNumber
 print("isValidUserToken (SYNC): \(result.boolValue)")
 if !result.boolValue {
 self.loginUser()
 }
 }
 else {
 self.loginUser()
 }
 },
 
 catchblock: { (exception) -> Void in
 print("Server reported an error (SYNC): \(exception as! Fault)")
 }
 )
 }

My scenario is:

    stayLoggedIn() on device B Quit the app without logging out stayLoggedIn() on device A Quit the app without logging out Launch app on device B isValidUserToken() returns false, log in on device B Try to do something (save new object) - it works right.
Try my sample in your app and let us know how it goes.

Regards,
Slava

Hi Vyacheslav,

You can try my code:

#============ in BLNetworkService class =============

typedef void (^BLCompletion)(NSError *error, NSDictionary *results);

- (void)isUserAlreadyLoggedIn:(BLCompletion)completion
{
 [[Backendless sharedInstance].userService isValidUserToken:^(id result)
 {
 if (completion)
 completion(nil, @{BLNetworkServiceBoolResultKey : result ?: @NO});
 } error:^(Fault *fault)
 {
 if (completion)
 completion([self errorFromFault:fault], nil);
 }];
}
 
 
 
 
 
 



- (void)loginUserWithEmail:(NSString *)email password:(NSString *)password completion:(BLCompletion)completion
{
 [[Backendless sharedInstance].userService login:email password:password response:^(BackendlessUser *user)
 {
 [BLPrefService sharedService].lastLoggedUserEmail = email;
 [BLPrefService sharedService].shouldTryAutologin = YES;
 
 [[Backendless sharedInstance].userService setStayLoggedIn:YES];
 
 if (completion)
 completion(nil, nil);
 } error:^(Fault *fault)
 {
 if (completion)
 completion([self errorFromFault:fault], nil);
 }];
}


//===============In login view controller ===============
 
 
 
 
 
 



- (void)tryAutoSignIn
{
 BLMakeWeakSelf();
 MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
 hud.labelText = NSLocalizedString(@"Trying autologin", nil);
 
 [[BLNetworkService sharedService] isUserAlreadyLoggedIn:^(NSError *error, NSDictionary *results)
 {
 BLMakeStrongSelf();
 [hud hide:YES];
 
 if (error || ![results[BLNetworkServiceBoolResultKey] boolValue])
 {
 [self showError:error withTitle:NSLocalizedString(@"Error during autologin", nil) defaultAction:nil];
 }
 else
 {
 [self performSegueWithIdentifier:BLShowMainUISegueIdentifier sender:nil];
 }
 }];
}

Vasyl, how could I run this code, really? It has couple of your classes.

To help you I need TO REPRODUCE the problem, so please send your whole project (maybe without ‘lib’ folder) to support@backendless.com.

Vyacheslav, that kinda of a double standard - you just asked me to try to reproduce the problem using the similar small excerpt of code - “Try my sample in your app” :slight_smile: Ok, if seriously, concerning complains about my custom classes - you are not supposed to copy my solution, I just posted it for you as a reference so that you can implement something similar yourself (I don’t like the idea of sharing my whole project).
Also, I wouldn’t say that you’re helping me personally - this fix is obviously more important for Backendless as a reliable platform than for one minor user.

This is fixed in the latest build of the library in github. Marking the topic as “Solved”.