How Can I Get AWS Cognito Login/logout To Work Properly With AWS API Gateway On Android?
I'm writing a simple Android app that currently offers the following features:
- Register/login with email and password, against an AWS Cognito back end
- Logout (against the same Cognito back end)
- Call a protected web API on AWS API Gateway
I'm building my own very simple login/logout UI, rather than using the AWS Cognito UI library:
Login screen (left); logged-in screen (right)
The web API should return 200 (and a body) when the user is logged in, and a 403 error when they are logged out. The server setup all appears to be correct, and an equivalent app on iOS is working as described.
The problem on Android is as follows:
- When I start the app, don't log in, and call the API: I get a 403 error (expected).
- When I log in and call the API again: I still get a 403 error (unexpected).
- When I close the app, swipe it from the recent apps list, and re-open it: I'm still logged in (expected)
- Now when I call the API: I get a 200 response (expected).
The same happens now if I log out: I still get a 200 response after logging out until I kill the app and restart it.
How can I get the API Gateway call to respect my current authentication state immediately, without recycling the app?
I wondered if the AWS API Gateway Android library might be to blame, so I've tried an alternative implementation using OkHttp but I get exactly the same result. I've based my Cognito code on the AmazonCognitoYourUserPools demo.
Here's the part of my build.gradle that imports the AWS libraries:
// AWS Mobile Client
implementation('com.amazonaws:aws-android-sdk-mobile-client:[email protected]') { transitive = true }
// Cognito UserPools for SignIn
implementation 'com.android.support:support-v4:27.1.1'
implementation('com.amazonaws:aws-android-sdk-auth-userpools:[email protected]') { transitive = true }
// AWS API gateway
implementation 'com.amazonaws:aws-android-sdk-apigateway-core:2.6.18'
It probably won't help to paste large amounts of code here, but I've created gists for the main classes involved (with logging etc. removed to keep them as small and relevant as possible):
The AwsInterceptor
class referenced in ApiCaller.java
came from here.
Answer
The solution my colleague and I have arrived at is as follows:
Login
After login, you need to re-initialise the AWSMobileClient
before you call any API Gateway endpoints. Here's a snippet from my AuthenticationHandler
in LoginActivity.java
:
private AuthenticationHandler authenticationHandler = new AuthenticationHandler()
{
@Override
public void onSuccess(final CognitoUserSession userSession,
final CognitoDevice newDevice)
{
// Initialise the client again
AWSMobileClient.getInstance().initialize(LoginActivity.this, new AWSStartupHandler()
{
@Override
public void onComplete(final AWSStartupResult awsStartupResult)
{
switchTo(LoggedInActivity.class);
}
}).execute();
}
// ...
}
Logout
After logout, we found we needed to clear the credentials from the IdentityManager
. This snippet is from my LoggedInActivity.java
:
private void logout()
{
final CognitoUser currentUser = getCurrentUser();
currentUser.signOut();
// Clear the IdentityManager credentials
final IdentityManager idm = new IdentityManager(this, new AWSConfiguration(this));
IdentityManager.setDefaultIdentityManager(idm);
idm.getUnderlyingProvider().clearCredentials();
idm.getUnderlyingProvider().clear();
idm.getUnderlyingProvider().setLogins(null);
switchTo(LoginActivity.class);
}
Related Questions
- → should I choose reactjs+f7 or f7+vue.js?
- → Phonegap Android write to sd card
- → Local reference jquery script in nanohttpd (Android)
- → Click to navigate on mobile devices
- → How to allow api access to android or ios app only(laravel)?
- → Access the Camera and CameraRoll on Android using React Native?
- → React native change listening port
- → What is the default unit of style in React Native?
- → Google play market autocomplete icon
- → Warning: Each child in an array or iterator should have a unique "key" prop. Check the render method of `ListView`
- → Using Laravel with Genymotion
- → react native using like web-based ajax function
- → react native pdf View