aws-sdk-js: Forbidden error: iotdata.getThingShadow with cognito credentials

I’m using AWS Cognito to manage the authentication and authorization in the app. I have created a user pool and one identity pool which is federated with the cognito user pool.

User logs-in with the credentials. I authenticate the user against the user pool and then exchange the returned id token with Cognito Identity to get temporary aws credentials, which can be used to connect to other aws resource, in my case aws resource is aws iot.

There are two aws iot modules in sdk:

  1. AWS .IoT (List Things etc.)
  2. AWS IotData (Get Thing Shadow, Update Thing Shadow etc.)

I’m able to successfully call the methods in first AWS IOT SDK with the temporary credentials. But I’m not able to use the same credentials to get the data from AWS IOT Data SDK. I get a forbidden error.

Every identity pool creates 2 roles, Authenticated Role and UnAuthenticatedRole. And in IAM console, I have attached the Full IOT access policy to the authenticated role. So i’m not sure why I’m getting the forbidden error.

IAM IOT Full access Policy:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "iot:*"
            ],
            "Resource": "*"
       }
    ]
}

Code:

// Snippet from login method. 
cognitoUser.authenticateUser(authDetails, {
            onSuccess: function (result) {
                // Get credentials from identity pool to access other AWS resource
                AWSCognito.config.region = REGION;
                AWS.config.credentials = new AWSCognito.CognitoIdentityCredentials({
                    IdentityPoolId: IDENTITY_POOL_ID, // your identity pool id here
                    Logins: {
                        'cognito-idp.us-west-2.amazonaws.com/USERPOOLID': result.idToken.getJwtToken()
                    }
                });
                
                getRegisteredThings(username); // Calls aws iot sdk
                getThingShadow('ShadowName'); // Calls aws iot data sdk
            },
            onFailure: function (err) {
                console.log('Error while authenticating user ' + +err);
            }
        });

// Works Fine
 var getRegisteredThings = function (username) {
        // Get the credentials and then call the iot api
        AWS.config.credentials.get(function (err) {
            if (err) {
                console.log(err);
                return;
            }
            AWS.config.region = REGION;
            var iot = new AWS.Iot();

            var params = {
                attributeName: 'owner',
                attributeValue: username
            };

            iot.listThings(params, function (err, data) {
                debugger; // This works absolutely fine. I am able to get the things registered
                if (err) {
                    console.log(err);
                    return;
                }
                console.log('List things data: ' + data);

            });
        });
    };

// Forbidden error
    var getThingShadow = function(thingName){
        AWS.config.credentials.get(function (err) {
            if (err) {
                console.log(err);
                return;
            }

            AWS.config.region = REGION;
            var iotdata = new AWS.IotData({
                endpoint: 'XXXXXX.iot.us-west-2.amazonaws.com'
            });

            var params = {
                thingName : thingName
            };
            iotdata.getThingShadow(params, function(err, data) {
                debugger; // This is where I get forbidden error
                if (err)
                    console.log(err, err.stack); // an error occurred
                else {
                    console.log(data);           // successful response
                }
            });

        });
    };

Question:

  1. Is this the right way to call the thing shadow api?'The intention is to get the current state of the shadow.
  2. Does the thingshadow api work with temporary credentials?

Workaround: As a work around I’m thinking of going the MQTT way, using the paho client library to publish to thing shadow’s ‘get’ topic and then subscribe to ‘get accepted’ topic to get the state. I’m hoping that might work.

Exception:

Error: Forbidden
    at Object.extractError (aws-iot-iotdata-sdk-2.7.24.js:7810)
    at Request.extractError (aws-iot-iotdata-sdk-2.7.24.js:7133)
    at Request.callListeners (aws-iot-iotdata-sdk-2.7.24.js:6976)
    at Request.emit (aws-iot-iotdata-sdk-2.7.24.js:6954)
    at Request.emit (aws-iot-iotdata-sdk-2.7.24.js:4057)
    at Request.transition (aws-iot-iotdata-sdk-2.7.24.js:3834)
    at AcceptorStateMachine.runTo (aws-iot-iotdata-sdk-2.7.24.js:5945)
    at aws-iot-iotdata-sdk-2.7.24.js:5954
    at Request.<anonymous> (aws-iot-iotdata-sdk-2.7.24.js:3850)
    at Request.<anonymous> (aws-iot-iotdata-sdk-2.7.24.js:4059) "ForbiddenException: Forbidden
    at Object.extractError (http://localhost:63342/aws-iot-sample/app/js/lib/aws-iot/aws-iot-iotdata-sdk-2.7.24.js:7810:37)
    at Request.extractError (http://localhost:63342/aws-iot-sample/app/js/lib/aws-iot/aws-iot-iotdata-sdk-2.7.24.js:7133:18)
    at Request.callListeners (http://localhost:63342/aws-iot-sample/app/js/lib/aws-iot/aws-iot-iotdata-sdk-2.7.24.js:6976:38)
    at Request.emit (http://localhost:63342/aws-iot-sample/app/js/lib/aws-iot/aws-iot-iotdata-sdk-2.7.24.js:6954:22)
    at Request.emit (http://localhost:63342/aws-iot-sample/app/js/lib/aws-iot/aws-iot-iotdata-sdk-2.7.24.js:4057:30)
    at Request.transition (http://localhost:63342/aws-iot-sample/app/js/lib/aws-iot/aws-iot-iotdata-sdk-2.7.24.js:3834:26)
    at AcceptorStateMachine.runTo (http://localhost:63342/aws-iot-sample/app/js/lib/aws-iot/aws-iot-iotdata-sdk-2.7.24.js:5945:22)
    at http://localhost:63342/aws-iot-sample/app/js/lib/aws-iot/aws-iot-iotdata-sdk-2.7.24.js:5954:22
    at Request.<anonymous> (http://localhost:63342/aws-iot-sample/app/js/lib/aws-iot/aws-iot-iotdata-sdk-2.7.24.js:3850:29)
    at Request.<anonymous> (http://localhost:63342/aws-iot-sample/app/js/lib/aws-iot/aws-iot-iotdata-sdk-2.7.24.js:4059:30)"

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 2
  • Comments: 17 (1 by maintainers)

Most upvoted comments

Guys @eczajk1 @bentranmyriota @louisdvs , You saved my day (actually days trying to get this to work) The thing though I can add is how to get your user id (Identity Id) used as the ‘target’ in attaching the policy request , you mentioned getting it from the console and url but according to this link: https://docs.aws.amazon.com/cognito/latest/developerguide/getting-credentials.html there is a method in the ‘CredentialsProvider’ which is ‘getIdentityId’ it’s a web request that gets the Identity Id but after providing the userIdToken in the login maps.

map.put("cognito-idp.<YOUR REGION>.amazonaws.com/<YOUR USER POOL ID>",yourCurrSession().getIdToken().getJWTToken()); credentialsProvider.setLogins(map); String identityId = credentialsProvider.getIdentityId(); That’s Java code and I used it in an android app and thank God it works instead of hard coding the user id. And dear Amazon please please please put a working step by step samples for authenticated users not just unauthenticated as all the ones in the android and ios sdk samples repositories ❤️ thank you