Amplify-ios: Developers want to reconfigure Amplify at runtime

Created on 5 Jun 2020  路  8Comments  路  Source: aws-amplify/amplify-ios

Is your feature request related to a problem? Please describe.
A customer is developing an app using TWO Cognito User Pools.
Customer develops a web app, an Android app and an iOS App.

On their web app, they are able to call Amplify.configure(configuration); with one config (Cognito User Pool) or the other, depending on the URL of the app being used.

But on Mobile, it seems that once configured, they can not switch to another configuration by calling Amplify.configure(configuration); a second time.

There is a global configuration lock defined here https://github.com/aws-amplify/amplify-ios/blob/master/Amplify/Amplify.swift#L23

and used here https://github.com/aws-amplify/amplify-ios/blob/master/Amplify/Core/Configuration/AmplifyConfiguration.swift#L88

Describe the solution you'd like
Developers would like to be able to reconfigure Amplify at runtime

Describe alternatives you've considered
A clear and concise description of any alternative solutions or features you've considered.

Additional context
I also raised an issues against amplify-android : https://github.com/aws-amplify/amplify-android/issues/560

core feature request

Most helpful comment

Hi, @drochetti !

My team has a similar problem: I have multiple user pools on the backend, and we determine the user's pool by username before the login. That's why I need to be able to reconfigure the Amplify SDK in runtime.

I've seen you did a great job adding the ability to configure the Amplify with file or config structure in runtime. But, unfortunately, this does not fully satisfy our needs: we also need to be able to reset the Amplify stack in runtime.

Why? Imagine, we have two users, user A and user B. User A is in pool A, user B is in pool B. User A tries signs in, then we configure Amplify to use Pool A and perform sign in. Then user A signs out, and user B tries to sign in. At this point we need to reconfigure Amplify to switch to the user pool B.

How? I found out you also did a great job writing Amplify+Reset extension, having wonderful static func reset(), which seems to be doing the job I need. The problem is, this reset() function is marked as internal, so I can't use it.

We really want to use Amplify SDK as it might save us a lot of time with its DataStore, but due to this problem we are considering using just AWS iOS SDK instead and to that job manually.

All 8 comments

Hi @sebsto,

Thanks for requesting this. We are currently tracking a feature where developers could have different configurations per environment, but being able to reconfigure in runtime is something that we don't intend to support at this moment.

with one config (Cognito User Pool) or the other, depending on the URL of the app being used

That is something that could be supported, by allowing multiple configuration files, like we intend to (one config per environment for example).

But on Mobile, it seems that once configured, they can not switch to another configuration by calling Amplify.configure(configuration); a second time.

And that's expected. We don't intend to allow things to be reconfigured once Amplify.configure() is called. The side-effects of such call are very hard to foresee. There are security and data privacy concerns involved (e.g. you restart DataStore pointing to another database). I would analyze the use case to check if there are alternatives to achieve the same without reconfiguring Amplify.

For instance, could the app be restarted for different URLs? What's the use case?

@drochetti Thank you for the info, I need to do the exact same thing. In my iOS app, I want to give users the option to switch between different backend endpoints, each of which uses a separate Cognito User Pool. Signing in with Cognito is the only feature of Amplify that I use in my app. So my questions are:

  1. Could I accomplish what I want if I only used AWSMobileClient directly, without Amplify? If so, how?
  2. Could I configure the Cognito User Pool directly in code, without the need for a JSON config file (or several config files, one for each user pool)?

Thanks!

Similar problem here. We use a multi-tenant architecture with a Cognito User Pool per tenant but with the current state of the SDK, it's not possible to switch between tenants without an app reset. Is there a workaround for this issue while maintaining a multiple user pool architecture?

Thanks in advance

Hi @jfahrenkrug and @andrebsampaio, unfortunately switching a Cognito User Pool, or any other backend configuration, while the app is running is not currently supported.

Could I accomplish what I want if I only used AWSMobileClient directly, without Amplify? If so, how?

Even using AWSMobileClient directly would not give you the capability you're looking for. The shared instance AWSMobileClient.default is used in different parts of the codebase. You can only switch the configuration if you restart your app.

Could I configure the Cognito User Pool directly in code, without the need for a JSON config file (or several config files, one for each user pool)?

Still not possible. The limitation is not on how the configuration is passed/consumed but how the entire security model is handled by the SDK. Switching configuration in runtime is very tricky and might have other implications such as stale tokens, user sensitive data saved locally, existing processes in process (e.g. file upload) that linked to a specific user pool, etc

Are you trying to accomplish that in a production environment or, like I've seen before, in a scenario where you want to switch between development environments within the app?

Hi @drochetti,

Thanks so much for your feedback. To answer your question: This is not for production, but to enable a Test Flight version of an iOS app to switch between dev, staging, and production environments. I'm solving it now by displaying a message to the user that they have to force-quit and restart the app for the change to take effect. It's ugly, but since it's just a small group of tech-savvy testers it works.

Another thing about using code to configure the instance instead of a JSON file: I'd be interested in being able to do that even if that doesn't help me with switching environments at runtime. I'd just prefer to not have to depend on another file in the bundle when I can just supply those values in code.

Thank you!

Johannes

Hey @jfahrenkrug, so for your case the solution you have, although not pretty, is the only one that can guarantee your testers will have a fresh environment. Even without Amplify, I had to rely on a similar approach before since refreshing cloud provisioned resources in runtime is very tricky and failure-prone and often _unsafe_, that's why I asked about production.

Another thing about using code to configure the instance instead of a JSON file: I'd be interested in being able to do that even if that doesn't help me with switching environments at runtime. I'd just prefer to not have to depend on another file in the bundle when I can just supply those values in code.

Good news then, the Amplify.configure(configurationFile:) is available since Amplify 1.1.0.

Hi, @drochetti !

My team has a similar problem: I have multiple user pools on the backend, and we determine the user's pool by username before the login. That's why I need to be able to reconfigure the Amplify SDK in runtime.

I've seen you did a great job adding the ability to configure the Amplify with file or config structure in runtime. But, unfortunately, this does not fully satisfy our needs: we also need to be able to reset the Amplify stack in runtime.

Why? Imagine, we have two users, user A and user B. User A is in pool A, user B is in pool B. User A tries signs in, then we configure Amplify to use Pool A and perform sign in. Then user A signs out, and user B tries to sign in. At this point we need to reconfigure Amplify to switch to the user pool B.

How? I found out you also did a great job writing Amplify+Reset extension, having wonderful static func reset(), which seems to be doing the job I need. The problem is, this reset() function is marked as internal, so I can't use it.

We really want to use Amplify SDK as it might save us a lot of time with its DataStore, but due to this problem we are considering using just AWS iOS SDK instead and to that job manually.

I'm wondering if this functionality could be achieved with a similar implementation design to Selective Sync. The idea being that you still only configure Amplify once, but have the ability to switch user pools with a function like Auth.stop() and then calling Auth.start().

An example call API design might look something like this 馃憞馃徑

func initialize() {
    try Amplify.add(plugin: AWSCognitoAuthPlugin(
        configuration: .custom(
            poolId: isProduction
                ? prodPoolId
                : devPoolId
        )
    )
    try Amplify.configure()
}

func changePool() {
    isProduction.toggle()
    Amplify.Auth.stop { (result) in
        switch(result) {
        case .success:
            Amplify.Auth.start { (result) in
                switch(result) {
                case .success:
                    print("Auth started")
                case .failure(let error):
                    print("Error starting Auth:\(error)")
                }
            }
        case .failure(let error):
            print("Error stopping Auth:\(error)")
        }
    }      
}
Was this page helpful?
0 / 5 - 0 ratings