AWS Cognito User Pools with mobile SDK for iOS using custom challenge

I was integrating AWS Cognito user pool to an iOS application. The sign-in feature is using a custom challenge for authentication, but there is a lack of documentation about how to use the iOS SDK. After many trial and errors, I have finally able to sign in success, so I’m going to document the steps as shown below:

Step 1: Create a CognitoUserPool

In AppDelegate, after didFinishLaunchingWithOptions, the user pool is initialised.

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {

  // setup service configuration

  let serviceConfiguration = AWSServiceConfiguration(region: CognitoIdentityUserPoolRegion, credentialsProvider: nil

  // create pool configuration

  let poolConfiguration = AWSCognitoIdentityUserPoolConfiguration(clientId: CognitoIdentityUserPoolAppClientId, clientSecret: nil, poolId: CognitoIdentityUserPoolId)

// initialize user pool client

  AWSCognitoIdentityUserPool.register(with: serviceConfiguration, userPoolConfiguration: poolConfiguration, forKey: AWSCognitoUserPoolsSignInProviderKey)

  // fetch the user pool client we initialized in above step 

  let pool = AWSCognitoIdentityUserPool(forKey: AWSCognitoUserPoolsSignInProviderKey)

  self.storyboard = UIStoryboard(name: “Main”, bundle: nil)

  pool.delegate = self

  return true 

}

Step 2: Implement the protocol delegate

extension AppDelegate: AWSCognitoIdentityCustomAuthentication{

  func didCompleteStepWithError(_ error: Error?) {

  }

  func getCustomChallengeDetails(_ authenticationInput: AWSCognitoIdentityCustomAuthenticationInput, customAuthCompletionSource: AWSTaskCompletionSource<AWSCognitoIdentityCustomChallengeDetails>) {

  }

  func startCustomAuthentication() -> AWSCognitoIdentityCustomAuthentication {

  if (self.navigationController == nil) {

  self.navigationController = self.storyboard?.instantiateViewController(withIdentifier: “signinController”) as? UINavigationController

  }

  if (self.signInViewController == nil) {

  self.signInViewController =   self.navigationController?.viewControllers[0] as? SignInViewController

  }

  DispatchQueue.main.async {

    self.navigationController!.popToRootViewController(animated: true)

    if (!self.navigationController!.isViewLoaded

    || self.navigationController!.view.window == nil) {

self.window?.rootViewController?.present(self.navigationController!,

animated: true,

completion: nil)

     }

    }

  return self.signInViewController! 

  }

}

Step 3: Handle the custom challenge inside the sign-in view controller

extension SignInViewController: AWSCognitoIdentityCustomAuthentication {

func getCustomChallengeDetails(_ authenticationInput: AWSCognitoIdentityCustomAuthenticationInput, customAuthCompletionSource: AWSTaskCompletionSource<AWSCognitoIdentityCustomChallengeDetails>) {

let authDetails = AWSCognitoIdentityCustomChallengeDetails(challengeResponses: [“USERNAME”:”YourUserName”, “ANSWER”: “123456”])

customAuthCompletionSource.set(result: authDetails)

}

public func didCompleteStepWithError(_ error: Error?) {

DispatchQueue.main.async {

if let error = error as? NSError {

print(“error”)

} else {

print(“success”)

self.dismiss(animated: true, completion: nil)

}

}

}

}

Step 4: After sign in success, you can get the username and user attribute:

self.user?.getDetails().continueOnSuccessWith { (task) -> AnyObject? in

DispatchQueue.main.async(execute: {

self.response = task.result

// With user details

print(response)

})

return nil

}

Please let me know if you have any questions. I hope AWS could update the documentation and provide a sample example code to save us time to understand the SDK through trial and error.