Delete user in iOS using Parse login - ios

I'm implementing parse login in iOS using swift. From a login view controller i get new users to signup via swift using just email and password. This creates a PFUser which correctly saves to Parse backend. The user is then taken to a UserDetails view controller to "complete" their signup by providing more details which gets saved to coredata (im using parse functionality just for the signup). If the user cancels however before "completing" the additional details, I want to delete the PFUser from parse created possibly moments earlier. In the UserDetails view controller under cancelTapped ibaction im running code
if PFUser.currentUser() != nil {
PFUser.currentUser()?.deleteInBackgroundWithBlock({ (deleteSuccessful, error) -> Void in
print("success = \(deleteSuccessful)")
})
//user deleted in background block above but still logged in so now logout
PFUser.logOut()
}
but im getting following parse error [Error]: User cannot be deleted unless they have been authenticated. (Code: 206, Version: 1.8.5) .... i dont know what authentication process is needed and im guessing the problem could be because im trying to delete a user before parse has had a proper time to create the user in the first place .... any help or suggestions appreciated

User ALC permission automatically blocks anyone else from performing a write/delete on your record. This means you must be logged in if you want to update/delete your own record. In your code, you probably log out before your asynchronous delete code gets a chance to run in the background. Instead you need to log the user out after the delete was successful in the completion block of deleteInBackgroundWithBlock function.
if PFUser.currentUser() != nil {
PFUser.currentUser()?.deleteInBackgroundWithBlock({ (deleteSuccessful, error) -> Void in
print("success = \(deleteSuccessful)")
PFUser.logOut()
})
}

Related

AWS Cognito check and get users

I'm building an iOS App that is using Amazon MobileHub. Currently it's associated with Cognito and the sign up and sign in flow works great.
What I'm trying to achieve is for one user to be able to add another user as a friend so to speak. To make that possible, I need to check if a user with a specific username exists and if it does, get some attributes such as the name of that target user.
I've tried to use the get user > get details function but it gives me an error Authentication delegate not set.
Here's the code I used:
var pool: AWSCognitoIdentityUserPool?
let user = pool?.getUser(usernameField.text!)
self.pool = AWSCognitoIdentityUserPool.init(forKey: AWSCognitoUserPoolsSignInProviderKey)
user?.getDetails().continueWith { (task: AWSTask<AWSCognitoIdentityUserGetDetailsResponse>) -> Any? in
if let error = task.error as NSError? {
print("ERROR: " + error.localizedDescription)
return ""
}
print(task.result)
return ""
}
An approach I thought of was to store the username and the attributes I want to access to DynamoDB and then access it there but that will just create double unnecessary entries.
The issue you'll run into is that user attributes aren't publicly visible. Only the user who has signed in can call GetUser. If it's a back end process, you could do this via the AdminGetUser operation, but this looks client side so I wouldn't recommend that. The only real way around this would be to do what you suggested at the bottom of your post, ultimately.

Checking Firebase current signed-in user via Listener in iOS

I've implement Firebase Authorization to login on my iOS app via Facebook and Google. I'm coding Swift.
When the app starts up I need to check whether a user is already signed-in in order to present the proper ViewController (e.g., if nobody is signed in I present the Login View Controller, otherwise I present the Home View Controller).
If I use the "easy" solution offered by Firebase, meaning
if FIRAuth.auth()?.currentUser != nil {
// User is signed in.
// ...
} else {
// No user is signed in.
// ...
}
So checking if the current user is not nil, it happens exactly what the Firebase guide (https://firebase.google.com/docs/auth/ios/manage-users) alerts might happen meaning
"Note: currentUser might also be nil because the auth object has not finished initializing. If you use a listener to keep track of the user's sign-in status, you don't need to handle this case."
So I would like to implement the listener as suggested in the guide:
handle = FIRAuth.auth()?.addStateDidChangeListener() { (auth, user) in
// ...
}
The listener will handle also intermediate status so that it is triggered when the Auth object is created. Point is I really cannot make it to work properly. Anybody can help me to use this listener in order to check if a user is logged in?
Thanks
I've implemented it like this:
FIRAuth.auth()?.addStateDidChangeListener { auth, user in
if let user = user {
// User is signed in. Show home screen
} else {
// No User is signed in. Show user the login screen
}
}
If you don't need the User object after checking, you can replace if let user = user with a boolean test, like this:
FIRAuth.auth()?.addStateDidChangeListener { auth, user in
if user != nil {
// User is signed in. Show home screen
} else {
// No User is signed in. Show user the login screen
}
}
Where to put the listener (from the comments):
For the cases I used to check if a user is signed in, it was enough to put it at the beginning of viewDidLoad in the specific view controller. But if you have any cases where you need to check every time you enter the specific view controller then it would be better to put it at the beginning of viewDidAppear. But I think in most cases you need to check only once, if the user enters the view
If you're setting up the StateDidChangeListener in application:didFinishLaunchingWithOptions, you'll notice that it fires once when the listener is attached (to set the initial state, which is nil when initialising) and then again once it's finished initialising (potentially not nil). This is intended behaviour, but really impractical if you're setting it up early.
An alternative to using the listener is using NotificationCenter. This will fire once initialisation has finished:
NotificationCenter.default.addObserver(forName: NSNotification.Name.AuthStateDidChange, object: Auth.auth(), queue: nil) { _ in
let user = Auth.auth().currentUser
}

Invalid session toked after deleting a user Parse Server Swift

Im running Parse Server on heroku and mLab and I use the following code to delete a user:
if PFUser.current() != nil {
PFUser.current()?.deleteInBackground(block: { (success, error) in
if error == nil {
self.performSegue(withIdentifier: "unwindToLoginFromSignUp", sender: self)
} else {
// Handle error
}
})
}
The issue is that after deleting a user if I create a new user I get the error "Invalid session token (Code: 209, Version: 1.14.2)". I understand what a session toked is but I'm not sure how I should be handling it when I delete a user.
Also the error does not cause a crash, it just shows up in the console. Any help is much appreciated!
I think you should store the currentUser object then log out the user first, and then delete the currentUser.
Once you delete the user without deleting the session, the app won't know that the current user doesn't exist any more, the session still remains, therefore you will get a session error after signing up another user.
But if you log out the user first, the current session will also be deleted, then you are free to create a new user.
I realized I forgot to log the user out after deleting their account and taking them back to the sigh up view.

Parse, how to handle an invalid session?

Straight from the documentation, it says that:
PFUser#currentUser() gets the currently logged in user from disk and
returns an instance of it.
This is fine and all, but what if the user logged in # disk isn't a user that's logged in on the server. Lets say the users account has been deleted for whatever reason, or the session is no longer valid due to database modifications. These are currently the problems that I'm facing.
Throughout the tutorials that I've read, I've seen using the following line of code as a way to check if the user is valid, and thus you can skip the login stage of the application:
if let user = PFUser.currentUser() as? Subclass {
// Simulate successful login
}
However, this is posing a problem for me, as the successful login is simulated, but the login was not successful. Here is the error I'm dealing with:
[Error]: invalid session token (Code: 209, Version: 1.12.0)
So the first thing I did was attempt to log the user out, however this fails (I assume because the user wasn't logged in to begin with) and now I'm thrown into application which immediately crashes because the data required by the server isn't there. Here's how I attempted to handle error code 209:
let query = PFQuery(className: "Foo")
query.whereKey("Bar", equalTo: "Foo")
query.findObjectsInBackgroundWithBlock {
(foo, error) -> Void in
if let error = error {
print(error);
if error.code == 209 {
PFUser.logOutInBackgroundWithBlock {
(error) -> Void in
if let error = error {
print("Okay, I'm trapped!");
}
}
}
}
}
The output of this "query" is the following:
[Error]: invalid session token (Code: 209, Version: 1.12.0)
Okay, I'm trapped!
I'm out of ideas over here, and I'm ripping my hair out trying to figure out how to properly validate a user upon application launch. It seems redundant to have to catch error code 209 on every query, but if that's what you have to do, then that's what you have to do.
You can use synchronous logout. So even if error occurs, it doesn't matter. The PFUser session token will be invalidated if the user launches the app again.
Also latest Parse SDK provides PFConstants class, which provides enum for all possible error cases.
kPFErrorInvalidSessionToken = 209.
if (error.code == kPFErrorInvalidSessionToken) {
PFUser.logOut()
//Necessary pop of view controllers after executing the previous code.
}

Logout user when deleted from Parse data browser

I have a couple hundred users that I need to remove from my parse app. However, when I delete the user accounts the users are still able to use the app fully without a problem. Is there anyway to "force" the logout remotely? Or what else would you suggest? Thanks!
It sounds like the user is being cached on the device and I don't think parse has a remote way to clear cached data on there. I like to put a user refresh(now fetch since refresh is deprecated) function when app opens to get the latest data for that user.
You could put a fetch function when the app opens and if it returns a specific error, it would mean the user doesn't exist and then set the current user to nil. I'm not sure which error it returns and I'm at work so I can't try it right now. I would hope that if the user doesn't exist, it would return kPFErrorUserWithEmailNotFound = 205...
Here are the error codes: https://parse.com/docs/ios/api/Constants/PFErrorCode.html
You will have to give it a try but I am thinking something like this (sudo-code):
post.fetchIfNeededInBackgroundWithBlock {
(post: PFObject?, error: NSError?) -> Void in
if let someError = error {
if someError = kPFErrorUserWithEmailNotFound {
// User doesn't exist!
}
} else {
// User exists and is fetched successfully
}
}

Resources