AWS Cognito User Pools with Mobile SDK for iOS Using Custom Challenge

June 07, 2018

I recently integrated an AWS Cognito User Pool into an iOS application. The sign-in feature utilizes a custom challenge for authentication. However, there is limited documentation on how to use the iOS SDK for this purpose. After several trials and errors, I finally succeeded in signing in. Below are the steps to accomplish this:

2018 06 07

Step 1: Create a CognitoUserPool

In the AppDelegate, after didFinishLaunchingWithOptions, the user pool is initialized as follows:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
  // Set up 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 the 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 {
      } else {
        self.dismiss(animated: true, completion: nil)

Step 4: Access User Attributes After Successful Sign-In

self.user?.getDetails().continueOnSuccessWith { (task) -> AnyObject? in
  DispatchQueue.main.async(execute: {
    self.response = task.result
    // Display user details
  return nil

If you have any questions, please feel free to ask. I hope AWS updates the documentation and provides sample code to make it easier to understand the SDK without having to resort to trial and error.

Profile picture

Victor Leung, who blog about business, technology and personal development. Happy to connect on LinkedIn