aws-amplify / amplify-swift

A declarative library for application development using cloud services.
Apache License 2.0
449 stars 194 forks source link

I want to amplify to recognize the user as logged in authentically and give us STS credentials. Then want to access the resources using Amplify SDK #1851

Closed bhaveshlsamcom closed 2 years ago

bhaveshlsamcom commented 2 years ago

Discussed in https://github.com/aws-amplify/amplify-ios/discussions/1850

Originally posted by **bhaveshlsamcom** June 2, 2022 Hello Folks, In iOS, We are trying to get the user logged in and give us STS credentials using the authentication way. So, for that -> First do the login with Facebook it gives the token. -> And we created the login API which manages the “Validate the token and create a new Cognito user in the Cognito user pool ” and it returns the “cognito_account” and “id_token” -> Then we use that id_token to do federation sign in - It’s a success -> Afterward, we get the identity ID successfully -> And then get the credential using Cognito identity Not able to get the auth session, I want to use the authentication way and then access the resources using Amplify. Here is the error: Recovery suggestion: Invoke Auth.signIn to re-authenticate the user), cognitoTokensResult: Swift.Result.failure(AuthError: Session expired could not fetch cognito tokens Recovery suggestion: Invoke Auth.signIn to re-authenticate the user)) Screenshot attached ![Screenshot 2022-06-02 at 3 45 45 PM](https://user-images.githubusercontent.com/75381167/171609330-b7e75ebf-adbc-49bb-bb9e-0be9b8c106a0.png) ![Screenshot 2022-06-02 at 3 45 53 PM](https://user-images.githubusercontent.com/75381167/171609365-16859c37-34b4-4ebc-aba0-5c9a0ee657c2.png) Thanking you,
royjit commented 2 years ago

@bhaveshlsamcom thanks for reaching out. You are trying to use aws-sdk-ios Cognito SDK along with amplify-ios library and expect to get a signed in session. This is not a supported flow, you could simply do this in your code:

func getAuthAWSTemporaryCredentials() {

  Amplify.Auth.signIn(...) {

         // On successful signIn, invoke fetchAuthSession
         Amplify.Auth.fetchAuthSession() {
         }
  }

}
maxfalc commented 2 years ago

hi @royjit

Thanks for your reply. I am in touch with @bhaveshlsamcom and I want to help to better describe the problem. In order to use the native login (apple and facebook sdk) without using the hosted UI we have implemented some lambdas which, when the apple or facebook token is received, creates a cognito user, login the user with a custom AUTH flow and send back the id cognito token to the app. In android then we map the logins of the credential provider to such token (see below)

        try {
            Map<String, String> logins = new HashMap<String, String>();
            logins.put("cognito-idp.eu-central-1.amazonaws.com/eu-XXXXXXXXXXXXXX", idToken);
            credentialsProvider.setLogins(logins);
            AWSSessionCredentials credentials = credentialsProvider.getCredentials();
            accessKey = credentials.getAWSAccessKeyId();
            secretkey = credentials.getAWSSecretKey();
            sessionToken = credentials.getSessionToken();
        } catch (Exception e) {
            Log.e("Max Test", String.valueOf(e));
        }

After this in Android we can fetch the STS credentials in amplify with no issue.

Our problem is that we cannot do the same in iOS. As you can see from what @bhaveshlsamcom shared we are trying to set the logins to the token using a custom identity provider. But when we try to fetch the STS token with amplify it always returns user is not signed in.

We don't want to use Amplify.Auth.signIn but to pass the token generated by the lambda to authenticate the user.

We wonder why this is possible in Android but not in iOS.

I hope this might help a bit. We need to find a solution. it's more than two weeks that we are going in circle with this, Thanks

royjit commented 2 years ago

iOS Amplify implementation rely on the underlying AWSMobileClient, so making changes in the AWSCredentialsProvider will not affect the AWSMobileClient internal state. I do not think you can do the same in amplify-iOS, but I could see a workaround like this:

  1. Do your flow of FB/Apple SDK signIn and use lambda to create Cognito User.
  2. Use Amplify.Auth.SignIn with custom auth to signIn the user https://docs.amplify.aws/lib/auth/signin_with_custom_flow/q/platform/ios/
  3. Call Amplify.Auth.fetchAuthSession to get valid credentials.
maxfalc commented 2 years ago

Thanks @royjit

But if iOS Amplify implementation relies on the underlying AWSMobileClient. Can't we use AWSMobileClient.sharedInstance().federatedSignIn to login the user with the token obtained from step 1? Our lambda after a user is created sends back a cognito pool id token, which we have verified to be correct.

Because of this we tried to use the token as below to sign the user:

AWSMobileClient.sharedInstance().federatedSignIn(
                providerName: IdentityProvider.developer.rawValue,
                token: cognitoTokens.token,
                federatedSignInOptions: FederatedSignInOptions(cognitoIdentityId: cognitoTokens.identityId),
                completionHandler: { (userState, error) in
                    if let userState = userState {
                        os_log("\nSigned in as: %@", type: .debug, userState.rawValue)
                    } else if let error = error {
                        os_log("\nError federated sign in: %@", type: .error, error.localizedDescription)
                    }
                }
)

But then when we call Call Amplify.Auth.fetchAuthSession to get valid credentials, we still receive the message that the user is not signed in, Shouldn't amplify recognize the user as logged in via federation? Thanks in advance

PS: or should we use cognito-identity.amazonaws.com as providerName (see below)?

AWSMobileClient.sharedInstance().federatedSignIn(
                providerName: cognito-identity.amazonaws.com,
                token: cognitoTokens.token,
                federatedSignInOptions: FederatedSignInOptions(cognitoIdentityId: cognitoTokens.identityId),
                completionHandler: { (userState, error) in
                    if let userState = userState {
                        os_log("\nSigned in as: %@", type: .debug, userState.rawValue)
                    } else if let error = error {
                        os_log("\nError federated sign in: %@", type: .error, error.localizedDescription)
                    }
                }
)
royjit commented 2 years ago

That should work, you will get authenticated credentials. Can you try adding with providername as: cognito-idp.<region>.amazonaws.com/<YOUR_USER_POOL_ID>, for example, cognito-idp.us-east-1.amazonaws.com/us-east-1_123456789 reference - https://docs.aws.amazon.com/cognitoidentity/latest/APIReference/API_GetId.html#API_GetId_RequestSyntax .

You can get the underlying AWSMobileClient as shown here: https://docs.amplify.aws/lib/auth/escapehatch/q/platform/ios/

bhaveshlsamcom commented 2 years ago

Thank you @royjit and @maxfalc Issue is resolved now.

dsaliberti commented 1 year ago

@royjit I'm trying to use this federated signIn with Cognito as providerName and am getting {"__type":"NotAuthorizedException","message":"Token is not from a supported provider of this identity pool."}

What exactly should be enabled in the Identity providers in the User pools configs? We want only cognito one, no one other (Google, Apple, etc) thank you!

victorOwnID commented 1 year ago

After calling to de federated identities sign in method as explained above, I get:

Status: signedIn

However, this method

  if let currentUser = Amplify.Auth.getCurrentUser() {
                        print("Current user: \(currentUser)")
                    } else {
                        print("No current user")
                    }

Return "No current user"

Why?

@royjit can you advise?

harsh62 commented 1 year ago

@victorOwnID This is because Amplify does not capture user details when using federated identities. You would have to write your own implementation to retrieve the user details from the provider i.e. (Google, Apple, FB SDK's would know the user details).