soto-project / soto

Swift SDK for AWS that works on Linux, macOS and iOS
https://soto.codes
Apache License 2.0
880 stars 83 forks source link

Configuration of Cognito Identity Pools giving errors "cannot find module in scope" #533

Closed RachaelSMathew closed 3 years ago

RachaelSMathew commented 3 years ago

The bug

I was previously using Pods to send logs from Xcode to Cloudwatch Logs. But I am now trying to use Soto(swift package manager) instead of Pods.

In this project, I want to configure with an identity pool id, just as I did with Pods here:

Screen Shot 2021-10-07 at 9 11 44 PM Screen Shot 2021-10-07 at 9 02 09 PM

So, I am using all the package products of the Soto Swift Packages and Soto Cognito Authentication Kit Swift Package to configure the identity pool:

Screen Shot 2021-10-07 at 9 05 48 PM

But I keep getting these errors:

Screen Shot 2021-10-07 at 9 20 26 PM

Questions

I would like to be able to configure my Cloudwatch AWS account with my identity pool id, the same way I did with the Pods. Do I need to do any configuration in the terminal? I have already done configuration for AWS there. Do I put my credentials in the AppDelegate.swift file the same way I did with Pods? I'm also confused about when syncShutdown needs to be called? Does this happen at the end of the didFinishLaunchingWithOptions function?

adam-fowler commented 3 years ago

If you are only using Cognito to access AWS services you don't need SotoCognitoAuthenticationKit.

Are you using a Cognito user pool to authenticate with? If so you can do the following

Use a .cognitoIdentity credential provider as follows

let userPoolId = "my user pool id"
let identityPoolId = "my identity pool id"
let identityProvider = "cognito-idp.<region>.amazonaws.com/\(userPoolId)"
let credential: CredentialProviderFactory = .cognitoIdentity(
    identityPoolId: identityPoolId, 
    logins: [ identityProvider : "id token received from user pools authentication"], 
    region: .useast1
)

let client = AWSClient(credentialProvider: credential, httpClientProvider: .createNew)

This client can then be used with any Soto service.

let cloudWatch = CloudWatch(client: client, region: region)

If you are using user pools for authentication you will have to call the CognitoIdentityProvider.initiateAuth call yourself to get the id token to include in the login dictionary above.

Unfortunately there isn't any direct support for refreshing ids at the moment. I am just looking into this. You can do it yourself if you use the alternative .cognitoIdentity call which takes a IdentityProviderFactory. https://github.com/soto-project/soto/blob/017a05d783eab5ba3941cfa8823e27625c5fc097/Sources/Soto/Extensions/CognitoIdentity/CognitoIdentity%2BCredentialProvider.swift#L135-L140

adam-fowler commented 3 years ago

As an aside I am working on a credential provider that will be part of SotoCognitoAuthenticationKit that does all the above. I have the starts of this inside Soto here.

RachaelSMathew commented 3 years ago

Thank you for your response. I am using the Cognito identity pool to authenticate. Does this mean for the CredentialProviderFactory, I would have an empty array for the login?

I have defined the AWSClient once in the class scope of the ViewController but I am still getting this error when I run the simulator. I did not call syncShutdown because you stated:

Although for each method of authentication it is best to have one global AWSClient which is never deleted so you should never need to call syncShutdown.

Screen Shot 2021-10-09 at 6 07 22 PM

Because I am defining my variables in the class scope of ViewController, is there a way to change the properties of the PutLogEvents class(logEvents, logGroupName, etc.) to be variables instead of 'let'? So that they can be changed later on if need be?

Screen Shot 2021-10-09 at 6 09 24 PM

Also, how do you access the sequence token from the DescribeLogStreamsResponse(or the uploadSequenceToken attribute as described in the AWS SDK?)

Screen Shot 2021-10-09 at 6 22 01 PM
adam-fowler commented 3 years ago

Hi @RachaelSMathew

As I understand it you need an Identity provider to authenticate with Cognito identity pools. This could be Cognito user pools, apple, amazon, google etc. They provide you with the values to stick in the logins parameter. If you allow unauthenticated access to your identity pool, I guess passing in nil for the logins should probably work (I personally haven't tried this, so can't guarantee it will work)

Your AWSClient is being deleted when your UIViewController is being deleted. You would need to call syncShutdown in the deinit of the UIViewController to ensure it is called before the AWSClient is deleted.

The request structures you send to the AWS commands are meant to be temporary structures. You would create one just before calling the AWS command. Because all the member variables are let there is no way to edit them once they are created.

How to access the response: The EventLoopFuture returned by the Soto commands is a structure that will be filled with the result of the AWS command once it is returned. There are multiple ways to access this value depending on what you want to do with it. You can call wait() on it to wait for the result. This isn't the best way because you are stalling your app while waiting for the result. You can call whenComplete with a closure which will be run when the result is available.

Here is the getting started guide to Soto which has a small section on asynchronous functions at the bottom https://soto.codes/getting-started.html. You should also checkout the swift-nio documentation on EventLoopFuture for more details. https://apple.github.io/swift-nio/docs/current/NIO/Classes/EventLoopFuture.html

As an aside Soto now provides async/await functionality. So you can use the new Swift 5.5 concurrency features with it

adam-fowler commented 3 years ago

Moving this across to discussions as it isn't really an issue