Search code examples
reactjsamazon-web-servicesamazon-s3amazon-cognitoaws-amplify

How to stop aws-amplify from appending level and identityPoolId in the url while performing S3 operations


I have setup react js website hosted on S3 with authentication using Cognito following the articles in aws-amplify docs and medium post. Everything works as documented, but I got held in customizing the URLs to perform operations on an S3 bucket (not the one used for hosting my site)

Objects in my S3 bucket are NOT under levels (public, private, protected) and also not under identityPoolId keys. For example, a typical object key in my bucket looks like below

project/run/ad33dff21f3g53/result.txt

However, a sample code below in my application

componentDidMount() {
    Amplify.configure({
      Auth: {
        identityPoolId: awsconfig.aws_cognito_identity_pool_id,
        region: awsconfig.aws_cognito_region,
        userPoolId: awsconfig.aws_user_pools_id,
        userPoolWebClientId: awsconfig.aws_user_pools_web_client_id
      },
      Storage: {
        bucket: awsconfig.my_results_bucket,
        region: awsconfig.aws_cognito_region,
        identityPoolId: awsconfig.aws_cognito_identity_pool_id
      }
    });
    SetS3Config(awsconfig.my_results_bucket, "private");
    Storage.get("project/run/ad33dff21f3g53/result.txt", {
      download: true,
      level: "private"
    })
      .then(result => {
        console.log(result.Body.toString());
        this.setState({ content: result.Body.toString() });
      })
      .catch(err => console.log(err));
  }

export function SetS3Config(bucket, level) {
  Storage.configure({
    bucket: bucket,
    level: level,
    region: awsconfig.aws_cognito_region,
    identityPoolId: awsconfig.aws_cognito_identity_pool_id
  });
}

doesn't work, as I see in the network tab of my browser, requests to s3 bucket API are hit in the below pattern

https://my_results_bucket.s3.eu-west-2.amazonaws.com/private/eu-west-2%3A0e197abd3-004e-4af8-ba56-32ff0d534f67/project/run/ad33dff21f3g53/result.txt

which throws 404 error, as I dont have my object under the specifed key.

Is there any way that I can stop aws amplify from adding level and identityPoolId in to the URL ?

PS: It works if I place my object at the exact location stated in the above URL. However, I can't do that as there are many dependencies on the keys in my S3 bucket.


Solution

  • From my understanding, this can't work with aws-amplify I'm afraid. At the moment the most you can achieve is setting customPrefixes to each level:

    const customPrefix = {
        public: 'myPublicPrefix/',
        protected: 'myProtectedPrefix/',
        private: 'myPrivatePrefix/'
    };
    
    Storage.put('test.txt', 'Hello', {
        customPrefix: customPrefix,
        level: \\ one of private, protected or public
    })
    .then (result => console.log(result))
    .catch(err => console.log(err));
    

    What I have reverted to is using the aws-sdk instead for doing complex operations:

    const credentials = await Auth.currentCredentials();
    
    const essentials = await  Auth.essentialCredentials(credentials)
    console.log(essentials)
    var s3 = new AWS.S3({
        apiVersion: '2006-03-01', 
        region: YOUR_REGION, 
        credentials:Auth.essentialCredentials(credentials)
    });
    
    var params = {Bucket: YOUR_BUCKET , Key: YOUR_OBJECT_PATH};
    var url = s3.getSignedUrl('getObject', params);
    console.log('The URL is', url);
    

    This would require to attach a policy to your user's role to give him the proper permission to do the required operations, so head to IAM and create a policy:

    {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Action": [
                    "s3:PutObject",
                    "s3:GetObject",
                    "s3:DeleteObject"
                ],
                "Resource": [
                    "arn:aws:s3:::YOUR_BUCKET/YOUR_OBJECT_PATH"
                ],
                "Effect": "Allow"
            }
        ]
    }
    

    Attach this policy to the auth/unauth role requiring access and you should be good to go. Hope I helped