4

(Note: this is related to this question I posted, but since my original question was answered and I am now encountering a different issue, I am posting this as a new question.)

I am setting up registration and login for an iOS app which uses DynamoDB and AWS Cognito. I eventually got the registration login process to work, but I've noticed that whenever I log out and then immediately try to log back in, the app fails to do so and I get the error message Invalid login token. Can't pass in a Cognito token. Only after I close and relaunch the app can I successfully log in again.

I primarily used this example project to set up registration, but when I was implementing the sign-in method, I had some trouble converting from Objective-C to Swift. I wasn't able to get the login process from the example to work, so I instead set up an explicit login method:

if locked { return }
    trimRegistrationValues()
    let name = usernameField.text!
    let user = pool!.getUser(name)
    lock()
    user.getSession(name, password: passwordField.text!, validationData: nil, scopes: nil).continueWithExecutor(AWSExecutor.mainThreadExecutor(), withBlock: {
        (task:AWSTask!) -> AnyObject! in

        if task.error != nil {
            self.sendErrorPopup("ERROR: Unable to sign in. Error description: " + task.error!.description)
        } else {
            print("Successful Login")

            let loginKey = "cognito-idp.us-east-1.amazonaws.com/" + USER_POOL_ID
            var logins = [NSString : NSString]()
            self.credentialsProvider!.identityProvider.logins().continueWithBlock { (task: AWSTask!) -> AnyObject! in

                if (task.error != nil) {
                    print("ERROR: Unable to get logins. Description: " + task.error!.description)

                } else {
                    if task.result != nil{
                        let prevLogins = task.result as! [NSString:NSString]
                        print("Previous logins: " + String(prevLogins))
                        logins = prevLogins
                    }
                    logins[loginKey] = name
                    let manager = IdentityProviderManager(tokens: logins)
                    self.credentialsProvider!.setIdentityProviderManagerOnce(manager)
                    self.credentialsProvider!.getIdentityId().continueWithBlock { (task: AWSTask!) -> AnyObject! in

                        if (task.error != nil) {
                            print("ERROR: Unable to get ID. Error description: " + task.error!.description)

                        } else {
                            print("Signed in user with the following ID:")
                            print(task.result)
                            dispatch_async(dispatch_get_main_queue()){
                                self.performSegueWithIdentifier("mainViewControllerSegue", sender: self)
                            }
                        }
                        return nil
                    }
                }
                return nil
            }
        }
        self.unlock()
        return nil
    })

Currently, the code in my AppDelegate class for setting up Cognito looks like this:

let userPoolConfiguration = AWSCognitoIdentityUserPoolConfiguration(clientId:APP_CLIENT_ID, clientSecret: APP_CLIENT_SECRET, poolId: USER_POOL_ID)
    let pool = AWSCognitoIdentityUserPool(forKey:USER_POOL_NAME)
    pool.delegate = self
    self.storyboard = UIStoryboard(name: "Main", bundle: nil)
    self.credentialsProvider = AWSCognitoCredentialsProvider(regionType: .USEast1, identityPoolId: IDENTITY_POOL_ID, identityProviderManager:pool)
    let serviceConfiguration = AWSServiceConfiguration(region:.USEast1, credentialsProvider:credentialsProvider!)
    AWSCognitoIdentityUserPool.registerCognitoIdentityUserPoolWithConfiguration(serviceConfiguration, userPoolConfiguration: userPoolConfiguration, forKey: USER_POOL_NAME)
    let manager = IdentityProviderManager(tokens: [NSString:NSString]())
    self.credentialsProvider = AWSCognitoCredentialsProvider(regionType: .USEast1, identityPoolId: IDENTITY_POOL_ID, identityProviderManager: manager)

    AWSServiceManager.defaultServiceManager().defaultServiceConfiguration = serviceConfiguration
    startPasswordAuthentication()

The viewDidLoad() method in the login ViewController only contains this line regarding the Cognito values I use for logging in:

if pool == nil{
        pool = AWSCognitoIdentityUserPool(forKey:USER_POOL)
    }

In the prepareForSegue() case from the login ViewController to the first view the user sees after logging in, I set the user by calling:

destination.user = pool!.getUser(usernameField.text!)

In the method for signing out from this view, I call user!.signOut().

I've noticed that many Cognito example projects call credentialsProvider.clearKeychain() after signing out, but this did not solve the issue for me. I've been having trouble finding many examples showing specifically how to log out through Cognito. I've also heard that AWS credentials expire after an hour after signing into an app like this. What is the proper way to handle credentials if I want to solve this problem and avoid other situations that might force my users to relaunch the app in order to sign in?

Community
  • 1
  • 1
user3726962
  • 333
  • 1
  • 4
  • 17

1 Answers1

1

On Log out in additions to user.signOut() getDetails needs to be called again! Not quite sure why this would be the case after signOut, but definitely fixed it for me. self.user?.getDetails().continueOnSuccessWith { (task) -> AnyObject? in return nil }

kos
  • 1,357
  • 9
  • 21
  • Unfortunately this does not seem to completely fix the issue. On restart of the app same issue occurs. – kos Nov 26 '19 at 12:50
  • Hi @kos can you update your answer with more code if you have solved this issue? – Anurag Sharma Sep 07 '20 at 12:23
  • I think the biggest issue and what needs to be taken care of is that you logout on the previously logged in environment first before attempting to log back in with new configuration. – kos Sep 08 '20 at 14:28
  • I have resolved the issue, The false thing I was doing that I was making the `pool` and `credentialsProvider` `nil` after `signout` and `getDetails` method. The solution was to make the `getDetails` call after `signOut` then nothing else. Thank you. – Anurag Sharma Sep 08 '20 at 17:11