I've integrated cognito into my xcode project. The sign up/password update features are working correctly. However I can't seem to get the sign in process to work. I turned on the logs and I get the following error
{"__type":"NotAuthorizedException","message":"Access Token has expired"}
Domain=com.amazonaws.AWSCognitoIdentityProviderErrorDomain Code=-1000 "Authentication delegate not set" UserInfo={NSLocalizedDescription=Authentication delegate not set}]
I have also implemented the AWSCognitoIdentityInteractiveAuthenticationDelegate delegate in the AppDelegate script.
Here's the AppDelegate code
class AppDelegate: UIResponder, UIApplicationDelegate {
class func defaultUserPool() -> AWSCognitoIdentityUserPool {
return AWSCognitoIdentityUserPool(forKey: userPoolID)
}
var window: UIWindow?
var loginViewController: LoginVC?
var navigationController: UINavigationController?
var storyboard: UIStoryboard?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
// Warn user if configuration not updated
if (CognitoIdentityUserPoolId == "us-east-1_TavWWBZtI") {
let alertController = UIAlertController(title: "Invalid Configuration",
message: "Please configure user pool constants in Constants.swift file.",
preferredStyle: .alert)
let okAction = UIAlertAction(title: "Ok", style: .default, handler: nil)
alertController.addAction(okAction)
self.window?.rootViewController!.present(alertController, animated: true, completion: nil)
//print("Please configure user pool constants in Constants.swift file.")
}
// setup logging
AWSDDLog.sharedInstance.logLevel = .verbose
AWSDDLog.add(AWSDDTTYLogger.sharedInstance)
// setup service configuration
let serviceConfiguration = AWSServiceConfiguration(region: CognitoIdentityUserPoolRegion, credentialsProvider: nil)
// create pool configuration
let poolConfiguration = AWSCognitoIdentityUserPoolConfiguration(clientId: CognitoIdentityUserPoolAppClientId,
clientSecret: CognitoIdentityUserPoolAppClientSecret,
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 AWSMobileClient.sharedInstance().interceptApplication(
application, didFinishLaunchingWithOptions:
launchOptions)
//return true
}
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
if let navigationController = self.window?.rootViewController as? UINavigationController {
if navigationController.visibleViewController is SummaryReportVC ||
navigationController.visibleViewController is GoalStatusReportVC || navigationController.visibleViewController is YearTotalsReportVC || navigationController.visibleViewController is DailyActivityReportVC {
return UIInterfaceOrientationMask.all
} else {
return UIInterfaceOrientationMask.portrait
}
}
return UIInterfaceOrientationMask.portrait
}
func applicationWillResignActive(_ application: UIApplication) {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
}
func applicationDidEnterBackground(_ application: UIApplication) {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
func applicationWillEnterForeground(_ application: UIApplication) {
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
}
func applicationDidBecomeActive(_ application: UIApplication) {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
func applicationWillTerminate(_ application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
}
extension AppDelegate: AWSCognitoIdentityInteractiveAuthenticationDelegate {
func startPasswordAuthentication() -> AWSCognitoIdentityPasswordAuthentication {
print("Calling signin VC from app delegate")
if (self.navigationController == nil) {
self.navigationController = self.storyboard?.instantiateViewController(withIdentifier: "NCFirst") as? UINavigationController
}
if (self.loginViewController == nil) {
self.loginViewController = self.navigationController?.viewControllers[0] as? LoginVC
}
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.loginViewController!
}
}
Here's my LoginVC code
class LoginVC: UIViewController {
@IBOutlet weak var loginButton: UIButton!
@IBOutlet weak var forgotPasswordLabel: UILabel!
@IBOutlet weak var signUpLabel: UILabel!
@IBOutlet weak var emailTF: UITextField!
@IBOutlet weak var passwordTF: UITextField!
var passwordAuthenticationCompletion: AWSTaskCompletionSource<AWSCognitoIdentityPasswordAuthenticationDetails>?
let pool = AWSCognitoIdentityUserPool(forKey: AWSCognitoUserPoolsSignInProviderKey)
var usernameText: String?
override func viewDidLoad() {
super.viewDidLoad()
self.navigationController?.navigationBar.tintColor = UIColor.white
self.navigationItem.backBarButtonItem = UIBarButtonItem(title: "", style: .plain, target: nil, action: nil)
self.navigationController!.navigationBar.setBackgroundImage(UIImage(), for: .default)
self.navigationController!.navigationBar.shadowImage = UIImage()
self.navigationController!.navigationBar.isTranslucent = true
loginButton.addTarget(self, action: #selector(loginUser), for: .touchUpInside)
loginButton.layer.cornerRadius = 18
emailTF.addPadding(.left(35))
passwordTF.addPadding(.left(35))
let tap = UITapGestureRecognizer(target: self, action: #selector(goToForgotPasswordVC))
let tap2 = UITapGestureRecognizer(target: self, action: #selector(goToSignUp1VC))
forgotPasswordLabel.isUserInteractionEnabled = true
forgotPasswordLabel.addGestureRecognizer(tap)
signUpLabel.isUserInteractionEnabled = true
signUpLabel.addGestureRecognizer(tap2)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.passwordTF.text = nil
self.emailTF.text = usernameText
}
@objc func loginUser() {
print("Got inside Login func")
if (self.emailTF.text != nil && self.passwordTF.text != nil) {
print("Calling login method now")
let authDetails = AWSCognitoIdentityPasswordAuthenticationDetails(username: self.emailTF.text!, password: self.passwordTF.text! )
self.passwordAuthenticationCompletion?.set(result: authDetails)
} else {
print("Empty fields")
let alertController = UIAlertController(title: "Missing information",
message: "Please enter a valid user name and password",
preferredStyle: .alert)
let retryAction = UIAlertAction(title: "Retry", style: .default, handler: nil)
alertController.addAction(retryAction)
}
}
@objc func goToActivitySessionsVC() {
let storyboard = UIStoryboard(name: "TabBar", bundle: nil)
let destVC = storyboard.instantiateViewController(withIdentifier: "TabBarVC")
self.navigationController?.pushViewController(destVC, animated: true)
self.navigationController?.isNavigationBarHidden = true
}
@objc func goToForgotPasswordVC() {
let storyboard = UIStoryboard(name: "ForgotPassword", bundle: nil)
let destVC = storyboard.instantiateViewController(withIdentifier: "ForgotPasswordVC")
self.navigationController?.pushViewController(destVC, animated: true)
}
@objc func goToSignUp1VC() {
let storyboard = UIStoryboard(name: "SignUp", bundle: nil)
let destVC = storyboard.instantiateViewController(withIdentifier: "SignUp1VC")
self.navigationController?.pushViewController(destVC, animated: true)
}
/* func checkLoginStatus() {
if !AWSSignInManager.sharedInstance().isLoggedIn {
showSignIn()
}
else {
print("Logged In")
AWSSignInManager.sharedInstance().logout(completionHandler: {(result: Any?, error: Error?) in
self.showSignIn()
print("Sign-out Successful");
})
}
}
}
*/
extension LoginVC: AWSCognitoIdentityPasswordAuthentication {
public func getDetails(_ authenticationInput: AWSCognitoIdentityPasswordAuthenticationInput, passwordAuthenticationCompletionSource: AWSTaskCompletionSource<AWSCognitoIdentityPasswordAuthenticationDetails>) {
print("Get details called")
self.passwordAuthenticationCompletion = passwordAuthenticationCompletionSource
DispatchQueue.main.async {
if (self.usernameText == nil) {
self.usernameText = authenticationInput.lastKnownUsername
}
}
}
public func didCompleteStepWithError(_ error: Error?) {
print("Did commplete step with error called")
DispatchQueue.main.async {
if let error = error as NSError? {
let alertController = UIAlertController(title: error.userInfo["__type"] as? String,
message: error.userInfo["message"] as? String,
preferredStyle: .alert)
let retryAction = UIAlertAction(title: "Retry", style: .default, handler: nil)
alertController.addAction(retryAction)
self.present(alertController, animated: true, completion: nil)
print(error.description)
} else {
self.emailTF.text = nil
self.dismiss(animated: true, completion: nil)
print("Got in else")
}
}
}
}
One other thing to note is that getDetails never gets called and so does the didCompleteStepWithError method. When I click the sign in button, nothing happens.