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
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, '/*' ]
💡 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'
}
})
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'
})
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])}
/>
)
}
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.
Top comments (4)
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.
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.
Where do you use "Auth"?
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.