| | | | |

Load Amplify configuration at Runtime – Dynamic AWS Cognito Configuration in Android

Load amplify configuration at runtime

Most of the Amplify configuration documentations won’t tell how to load the full amplify configuration json dynamically, there might be many solutions and here I have one. This will help you load values dynamically at runtime, like, Pool IDs, client secrets, domains etc.

It’s obvious that the json file should not be visible publicly, if not you are risking security. We can use Gradle and runtime environment to assemble the JSON as when required.

1. Move cognito key and values to properties

This is ideal place since by default this file is not part of version control and it only contains SDK directory.
So first thing you need to do is gather all your attributes/values which you want to load dynamically or at runtime from your amplify configuration file.

Let’s say you want you load these 3 values dynamically:

"CognitoUserPool": {
    "Default": {
        "PoolId": "YOUR_POOL_ID",
        "AppClientId": "YOUR_APP_CLIENT_ID",
        "Region": "YOUR_REGION"
     }
},

You need to move them to your local.properties file.

sdk.dir=C\:\\Users\\name\\AppData\\Local\\Android\\Sdk

# Apmlify configuration keys
COGNITO_POOL_ID=YOUR_POOL_ID
COGNITO_APP_CLIENT_ID=YOUR_APP_CLIENT_ID
COGNITO_REGION=YOUR_REGION

Sync the project, now let’s work on build configuration to access those values.

2. Provide fields to BuildConfig

We need to get those properties from local file and provide it to build, we will write this configuration in your app module’s build.gradle.kts file.

import java.util.Properties

android {
    defaultConfig {
        val properties = Properties().apply {
            val file = rootProject.file("local.properties")
            if (file.exists()) {
                file.inputStream().use { load(it) }
            }
        }
    }
}

This above variable properties holds all the values from local.properties file.
Now we need to add fields using buildConfigField, so that they will be generated to access from BuildConfig.

In same defaultConfig block, add them after properties variable.

buildConfigField(
    type = "String",
    name = "COGNITO_POOL_ID",
    value = "\"${properties.getProperty("COGNITO_POOL_ID", "")}\""
)

buildConfigField(
    type = "String",
    name = "COGNITO_APP_CLIENT_ID",
    value = "\"${properties.getProperty("COGNITO_APP_CLIENT_ID", "")}\""
)

buildConfigField(
    type = "String",
    name = "COGNITO_REGION",
    value = "\"${properties.getProperty("COGNITO_REGION", "")}\""
)

I have provided 3 as mentioned above, you can add as many you can based on your configuration requirements.

I have kept it simple by giving name and value with same attribute name which matches the key provided in local properties file.

Now sync the project, search and navigate to your BuildConfig.java file which is build generated. You should find your keys/values there. We will use them.

3. Configure the Amplify JSON at Runtime

With those values from BuildConfig available, we can now build exactly the JSON amplify configuration file.

We no more need to have a static configuration file, delete it and load json string as below, I have moved it inside an object AmplifyConfigProvider to keep it simple.

Key part here is, you can access those cognito values from BuildConfig as shown below.

import com.amplifyframework.core.AmplifyConfiguration
import org.json.JSONObject

object AmplifyConfigProvider {
    private val json = """
{
  "auth": {
    "plugins": {
      "awsCognitoAuthPlugin": {
        "CognitoUserPool": {
          "Default": {
            "PoolId": "${BuildConfig.COGNITO_POOL_ID}",
            "AppClientId": "${BuildConfig.COGNITO_APP_CLIENT_ID}",
            "Region": "${BuildConfig.COGNITO_REGION}"
          }
        },
        "Auth": { }
      }
    }
  }
}
    """.trimIndent()

    val config = AmplifyConfiguration.fromJson(JSONObject(json))
}

This code takes care of constructing the configuration from raw json.

val config = AmplifyConfiguration.fromJson(JSONObject(json))

In your Application or where ever your Plugin configuration is located, replace the static amplifyconfiguration.json as below.

class ComposeActorsApp : Application() {
  override fun onCreate() {
    super.onCreate()

    try {
      Amplify.addPlugin(AWSCognitoAuthPlugin())
      Amplify.configure(AmplifyConfigProvider.config, applicationContext)
    } catch (e: Exception) {
      throw e
    }
  }
}

At this point we have configured everything, check the setup by running the application and try to login.

4. Supporting integration in actions workflow

Example – GitHub Actions:

In your repository settings, navigate to Actions in Secrets and variables and create entries for keys as required.
In your workflow file, in environment section provide those matching attributes and values:

env:
  COGNITO_POOL_ID: ${{ secrets.COGNITO_POOL_ID }}
  COGNITO_APP_CLIENT_ID: ${{ secrets.COGNITO_APP_CLIENT_ID }}
  COGNITO_REGION: ${{ secrets.COGNITO_REGION }}

    5. Guarding for values not provided

    Validate for no empty values in properties file, this will help us by letting us know when cognito values are not provided in local properties file. Gradle will warn us by throwing an Error.

    if (properties.getProperty("COGNITO_POOL_ID").isEmpty()) {
        error("COGNITO_POOL_ID not set in local.properties")
    }

    You can extract all those checks and validation to a new function and call them in defaultConfig block to keep it clean. If the values are missing, build will fail with Exception as below :

    * Exception is:
    java.lang.IllegalStateException: COGNITO_POOL_ID not set in local.properties

    That is all!

    Reference : Project with working examples

    Author

    Similar Posts

    Leave a Reply

    This site uses Akismet to reduce spam. Learn how your comment data is processed.