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

danielbayerlein

Daniel Bayerlein

Posted on April 28, 2020

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.

šŸ’– šŸ’Ŗ šŸ™… šŸš©
danielbayerlein
Daniel Bayerlein

Posted on April 28, 2020

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related