Aws-sdk-ios: AWSMobileClient doesn't persist Session during CustomAuth

Created on 20 May 2020  Â·  6Comments  Â·  Source: aws-amplify/aws-sdk-ios

Describe the bug
If a CustomAuth flow is interrupted (by an app restart, e.g.), the CustomAuth flow cannot be completed successfully

To Reproduce
Steps to reproduce the behavior:

  1. I've configured AWSMobileClient for CustomAuth per: https://docs.amplify.aws/sdk/auth/custom-auth-flow/q/platform/ios
  2. Initiate first call of AWSMobileClient.default().signIn(username: username, password: "dummyPassword")
  3. Kill app to interrupt custom auth process
  4. Restart app and attempt to complete CustomAuth by: AWSMobileClient.default().confirmSignIn(challengeResponse: "<Challenge Response>"...

Observed Behavior
AWSMobileClient returns error 'Please call signIn before calling this method.'

Expected Behavior
AWSMobileClient should be able to continue/complete the original call to signIn. Maybe the Session needs to be persisted, instead of kept in memory?

Unique Configuration

{
    "IdentityManager": {
        "Default": {}
    },
    "CredentialsProvider": {
        "CognitoIdentity": {
            "Default": {
                "PoolId": "<redacted>",
                "Region": "us-east-1"
            }
        }
    },
    "CognitoUserPool": {
        "Default": {
            "PoolId": "<redacted>",
            "AppClientId": "<redacted>",
            "Region": "us-east-1"
        }
    },
    "Auth": {
      "Default": {
        "authenticationFlowType": "CUSTOM_AUTH"
      }
    }
}

Areas of the SDK you are using (AWSMobileClient, Cognito, Pinpoint, IoT, etc)?
AWSMobileClient

Environment(please complete the following information):

  • SDK Version: 2.13.1 AWSMobileClient
  • Dependency Manager: Cocoapods
  • Swift Version : 5.2
  • Xcode Version: 11.4

Device Information (please complete the following information):

  • All devices/simulators

Relevant Console Output

LOG OUTPUT FROM 1st APP RUN

2020-05-20 10:17:58:261 APPNAME[4274:2759335] Configuring SignInProvider : CognitoUserPool.
2020-05-20 10:17:58:262 APPNAME[4274:2759335] Registering SignInProvider AWSCognitoUserPoolsSignInProvider from awsconfiguration.json.
2020-05-20 10:18:13.785914-0500 APPNAME[4274:2759553] Attempting signIn with email and dummyPassword
2020-05-20 10:18:13:863 APPNAME[4274:2759335] Request headers:
{
    "Content-Type" = "application/x-amz-json-1.1";
    Host = "cognito-idp.us-east-1.amazonaws.com";
    "User-Agent" = "aws-sdk-iOS/2.13.1 iOS/13.4.1 en_US";
    "X-Amz-Date" = 20200520T151813Z;
    "X-Amz-Target" = "AWSCognitoIdentityProviderService.InitiateAuth";
}
2020-05-20 10:18:13:863 APPNAME[4274:2759335] Request body:
{"UserContextData":{"EncodedData":"eyJwYXlsb2FkIjoie1widXNlcm5hbWVcIjpcInN0ZXBoZW4uci5ncmF5KzI1QGdtYWlsLmNvbVwiLFwiY29udGV4dERhdGFcIjp7XCJDYXJyaWVyXCI6XCJBVCZUXCIsXCJBcHBsaWNhdGlvblZlcnNpb25cIjpcIjAuMS4wLTM2XCIsXCJIYXNTaW1DYXJkXCI6XCJ0cnVlXCIsXCJQaG9uZVR5cGVcIjpcImlQaG9uZTEyLDNcIixcIkRldmljZUlkXCI6XCIxOTcyZThmNi00OThjLTQ5NzAtOTEzNy1lMGMyNGJkZWNmMzhcIixcIk5ldHdvcmtUeXBlXCI6XCJDVFJhZGlvQWNjZXNzVGVjaG5vbG9neUxURVwiLFwiU2NyZWVuV2lkdGhQaXhlbHNcIjpcIjExMjVcIixcIlBsYXRmb3JtXCI6XCJpT1NcIixcIlNjcmVlbkhlaWdodFBpeGVsc1wiOlwiMjQzNlwiLFwiQXBwbGljYXRpb25UYXJnZXRTZGtcIjpcIjgwMDAwXCIsXCJBcHBsaWNhdGlvbk5hbWVcIjpcImNvbS5jcm93ZG5vaXNlLkNyb3dkTm9pc2VNb2JpbGVcIixcIkRldmljZU9zUmVsZWFzZVZlcnNpb25cIjpcIjEzLjQuMVwiLFwiRGV2aWNlRmluZ2VycHJpbnRcIjpcIkFwcGxlXFxcL2lQaG9uZVxcXC9pUGhvbmUxMiwzXFxcLy06MTMuNC4xXFxcLy1cXFwvLTotXFxcL2RlYnVnXCIsXCJUaGlyZFBhcnR5RGV2aWNlSWRcIjpcIjg1RDEzMzJELUEwNzctNDQ3My1BRkNBLTA3OUNFQzMwRTFCNVwiLFwiRGV2aWNlTGFuZ3VhZ2VcIjpcImVuLVVTXCIsXCJDbGllbnRUaW1lem9uZVwiOlwiLTA1OjAwXCIsXCJCdWlsZFR5cGVcIjpcImRlYnVnXCIsXCJEZXZpY2VOYW1lXCI6XCJTdGVwaGVuJ3MgaVBob25lIDExIFByb1wifSxcInVzZXJQb29sSWRcIjpcInVzLWVhc3QtMV9salVJM0w5NWlcIixcInRpbWVzdGFtcFwiOlwiMTU4OTk4Nzg5Mzg1NFwifSIsInZlcnNpb24iOiJJT1MyMDE3MTExNCIsInNpZ25hdHVyZSI6IndMclNVNGR4a2FvZFA3QSt3R21hY2VhN1dlUk1Lclg3TG9KXC81UU4wOWZvPSJ9"},"ClientMetadata":{"cognito:deviceName":"iPhone 11 Pro","cognito:bundleShortV":"0.1.0","cognito:idForVendor":"85D1332D-A077-4473-AFCA-079CEC30E1B5","cognito:bundleVersion":"36","cognito:bundleId":"com.APPNAME.APPNAMEMobile","cognito:model":"iPhone","cognito:systemName":"iOS","cognito:iOSVersion":"13.4.1"},"AuthParameters":{"SRP_A":"8b63f28694412c040b429517fe6566552ac3ba1fd984da59a4b0f9d87622cd208019268d92cc9c57306555959704bfcc8a8f603caaaf31dd9d3c3276f7979a0e70b5c74a5ed90061923dee9006d2c56065a5510823e2a1e9e6f50f01e2283ad44de124b91e5a2ee51968e0ef63b146c66ea92e105a3b012aab29820cec77be72af5d889c9ea7a8838ee34df83adea053d586fcd9f14cf91c51717cbb2b1c2177029799c83caf0a552c89518ae110892793fea717f61ecba87d7a3a3c0282ad10b8519dd08b9afc643df6b4419ff3738156e48d820e1785e1a29debb9d1038bb5cfcac7928605e19edade1222e2d731b8fb4733ca0009b56249519a6e68d6708a0e0feb4e9892b08222e36d6c8526926ce51df3e277d1f0054c0bd83307973e7d01c9a8a73ff47bba57ad6675fb3250e3558beeb66940cf213b9869bb8c5b7e26d62311e0d1652af0cd70c3e5812dfd4ab95f5969b7d5e64b66b6a35d9a31a696cf9bc8d44f76cc34b0a9586d048ac2714471884df08470fc429230467dac4786","CHALLENGE_NAME":"SRP_A","USERNAME":"<redactedEmailAddress>"},"AuthFlow":"CUSTOM_AUTH","ClientId":"<redacted>"}
2020-05-20 10:18:15:036 APPNAME[4274:2759547] Response headers:
{
    "Content-Length" = 1383;
    "Content-Type" = "application/x-amz-json-1.1";
    Date = "Wed, 20 May 2020 15:18:14 GMT";
    "x-amzn-requestid" = "f7e4e7dd-cc9e-42f3-901e-e48b64d77a89";
}
2020-05-20 10:18:15:036 APPNAME[4274:2759547] Response body:
{"ChallengeName":"CUSTOM_CHALLENGE","ChallengeParameters":{"USERNAME":"255c05e6-1d98-48dc-8c07-510dc6ac70aa","email":"<redactedEmailAddress>"},"Session":"R9gJToJufqLzsZJVdZhJbUV7Jt4Reb5USC5qTJFD8NmE4B4HcR75Qel60DrSpfD4fqqjKYhvorxXZtySE8QJDPvZ3Kb1PGv0oNR_pkUmBtg5-eMtm0jgcKhCG9WvAvb3Brg3gz4bqRv1ZMnnlPdGWq6UJgoRPPJY6bwxbNd4BYl2e7O2WU9sCN20A13tiDwhE4ndBkNqYaR1eeissfOANJLoAlMbNJsiuP2wTFRnrfqtH11LDfSB-zZCkbieHmWLDYTU7Y6Ap1iNQfRg6apkjT6-pBgBlPeyoBQUxOou-xDI1u1H-6WyXaUd83eT20sEZRJtOR_aP5Ki_nnwgXeZdWbgxhwZp2XyTN1S6W3oDguQFpskpRHhAkYrfelFU5LtM0MRRgCthvU92qII0fmclDkqjgUyyEod6eJXjxy9fioOv-BvlOSfPwGWyPPjGL8o0s9tNkgNyzVhyc9QZ2yOaW9g3-SNZBTtNvnn60HbKH58nvlGhXnw306GVHiZsOyc2u59t4xCs91eIJky_XFg_-3xNwlqD_UPJwFGeXirSB_oR20zwOHdiacIbYjToFsl-14UFAUdxv70rrZ97_iPb4ZSCcY8CzkuZSL4ZFvtjl7_lN93YZqT3qyra_pMK5nI2YcIOIxYqn91Dga_I8QAhGO22XH2aWNkXCtNRVBrJdF1WMePay2Jq9Wb8WtjzHUnd7Hvy4RxoVISkin0Novdm4w9vCspdentRe-eBArxEkd2veJHlUpH9lnFWUG4YWbLi-1lKdQOi4VQEJsoSYq_pbd4cno4MXHc8FiNUUcOqXLwbT9IMcn98V_zGT-bznfxrNn_sY9AgEoLR7AMEx-wKwPj_EAR6PVZsdo4egV_vBiXs5bNJx22e-4rHzsWVEA5k6XrVCZ00t7kKBw0uWxmvWnpz6iltWimlRm6XaUOEom4pCExtVIfS6HY7FEsVct5gE3ughz4ssXQ5SAEqAyNC5f0sTRhcTtOji8FfU3gvkXl600X0TFMxluduGini_dGmFA9Zd5haWxE8PPNWToMhKxyUmeNZwAV6w8OHFP2-6oeAEE1bdb4V_0GnilRpizI8yumTN1bNyZds0oyKo68DILmTjPoi10v2pyH4COaavbQv-aoP2cWzF8JjaBbxkFb3MkQxqrAYWHa_7QnP6ltCR-ehN1PurGY6knmX-AiaryD_feCStU0nB73SeOwJ_xbKJJLng"}
2020-05-20 10:18:15.039986-0500 APPNAME[4274:2759553] AWS responded with signInState: customChallenge

LOG OUTPUT FROM 2nd APP RUN

2020-05-20 10:18:28:814 APPNAME[4277:2760029] Configuring SignInProvider : CognitoUserPool.
2020-05-20 10:18:28:815 APPNAME[4277:2760029] Registering SignInProvider AWSCognitoUserPoolsSignInProvider from awsconfiguration.json.
2020-05-20 10:18:39.340814-0500 APPNAME[4277:2760064] Attempting confirmSignIn with challengeCode
2020-05-20 10:18:39.341572-0500 APPNAME[4277:2760066] Please call `signIn` before calling this method.
2020-05-20 10:18:39.347165-0500 APPNAME[4277:2760067] APPNAMEKit.AWSSignInError(0)
cognito feature request pending triage

All 6 comments

Hey @srgray

Thanks for reaching out. At the moment, I believe that we do not plan to support this use case for our authentication flows.

As a user of a native iOS application, if the app crashes between entering my credentials and a custom auth challenge I would expect that when I re-launch the application that I would have to re-enter my credentials. Right?

Similarly, I would expect this behavior if I were attempting to log into a website via a browser which required 2FA, right?

Yes, I understand your reasoning.
Here's a little more detail about our setup:
We use a Lambda flow similar to: https://aws.amazon.com/blogs/mobile/implementing-passwordless-email-authentication-with-amazon-cognito/ to implement custom auth.
When user requests this 'magic link email' in mobile app (the first step in custom auth, where I use AWSMobileClient.signIn(username, "dummyPassword), that triggers our Lambda backend to send an email to the user that contains a direct link back into the app. That direct link has the challenge code embedded so that the app can extract it and complete the auth challenge without user interaction.
So, in this use case, it's a nice feature to have the user be able to tap on that link and complete custom auth automatically, even if the app has restart since the custom auth process was begun.

Thank you so much for taking the time to explain to us your use case!  I now understand why you’d want such a feature, and it makes sense, but in talking with the team, I don’t expect us to pick up this feature any time soon for AWSMobileClient, if ever.

As a workaround, we brainstormed around how you’d be able to work around this.

To summarize your system design for Custom Auth (and please correct me if I’m wrong):

  1. App has text field for the customer’s email and “sign-in” button.  Upon tapping the sign in button, the app calls AWSMobileClient.signin(), which under the hood, makes a network request to Cognito’s initiateAuth() API - https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_InitiateAuth.html
  2. As a result, because we are using custom auth, the Lambda function gets executed, and issues an email to the customer’s email address
  3. Customer receives the email, and taps on the “magic link", which then opens the mobile application
  4. Mobile application parses the payload from the link in order to call confirmSignIn() with the parsed parameters

The problem occurs because in Step 4, the app may have been backgrounded too long, or the app crashes, etc..

So, as a work around, in Step 4, AFTER parsing the payload, we could:

  1.  Force AWSMobileClient to reset its state, possibly by calling sign out (in the event that the app is ready to call confirmSignIn).  Haven’t personally confirmed this, but seems like this should work?
  2. Call signin()/initiateAuth but pass in some a flag/value/etc in the clientMetaData field (see link above to initiateAuth API specs) to include some data so that the custom Lambda does not send out a “magic link” to the customer (as well as prevents a generation of a new "code" or auth challenege)
    Note that with AWSMobileClient, you can pass data into the clientMetaData field using the validationData parameter. You can use the following AWSMobileClient api:
public func signIn(username: String,
                   password: String,
                   validationData: [String: String]? = nil,
                   completionHandler: @escaping ((SignInResult?, Error?) -> Void))
  1. Wait for signin/initiateAuth to successfully complete, and then call confirmSignIn with the parsed parameters from the original “magic link”.

I think this approach will work, and best of luck! Let us know how it goes!

Thanks again!

Thank you for the suggested workaround. We are going to try this out and I will report back.

@srgray did any of the workarounds work?

We weren't able to get this workaround working. The main issue is that we couldn't get AWS Cognito backend to make the connection between the first and second calls to signIn/initiateAuth, probably due to the stateless nature of Cognito/Lambda. So, the second call to signIn (even though we provide a flag that indicates it's the second call), is basically handled as a new session and cannot make the connection to the original request/confirmation code.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

aymericio picture aymericio  Â·  5Comments

mohab2014 picture mohab2014  Â·  4Comments

r-plus picture r-plus  Â·  3Comments

premiumbosslimited picture premiumbosslimited  Â·  3Comments

aTylerRice picture aTylerRice  Â·  3Comments