Invalid Session Token (Code: 209 Version: 1.7.4) - swift

Every time I go to run my app the app runs fine but the console prints an error. The error is "Invalid Session Token (Code: 209 Version: 1.7.4)"
I checked Parse.com and they told me to handle this error, writing a global utility function that is called by all of my parse request error callbacks. They said i can handle the "invalid session token" error in this global function and I should prompt the user to login again so that they can obtain a new session token. However when I try to input the code in my app I get the error that I am using unresolved identifiers.
Does anyone know how to fix an Invalid Session Token error. Or how I can use the code "kPFErrorInvalidSessionToken" in my app. Any help would be greatly appreciated. (the language I am writing in is swift)

I have tried to call ParseErrorHandler.handleParseError(err) not just only from AppDelegate, but also from other view controllers and it was not worked properly. Here is solution which works from every VC:
class ParseErrorHandler {
class func handleParseError(error: NSError) {
if error.domain != PFParseErrorDomain {
return
}
switch (error.code) {
// error code 209 handling
case PFErrorCode.ErrorInvalidSessionToken.rawValue:
invalidSessionTokenHandler()
default:
break
}
}
// NOTE: User has no other option but to log out in this implementation
private class func invalidSessionTokenHandler() {
let message: String = "Session is no longer valid! Please login again!"
let alert = UIAlertController(title: nil, message: message, preferredStyle: .Alert)
var vc = UIApplication.sharedApplication().keyWindow?.rootViewController
while (vc!.presentedViewController != nil)
{
vc = vc!.presentedViewController
}
vc?.presentViewController(alert, animated: true, completion: nil)
let logoutAction = UIAlertAction(title: "OK", style: .Default, handler: {
(UIAlertAction) -> Void in
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let exampleViewController: SignUpViewController = mainStoryboard.instantiateViewControllerWithIdentifier("SignUpViewController") as! SignUpViewController
vc?.presentViewController(exampleViewController, animated: true, completion: nil)
PFUser.logOut()
})
alert.addAction(logoutAction)
}
}
Hopefully I will save somebody's time!

If by saying "unresolved identifiers" you mean to "kPFErrorInvalidSessionToken" then you should use PFErrorCode.ErrorInvalidSessionToken.rawValue instead.
please tell me if you succeded in catching the error because all i get back is a nil NSErrorPointer.

Here is my solution, largely based on code in the Parse.com iOS developers guide.
class ParseErrorHandler {
class func handleParseError(error: NSError) {
if error.domain != PFParseErrorDomain {
return
}
switch (error.code) {
// error code 209 handling
case PFErrorCode.ErrorInvalidSessionToken.rawValue:
invalidSessionTokenHandler()
default:
break
}
}
// NOTE: User has no other option but to log out in this implementation
private class func invalidSessionTokenHandler() {
let message: String = "Session is no longer valid, you are no longer logged in"
let alert = UIAlertController(title: nil, message: message, preferredStyle: .Alert)
let presentingViewController = UIApplication.sharedApplication().keyWindow?.rootViewController
presentingViewController?.presentViewController(alert, animated: true, completion: nil)
let logoutAction = UIAlertAction(title: "OK", style: .Default, handler: {
(UIAlertAction) -> Void in
let loginViewController:UIViewController = UIStoryboard(name: "Main", bundle:
nil).instantiateViewControllerWithIdentifier("Login_2.0")
presentingViewController?.presentViewController(loginViewController, animated: true, completion: nil)
PFUser.logOut()
})
alert.addAction(logoutAction)
}
}
Above is the errorHandler class that should be used to catch all errors according to the Parse documentation (in this case I'm only showing error 209)
Here is how I catch this error in AppDelegate.swift within application function:
PFAnalytics.trackAppOpenedWithLaunchOptionsInBackground(launchOptions, block: {
(suceeded: Bool?, error: NSError?) -> Void in
if let err = error {
ParseErrorHandler.handleParseError(err)
}
})
Note that the user is technically still logged in hence why logout is called

Related

Code not finishing the function, it is ending execution halfway through

My code is as follows:
#IBAction func clicked(_ sender: Any) {
let ref = Database.database().reference()
let pass = password.text
var firpass = ""
var bool = false;
ref.child(name.text as! String).child("password").observeSingleEvent(of: .value, with: { dataSnapshot in
firpass = dataSnapshot.value as! String
if firpass == pass {
bool = true
print("in here")
}
})
print(bool)
if bool {
self.sendname = name.text!
let vc = DatabaseTableViewController(nibName: "DatabaseTableViewController", bundle: nil)
vc.finalName = self.sendname
navigationController?.pushViewController(vc, animated: true)
performSegue(withIdentifier: "username", sender: self)
} else {
let alert = UIAlertController(title: "Error", message: "Incorrect username or password", preferredStyle: UIAlertController.Style.alert)
alert.addAction(UIAlertAction(title: "OK", style: UIAlertAction.Style.default, handler: nil))
self.present(alert, animated: true, completion: nil)
}
}
"in here" gets printed, but bool is never printed and the alert is showing. Why does my code not enter the if bool block and output the alert?
Data is loaded from Firebase asynchronously, since it may take a while. Instead of making your app wait for the data (which would be a bad user experience), your main code continues while the data is being loaded, and then once the data is available your closure is called.
This explains the behavior you're seeing: by the time your runs, the hasn't run yet.
the solution is as simple as it is initially confusing and annoying: any code that needs the data from the database must be inside the closure, or be called from there.
So for example:
ref.child(name.text as! String).child("password").observeSingleEvent(of: .value, with: { dataSnapshot in
firpass = dataSnapshot.value as! String
if firpass == pass {
bool = true
print("in here")
}
print(bool)
if bool {
self.sendname = name.text!
let vc = DatabaseTableViewController(nibName: "DatabaseTableViewController", bundle: nil)
vc.finalName = self.sendname
navigationController?.pushViewController(vc, animated: true)
performSegue(withIdentifier: "username", sender: self)
} else {
let alert = UIAlertController(title: "Error", message: "Incorrect username or password", preferredStyle: UIAlertController.Style.alert)
alert.addAction(UIAlertAction(title: "OK", style: UIAlertAction.Style.default, handler: nil))
self.present(alert, animated: true, completion: nil)
}
})
Also see:
Firebase with Swift 3 counting the number of children
Array of struct not updating outside the closure
getting data out of a closure that retrieves data from firebase (showing examples with custom callbacks and delegates)
How to reload data after all Firebase calls finished? (showing how to use a dispatch group)
Finish all asynchronous requests before loading data? (another example using a dispatch group)
Also you have to set variable bool to false when you are navigating to next view controller after login. So that you login again and if password is wrong then you can not navigate to next page and only it shows alert for wrong password.

How to Delete Current User with UIAlert using Swift with Firebase

quick question I am trying to give the user the option to delete their account from firebase using swift on Xcode.
I currently have a "Delete" button that leads to a UIAlert that ask if the user is sure they want to delete their account (just in case) like this
and my code for this action is below
//Handles delete current user account (not fnished yet)
#IBAction func deleteAccount(_ sender: Any) {
createAlert2(title: "Delete Account", message: "Are you sure you want to delete your account? This will permanently erase your account.")
}
to this function
func createAlert2 (title:String, message:String){
let alert2 = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.alert)
alert2.addAction(UIAlertAction(title: "Cancel", style: UIAlertActionStyle.cancel, handler: { (action) in
alert2.dismiss(animated: true, completion: nil)
}))
alert2.addAction(UIAlertAction(title: "Delete", style: UIAlertActionStyle.destructive, handler: { (action) in
let user = Auth.auth().currentUser
user?.delete { error in
if error != nil {
// An error happened.
} else {
// Account deleted.
print("user deleted")
}
}
let controller2 = UIStoryboard.init(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "MenuViewController") as! MenuViewController
self.present(controller2, animated: true, completion: nil)
}))
self.present(alert2, animated: true, completion: nil)
My goal is to delete the user and send them back to that MenuViewController. But all it seems to do is send the user to that menu view and not actually delete their account on firebase. Any help is appreciated and I always like and check mark answers. Thank you:)
If you print errors or just put few breakpoints after user?.delete, most probably you going to see something like this:
Optional
- some : Error Domain=FIRAuthErrorDomain Code=17014 "This operation is sensitive and requires recent authentication. Log in again before retrying this request." UserInfo={NSLocalizedDescription=This operation is sensitive and requires recent authentication. Log in again before retrying this request., error_name=ERROR_REQUIRES_RECENT_LOGIN}
It means that you need to sign up or re-authenticate again with credentials (email, password) to have the ability to delete your user. You can user code bellow with some improvements(choose your way how to get credentials)
// Latest firebase + swift 4
let user = Auth.auth().currentUser
let password = "mypassword from stream - ask for a password from your user"
let email = user?.email
let credential = EmailAuthProvider.credential(withEmail: email, password: password)
user?.reauthenticateAndRetrieveData(with: credential, completion: { (result, error) in
if let error = error {
// handle error here
print(error)
}else{
user?.delete { error in
if let error = error {
// handle your error here
print(error)
}else{
do {
// handle your signout smth like:
try Auth.auth().signOut()
self.dismiss(animated: true, completion: nil)
} catch let logoutError {
// handle your error here
print(logoutError)
}
}
}
}
})
Unfortunately this issue documentation is very poor(especially latest version). Hope you find my answer useful.
Note***: giving your user ability to delete his profile directly it is a very BAD idea (IMHO), better if you send email notification and disable user and invalidate his tokens or UID, it will give you more flexibility in the future.

Swift 4: Azure DB with Facebook Authentication Callback method

app in swift4+xcode9 we are connection with DataBase in Azure with authentication through facebook.
in the App when launch the viewController, the login window of facebook appears.
I enter the user and the password but when the control will be return to the app will appears this window and stay there (nor return to the app control:
window callback
this is the code of viewDidAppear:
override func viewDidAppear(_ animated: Bool) {
let delegate = UIApplication.shared.delegate as! AppDelegate
let cliente = delegate.cliente
cliente?.login(withProvider: "facebook", urlScheme: "portfoliodispositivos", controller: self, animated: true) {
(usuario, error) -> Void in
if (error != nil) {
let alerta = UIAlertController(title: "Error", message: "Ocurrió un error al iniciar sesión en Facebook Error: \(String(describing: error?.localizedDescription))", preferredStyle: .alert)
alerta.addAction(UIAlertAction(title: "Ok", style: .default, handler: nil))
self.present(alerta, animated: true, completion: nil)
} else {
print("sin error en login")
let tablaUbicaciones = cliente?.table(withName: "Ubicaciones")
tablaUbicaciones?.read(){
(resultado, error) in
if error != nil {
print("Error: \(error.debugDescription)")
} else {
self.ubicaciones.removeAll()
for item in (resultado?.items)! {
let ubicacion = item as NSDictionary
self.ubicaciones.append(ubicacion)
}
}
}
}
}
self.tableView.reloadData()
}
In previous versions of swift the login not included urlScheme and I do not understand what scheme it refers to.
If push 'Done' in the window the control return with error. I d not understand if the message is 'You have successfully signed in' why does not it come back without error automatically?

AWS Cognito doesn't call confirmSignUp when confirming user identity in Swift with Xcode

I finally managed to get the SignUp to work, but when trying to confirm the signup, I'm reaching a problem. Here is my code:
var user: AWSCognitoIdentityUser?
#IBAction func submitButton(_ sender: Any) {
guard let confirmationCodeValue = self.codeTextField.text, !confirmationCodeValue.isEmpty else {
let confirmationAlert = UIAlertController(title: alertTitle, message: alertMessage, preferredStyle: .alert)
confirmationAlert.addAction(UIAlertAction(title: "好", style: .default, handler: {action in
print("Try again!")
}))
self.present(confirmationAlert, animated: true, completion: nil)
return
}
self.user?.confirmSignUp(self.codeTextField.text!, forceAliasCreation: true).continue({[weak self] (task: AWSTask) -> Any? in
guard let strongSelf = self else { return nil }
DispatchQueue.main.async(execute: {
print("At least this is working...")
if let error = task.error {
let confirmationFailAlert = UIAlertController(title: (error as NSError).userInfo["__type"] as? String,
message: (error as NSError).userInfo["__type"] as? String,
preferredStyle: .alert)
confirmationFailAlert.addAction(UIAlertAction(title: "好",
style: .default,
handler: {action in
}))
self?.present(confirmationFailAlert, animated: true, completion: nil)
} else {
let confirmationSuccessAlert = UIAlertController(title: self?.alertTitleConfirmationComplete,
message:self?.alertMessageConfirmationComplete,
preferredStyle: .alert)
confirmationSuccessAlert.addAction(UIAlertAction(title: "好",
style: .default,
handler: {action in
self?.dismiss(animated: true, completion: nil)
}))
self?.present(confirmationSuccessAlert, animated: true, completion: nil)
}
})
return nil
})
}
The first part of this code works fine. If I type nothing in the space, I get an alertView telling me so. However, if I type anything in the space, nothing happens. The print statement "At least this is working..." never gets called. I've been staring at this code for a couple hours now trying to figure out what's wrong, and I feel like it's probably something simple, but as of now, I could use some help!
Thanks in advance!
I assume the code block above is not the full source, but be sure the optional, user, is "unencapsulated" and equal to an actual instance of AWSCognitoIdentityUser.
If it isn't, which I am assuming it is not, confirmSignUp won't know the username, sub, or have any information on the user it is "confirming".
I would recommend logging user and be sure that username is in fact a value within user.
I believe you set it equal to that instance type in the response to your AWSCognitoIdentityUserPool class signUp:password:userAttributes:validationData: call.
Check those values that are returned in AWSCognitoIdentityUserPoolSignUpResponse.

"fatal error: unexpectedly found nil while unwrapping an Optional value" in Standardized Social Media Sharing Method

I am trying to create a standardized social media sharing method inside my SocialMediaSharingDelegate. Specifying an individual social media service like I do in the facebookShare method works perfectly fine. So to extend this I created an enum with the possible service types and the shareOn method accepts any valid service name to perform sharing.
It seems straight forward. However, when I run the code and click on a button that calls the shareOn method I get a runtime error. The error "fatal error: unexpectedly found nil while unwrapping an Optional value" occurs on the line let serviceViewController... right after the guard statement.
It also works fine if I replace socialMediaService.associatedService() with SLServiceTypeFacebook on that line which is strange because socialMediaService.associatedService() is used without issue in the guard statement.
I can just create separate functions for each service for now but that is not ideal in terms of code reuse.
import Foundation
import UIKit
import Social
enum SocialMediaEnum : String {
case Twitter = "SLServiceTypeTwitter"
case Facebook = "SLServiceTypeFacebook"
// This internal enum function returns the SLServiceType associated with the current enum value
func associatedService() -> String {
var serviceName: String
switch self {
case .Twitter:
serviceName = "SLServiceTypeTwitter"
case .Facebook:
serviceName = "SLServiceTypeFacebook"
}
return serviceName
}
}
class socialMediaSharing : SocialMediaSharingDelegate {
func shareOn(let socialMediaService: SocialMediaEnum, sender: subclassedUIButton?, currentViewController: UIViewController) {
guard SLComposeViewController.isAvailableForServiceType(socialMediaService.associatedService()) else {
let alert = UIAlertController(title: "Accounts", message: "Please login to a Twitter account to tweet.", preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.Default, handler: nil))
currentViewController.presentViewController(alert, animated: true, completion: nil)
return
}
let serviceViewController :SLComposeViewController = SLComposeViewController(forServiceType: socialMediaService.associatedService())
if let imageUrl = sender?.urlString {
if let url:NSURL = NSURL(string: imageUrl as String) {
serviceViewController.addURL(url)
}
}
currentViewController.presentViewController(serviceViewController, animated: true, completion: nil)
}
func facebookShare(sender: subclassedUIButton?, currentViewController: UIViewController) {
guard SLComposeViewController.isAvailableForServiceType(SLServiceTypeFacebook) else {
let alert = UIAlertController(title: "Accounts", message: "Please login to a Facebook account to share.", preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.Default, handler: nil))
currentViewController.presentViewController(alert, animated: true, completion: nil)
return
}
let shareToFacebook :SLComposeViewController = SLComposeViewController(forServiceType: SLServiceTypeFacebook)
if let imageUrl = sender?.urlString {
if let url:NSURL = NSURL(string: imageUrl as String) {
shareToFacebook.addURL(url)
}
}
currentViewController.presentViewController(shareToFacebook, animated: true, completion: nil)
}
}
SLServiceTypeTwitter and SLServiceTypeFacebook are keywords so they should not have quotation marks in the switch statement. The actual values they hold are "com.apple.social.(service name)".