Securely store client files in S3 using AWS cognito (Cognito + S3 + Ionic sample application)

Introduction

In this example series, we will build an ionic4 (angular6) client app where user can signup and manage his/her images in a personal space. No one other than the user signed will have access to the files uploaded. We use aws cognito for authentication and authorization and S3 to store the files.

Demo

Components

AWS Cognito — User management (signup, verify user, Authentication, Authorization)

AWS S3 — store images

Ionic4 (Angular6) — Client application

AWS amplify — javascript client library to integrate to AWS cognito and AWS S3.

Architecture

Prerequisites

$node -v
v8.9.4
$npm -v
5.6.0
$ionic -v
_ _
(_) ___ _ __ (_) ___
| |/ _ | '_ | |/ __|
| | (_) | | | | | (__
|_|___/|_| |_|_|___| CLI 4.0.1

Steps Required

Step 1: Create S3 bucket

Step 2: Enable CORS for s3

<?xml version=”1.0" encoding=”UTF-8"?> <CORSConfiguration xmlns=”http://s3.amazonaws.com/doc/2006-03-01/"> 
<CORSRule> <AllowedOrigin>*</AllowedOrigin> <AllowedMethod>PUT</AllowedMethod> <AllowedMethod>GET</AllowedMethod> <AllowedMethod>POST</AllowedMethod> <AllowedMethod>DELETE</AllowedMethod> <MaxAgeSeconds>3000</MaxAgeSeconds> <ExposeHeader>ETag</ExposeHeader> <AllowedHeader>*</AllowedHeader> </CORSRule> </CORSConfiguration>

Step 3: Create IAM policy to allow only signed-in users to access the S3 bucket.

{ 
"Version": "2012-10-17",
"Statement": [
........
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": [ "s3:PutObject", "s3:GetObject", "s3:DeleteObject" ],
"Resource": [ 
"arn:aws:s3:::<bucket-name>/<user-defined-prefix>/${cognito-identity.amazonaws.com:sub}",
"arn:aws:s3:::<bucket-name>/<user-defined-prefix>/${cognito-identity.amazonaws.com:sub}/*"
]
}
]
}

Step 5: Create a new IAM “Role” with S3 access policy attached.

Step 4: Create User pool

It is self explanatory in the UI. You can configure

  • Users and groups
  • Password policies
  • Message customization (email / sms) for user verification.

Step 5: Create identity Pool and configure “Cognito Authentication Provider” with newly created user pool.

Step 6: Link the “S3 access role” to “Authenticated user”

Step 6: Link the policy to cognito identity pool

Step 7: Build a client app

## Create new project 
ionic start ionic4Cognito sidemenu --type=angular
ionic serve
## Install angular amplify npm install --save aws-amplify 
npm install --save aws-amplify-angular
## create a deployment package 
npm run build --prod

Step 8: Integrate to AWS using amplify

Create an authentication service for aws cognito interaction

Step 9: Configure AWS cognito pool

Step 10: Build your ionic pages injecting authentication service.

For example, signin page below

and html

Step 11: Integrate to S3.. create a service to integrate to S3 using amplify “Storage”

Deploy ionic app as webapp to S3

## create a new production deployment package 
npm run build --prod
## Romove all existing files 
aws s3 rm s3://<your-bucket-name>/ --recursive
## Copy new files to S3 
aws s3 cp www/ s3://<your-bucket-name> --recursive --acl public-read

Authentication and Authorization

On sign-in, cognito issues three tokens to the client.

IdToken

IdToken contains information about the identity of the user like name, email etc.

AccessToken

Users can use this token to get authorised access to aws resources.

In our example, user is authorized to access S3 when the requests are send with AccessToken.

Request URL: https://<bucket-name>.s3.ap-southeast-2.amazonaws.com/private/<user specific path>/images/icons8-calendar-50.png
Request Method: PUT
Status Code: 200 OK
......
Authorization: AWS4-HMAC-SHA256 <more here>
Content-Type: image/png
.......

....Image data .......

RefreshToken

RefreshToken can be used to retrieve new IdToken and AccessToken.

More information can be found here and here.

Conclusion

It was pretty quick to build an ionic app with secure user access using aws cognito. Lot of heavy lifting was done by aws like user storage, notifications, token issuing, user management etc. When you want to quickly put together an app with user authentication / authorization, it is worthwhile considering aws cognito as an option.

In the next article, we will see how we can use the AccessToken to access APIs in aws api gateway implemented in aws Lamda.