AWS IoT Android application over MQTT throws MqttException (0) - java.io.IOException: Already connected

I beat my head up with this almost a week.

Full course of action -> After succesfull login you will have a jwt token

String idToken = cognitoUserSession.getIdToken().getJWTToken();

put it into a map

Map<String, String> logins = new HashMap<String, String>(); 
//fill it with Cognito User token
logins.put("cognito-idp.<REGION>.amazonaws.com/<COGNITO_USER_POOL_ID>", idToken);

then use it to set in two places (not stated in any documentation!)

CognitoCachingCredentialsProvider credentialsProvider = new 
CognitoCachingCredentialsProvider(context, IDENTITY_POOL_ID, REGION);
credentialsProvider.setLogins(logins);

and

AmazonCognitoIdentity cognitoIdentity = new AmazonCognitoIdentityClient(credentialsProvider);
GetIdRequest getIdReq = new GetIdRequest();
getIdReq.setLogins(logins); //or if you have already set provider logins just use credentialsProvider.getLogins()
getIdReq.setIdentityPoolId(COGNITO_POOL_ID);
GetIdResult getIdRes = cognitoIdentity.getId(getIdReq);

after that you still nedd to make some call

AttachPrincipalPolicyRequest attachPolicyReq = new AttachPrincipalPolicyRequest(); //in docs it called AttachPolicyRequest but it`s wrong
attachPolicyReq.setPolicyName("allAllowed"); //name of your IOTAWS policy
attachPolicyReq.setPrincipal(getIdRes.getIdentityId());
new AWSIotClient(credentialsProvider).attachPrincipalPolicy(attachPolicyReq);

and only after that you can enable connect button and continue like that

mqttManager.connect(credentialsProvider, new AWSIotMqttClientStatusCallback() {

Really for this small piece of code i spent a lot of time...


I was also getting same error -

Feb 27, 2019 10:23:09 AM com.amazonaws.services.iot.client.mqtt.AwsIotMqttConnectionListener onFailure
WARNING: Connect request failure
MqttException (0) - java.io.IOException: Already connected
    at org.eclipse.paho.client.mqttv3.internal.ExceptionHelper.createMqttException(ExceptionHelper.java:38)
    at org.eclipse.paho.client.mqttv3.internal.ClientComms$ConnectBG.run(ClientComms.java:664)
    at java.lang.Thread.run(Thread.java:748)
Caused by: java.io.IOException: Already connected
    at java.io.PipedOutputStream.connect(PipedOutputStream.java:100)

but the problem was different.

First of all, you do not need to call attachPrincipalPolicy from code. You can use the command line as well. You can do something like -

aws iot attach-principal-policy --principal us-east-1:1c973d17-98e6-4df6-86bf-d5cedc1fbc0d --policy-name "thingpolicy" --region us-east-1 --profile osfg

You will get the principal ID from identity browser of your identity pool. Now lets come to the error -

To successfully connect to mqtt with authenticated Cognito credentials, you need 2 correct policies -

  1. Authenticated role corresponding to your identity pool should allow all mqtt operations.
  2. AWS IoT policy should allow the same operations and you need to associate your cognito identity with this policy. We use attachPrincipalPolicy to do so.

If anyone step is missed we get above error. I agree the error is misleading - Already connected makes no sense to me for this. I would normally think it has to do with clientId, which should be unique. But anyways hopefully AWS folks would make this better at some point.

For my particular case issue was point 1. Though my IoT policy had all the required permissions, the auth role corresponding to the identity pool did not. So make sure you do that.

I have created a youtube video to show this as well: https://www.youtube.com/watch?v=j2KJVHGHaFc