DEV Community

Daniel Bayerlein
Daniel Bayerlein

Posted on

How to upload images to Amazon S3 using the AWS Amplify Storage module

AWS Amplify is a development platform for building secure, scalable mobile and web applications. It provides several libraries for the communication with the AWS services.

In this blog post I show you how to store images (also audio, video, etc. possible) on Amazon S3 using a React application.

This example uses the @aws-amplify/storage and the @aws-amplify/auth package. More on this later.

To manage the infrastructure I use the Serverless Framework.

Amazon S3 and Cognito Identity Pool

For the upload we need a S3 bucket to store the files and a Cognito Identity Pool for access control.

Configure S3 bucket

First of all you need a S3 bucket. I create it as a private bucket called example-bucket.

The CORS configuration is important, otherwise some CORS exceptions occur and the upload will not work. You can also define the allowed methods - in the example GET and PUT are allowed.

S3ImageBucket:
  Type: AWS::S3::Bucket
  Properties:
    BucketName: example-bucket
    AccessControl: Private
    CorsConfiguration:
      CorsRules:
        -
          AllowedOrigins:
            - '*'
          AllowedHeaders:
            - '*'
          AllowedMethods:
            - GET
            - PUT
          MaxAge: 3000
          ExposedHeaders:
            - x-amz-server-side-encryption
            - x-amz-request-id
            - x-amz-id-2
            - ETag
Enter fullscreen mode Exit fullscreen mode

Configure Cognito Identity Pool

After the S3 bucket has been created, a Cognito Identity Pool must be created.

I use an existing Cognito User Pool as provider. This can be configured with the CognitoIdentityProviders option. Of course you can also use another provider. In the policy, I specify which actions may be carried out. In this case s3:GetObject and s3:PutObject.

CognitoIdentityPool:
  Type: AWS::Cognito::IdentityPool
  Properties:
    IdentityPoolName: ${self:service}-${self:provider.stage}-${self:provider.region}-IdentityPool
    AllowUnauthenticatedIdentities: false
    CognitoIdentityProviders:
      - ClientId: 111xxx111xxx111xxx111
        ProviderName: cognito-idp.eu-central-1.amazonaws.com/eu-central-1_XXX

CognitoIdentityPoolRoles:
  Type: AWS::Cognito::IdentityPoolRoleAttachment
  Properties:
    IdentityPoolId:
      Ref: CognitoIdentityPool
    Roles:
      authenticated:
        !GetAtt CognitoAuthRole.Arn

CognitoAuthRole:
  Type: AWS::IAM::Role
  Properties:
    Path: /
    AssumeRolePolicyDocument:
      Version: '2012-10-17'
      Statement:
        - Effect: 'Allow'
          Principal:
            Federated: 'cognito-identity.amazonaws.com'
          Action:
            - 'sts:AssumeRoleWithWebIdentity'
          Condition:
            StringEquals:
              'cognito-identity.amazonaws.com:aud':
                Ref: CognitoIdentityPool
            'ForAnyValue:StringLike':
              'cognito-identity.amazonaws.com:amr': authenticated
    Policies:
      - PolicyName: ${self:service}-${self:provider.stage}-${self:provider.region}-S3CognitoAuthPolicy
        PolicyDocument:
          Version: '2012-10-17'
          Statement:
            - Effect: 'Allow'
              Action:
                - 's3:GetObject'
                - 's3:PutObject'
              Resource:
                - !Join [ '', [ !GetAtt S3ImageBucket.Arn, '/*' ]
Enter fullscreen mode Exit fullscreen mode

💡 You can also set a role for unauthenticated users via unauthenticated if your application requires access to the S3 bucket.

The Storage module

The @aws-amplify/storage module provides a simple mechanism for managing user content for your app in public, protected or private storage buckets.

Configure Amplify Storage

The configuration is very simple. You only have to set the bucket name and the region of this S3 bucket.

import Storage from '@aws-amplify/storage'

Storage.configure({
  AWSS3: {
    bucket: 'example-bucket',
    region: 'eu-central-1'
  }
})
Enter fullscreen mode Exit fullscreen mode

The Auth module

Additionally we need the @aws-amplify/auth module so that the application can authenticate itself.

Configure Amplify Auth

The configuration object expects the following parameters:

  • region: Region of your Amazon Cognito
  • identityPoolId: ID of your Amazon Cognito Identity Pool
  • userPoolId: ID of your Amazon Cognito User Pool
  • userPoolWebClientId: Web Client ID of your Amazon Cognito User Pool

As code it looks like this:

import Auth from '@aws-amplify/auth'

Auth.configure({
  region: 'eu-central-1',
  identityPoolId: 'eu-central-1:xxx-xxx-xxx-xxx-xxxxxx',
  userPoolId: 'eu-central-1_XXX',
  userPoolWebClientId: '111xxx111xxx111xxx111'
})
Enter fullscreen mode Exit fullscreen mode

Using Amplify Storage

Enough configurations, time for usage. 🎉

With the Storage.put() function you can put the data to S3. It returns a {key: S3 Object key} object on success.

const S3ImageUpload = () => {
  const onChange = async (file) => {
    const { key } = await Storage.put('example.png', file, {
      contentType: 'image/png'
    })

    console.log('S3 Object key', key)
  }

  return (
    <input
      type='file'
      accept='image/png'
      onChange={(e) => onChange(e.target.files[0])}
    />
  )
}
Enter fullscreen mode Exit fullscreen mode

With the return value (key) and the function Storage.get() you can retrieve the image again.

📖 All Storage functions can be found in the documentation.

Discussion (4)

Collapse
jknapp25 profile image
Josh • Edited

Thank you for the article daniel! I just wanted to mention a few items that might help improve this article for those that may be searching for this information like myself.

As a new AWS user a stumbling block for me was understanding where the CORS configuration was set, seeing as your description does not show where that is input. Also, the AWS docs specify this info is XML in their docs, but can be added programmatically as well. Seeing as your config is not XML, and the AWS docs make it difficult to find out how to add this programmatically, I had a hard time figuring out how to add this configuration.

Collapse
danielbayerlein profile image
Daniel Bayerlein Author

Hi Josh, thank you for your feedback.

You can setup the CORS configuration via XML in the AWS Management Console, see docs.aws.amazon.com/AmazonS3/lates... and docs.aws.amazon.com/AmazonS3/lates...

To provide the infrastructure I use the Serverless Framework (serverless.com/). I create the S3 bucket in the "Configure S3 bucket" section including the CORS configuration with the Serverless Framework.

Collapse
jknapp25 profile image
Josh

Where do you use "Auth"?

Collapse
danielbayerlein profile image
Daniel Bayerlein Author

To use the Amplify Storage module, you will have to configure Amplify Auth as well. Auth is a requirement for the Storage module and is used internally.