State your question
Recently, I've spent some time to figure out why first ddb query in my app is very slow. It turned out to be because I was passing AWSMobileClient.getInstance() as a credentials provider to AmazonDynamoDBClient, and its getCredentials() implementation always makes network calls instead of using cached offline credentials. When I switched to using CognitoCachingCredentialsProvider, that problem was solved.
Unfortunately, in a comment for AmazonDynamoDBClient constructor, it says:
* If AWS session credentials are passed in, then those credentials will be
* used to authenticate requests. Otherwise, if AWS long-term credentials
* are passed in, then session management will be handled automatically by
* the SDK. Callers are encouraged to use long-term credentials and let the
* SDK handle starting and renewing sessions.
* Automatically managed sessions will be shared among all clients that use
* the same credentials and service endpoint. To opt out of this behavior,
* explicitly provide an instance of AWSCredentialsProvider that
* returns AWSSessionCredentials.
So I was wandering, since CognitoCachingCredentialsProvider returns AWSSessionCredentials, does that mean it is not recommended to use it? Which credentials provider should we use to create clients (AmazonDynamoDBClient, AmazonS3Client,..)?
Which AWS Services are you utilizing?
AWS Cognito, S3, DynamoDB
Provide code snippets (if applicable)
This is what I used to create AmazonDynamoDBClient and AmazonS3Client:
AmazonDynamoDBClient dynamoDBClient = new AmazonDynamoDBClient(AWSMobileClient.getInstance());
AmazonS3Client amazonS3Client = new AmazonS3Client(AWSMobileClient.getInstance(), Region.getRegion(Regions.US_EAST_1));
This is what I now use:
CognitoCachingCredentialsProvider ccp = new CognitoCachingCredentialsProvider(context, AWSMobileClient.getInstance().getConfiguration());
AmazonDynamoDBClient dynamoDBClient = new AmazonDynamoDBClient(ccp);
AmazonS3Client amazonS3Client = new AmazonS3Client(ccp, Region.getRegion(Regions.US_EAST_1));
Environment(please complete the following information):
Device Information (please complete the following information):
@markorakita Sorry for the delayed response. AWSMobileClient creates a CognitoCachingCredentialsProvider when there is an entry for the CredentialsProvider section in the awsconfiguration.json file.
Did you verify subsequent calls to getCredentials() within the expiration time (default is 1 hour) window makes network call?
@kvasukib Thanks for your response. So you are saying that if there is an entry for CredentialsProvider section in the awsconfiguration.json file, we can pass AWSMobileClient.getInstance() as a credentials provider to AmazonDynamoDBClient and AmazonS3Client constructors, and it will use CognitoCashinCredentialsProvider in the background for getCredentials() calls?
I don't see this happening in the aws sdk codebase. As I can see, AWSMobileClient implements the AWSCredentialsProvider interface and has its own getCredentials() method, which always makes network calls since it calls waitForSignIn() function which calls getUserStateDetails(false) function, where false means "don't use cashed offline credentials".
Only if AWSMobileClient is initialized using deprecated initialize() function, then it might use some other credentials provider:
if (isLegacyMode()) {
return IdentityManager.getDefaultIdentityManager().getCredentialsProvider().getCredentials();
}
Did you verify subsequent calls to getCredentials() within the expiration time (default is 1 hour) window makes network call?
I haven't checked multiple calls within same session, but every time my app was started and made some call to DynamoDB it always resulted in waiting for getCredentials(). And yes it was within 1 hour period.
Hi @markorakita ,
which calls getUserStateDetails(false) function, where false means "don't use cashed offline credentials".
The false that you are referring to actually does something different. It flips between forcing an online check as seen here.
When false (make network calls if necessary), it checks with the underlying CognitoCachingCredentialsProvider client for valid tokens which reads from cache first, otherwise does a network-based refresh or sign-in.
When true (under no condition make network calls), it checks for the presence of tokens for whether you are signed-in.
does that mean it is not recommended to use it
No, the documentation is misleading and we are updating it.
my app is very slow. It turned out to be because I was passing AWSMobileClient.getInstance() as a credentials provider to AmazonDynamoDBClient, and its getCredentials() implementation always makes network calls instead of using cached offline credentials
I will run some benchmarks to see what the issue is here.
We will update this once we have completed the following action items:
@minbi Today I encountered another issue with using AWSMobileClient.getInstance() as a credentials provider.
If you create a table in DynamoDB and you want to set fine grained policy to allow users to query only fields in the table that they added, you have to create a table with primary key being UserID. I tried setting user sub as UserID since policy has a condition:
"Condition": {
"ForAllValues:StringEquals": {
"dynamodb:LeadingKeys": [
"${cognito-identity.amazonaws.com:sub}"
]
}
}
But that doesn't work. Only UserId that works is _credentialsProvider.getCachedIdentityId()_ like in this tutorial: https://aws.amazon.com/blogs/mobile/using-amazon-dynamodb-document-api-with-the-aws-mobile-sdk-for-android-part-2/
That means that you have to have CognitoCachingCredentialsProvider instance to be able to acess getCachedIdentityId() function, and there is no way to do that from AWSMobileClient.getInstance().
EDIT: Just realized there is a getIdentityId() function inside AWSMobileClient.
@markorakita Yes, you're right. You could do AWSMobileClient.getInstance().getIdentityId() to retrieve the Cognito Identity ID and use it in your app. Please let us know if you have any other questions.
@minbi Hi, have you had a chance to run the benchmarks yet?