xiaolingxiao
xiaolingxiao

Reputation: 4895

AWS Cognito API `AWSMobileClient.default().addUserStateListener` only fires when user authentication state changes

I am using xcode 11 with swift 4. I am following the docs for aws cognito here https://aws-amplify.github.io/docs/ios/authentication and in AppDelegate.swift, I have:

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

    // initialize AWS amplify
    let apiPlugin = AWSAPIPlugin(modelRegistration: AmplifyModels())

    do {
        try Amplify.add(plugin: apiPlugin)
        try Amplify.configure()
    } catch {
        // Navigate to page showing bad network connection
        print("Failed to configure Amplify \(error)")
    }

    AWSMobileClient.default().addUserStateListener(self) { (userState, info) in
        switch (userState) {
            case .signedOut:
                // user clicked signout button and signedout
                print("AppDelegate.application state: user signed out")
            case .signedIn:
                print("AppDelegate.application state: user signed in: \(userState)")
            case .signedOutUserPoolsTokenInvalid:
                print("need to login again.")
            default:
                print("unsupported")
        }
    }

    return true
}

The AWSMobileClient.default().addUserStateListener only fires when the user is logging in or signing up for the first time. if the user is already authenticated. then addUserStateListener does not fire. This is an issue because I need to get the user's account token to access his/her information. Am I using the wrong Cognito API? Or is addUserStateListener used in the wrong function.

If I use the other Cognito API

AWSMobileClient.default().initialize { (userState, error) ... }

It fires each time, but I cannot access the user token from this api.

Upvotes: 0

Views: 766

Answers (1)

Michael Wells
Michael Wells

Reputation: 596

You can access the user token by using the AWSAppSync api and this method in you app delegate either by extending appDelegate or using your own custom class as I did.

class CognitoPoolProvider : AWSCognitoUserPoolsAuthProviderAsync {


    func getLatestAuthToken(_ callback: @escaping (String?, Error?) -> Void) {

        AWSMobileClient.default().getTokens { (token, error) in

            if let error = error {
                callback(nil,error)
            }
            callback(token?.accessToken?.tokenString, error)
        }
    }
}

So, in my appDelegate I did something like this

var appSyncClientBridge : AWSAppSyncClient?

    /// Sets the configuration settings for application's AWSAppSync Client.
    func appSyncSetup()throws -> AWSAppSyncClientConfiguration{

        let cache = try AWSAppSyncCacheConfiguration()
        let serviceConfig = try AWSAppSyncServiceConfig()

        let appSyncConfiguration = try AWSAppSyncClientConfiguration(appSyncServiceConfig: serviceConfig,
                                                                     userPoolsAuthProvider: CognitoPoolProvider(),
                                                                     cacheConfiguration: cache)


        return appSyncConfiguration
    }

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

        do {
            let configFile = try appSyncSetup()
            appSyncClientBridge = try AWSAppSyncClient(appSyncConfig: configFile)
        }
        catch(let error){
            print(error.localizedDescription)
        }

        return true
    }

UPDATE:

If the user is already logged in. You can create a method like this one.

func getTokens(){
        let getPool = CognitoPoolProvider()

        func getToken(completion: @escaping (Result<String,Error>)->Void){
            getPool.getLatestAuthToken { (token, error) in
                if let error = error {
                    completion(.failure(error))
                }
                if let token = token {
                    completion(.success(token))
                }
            }
        }

        getToken { (result) in
            print(("This is the token — \(String(describing: try? result.get() as String))"))
        }
    }

If you place this in your viewDidLoad you'll be able to access the user token. In this example it's just printed out, but I think from here you'll be able to use it for what you need.

Upvotes: 1

Related Questions