During this workshop, we’ll look into authentication, authorization and the integration with multiple backend data sources.
This repository contains template/boilerplate scripts and resources to be used during the workshop, including:
- Web (React 18 single-page-app)
- GraphQL API (AWS AppSync)
- User pool (Amazon Cognito)
- Booking NoSQL (Amazon DynamoDB) database
- Rooms SQL (Amazon Aurora Serverless) database
- Scripts and templates to get these running in the AWS public cloud
Requirements:
- AWS account
- Python 3.x to serve the web locally
- Postman to issue API requests directly
Optional:
- NodeJS to make changes and rebuild the web
- jq (if running
provision.shlocally)
The script might return some errors on the first run, as it tries to clean up any leftovers from previous executions. It is safe to ignore errors during clean-up. Any errors from the "Provisioning" point should be reported.
NOTE: Consecutive executions of provision.sh will reset the environment back to the starting point! Changes done in the AWS Console will be lost!
- Login into your AWS sandbox
- Select the
Europe (Ireland) - eu-west-1region on the top right corner - Open the CloudShell on the lower left corner.
- Clone repository
git clone https://github.com/xavicampa/appsync-workshop.git
- Execute
provision.sh. EmptyInstance IDon the first run is fine, simply press Enter:
cd appsync-workshop
bash provision.sh
Errors are expected on the first run, as it tries to clean up leftovers from pervious executions. Pay attention to any errors happening after the Provisioning message
- Copy the final output of the script into your notepad for later use
This option assumes you have installed and configured the aws-cli with a default AWS profile.
- Clone repository
git clone https://github.com/xavicampa/appsync-workshop.git
-
Ensure that the
defaultAWS profile is correctly set up with credentials from your AWS sandbox account with region and output specified-
Make sure that your default profile DOES NOT point to a customer AWS account!
-
.aws/credentials
[default] aws_access_key_id = ***************** aws_secret_access_key = *********************.aws/config
[profile default] region = eu-west-1 output = json -
-
Execute
provision.sh. EmptyInstance IDon the first run is fine, simply press Enter:
cd appsync-workshop
bash provision.sh
Errors are expected on the first run, as it tries to clean up leftovers from pervious executions. Pay attention to any errors happening after the Provisioning message
- Copy the final output of the script into your notepad for later use
The file aws-exports.js is primed during the execution of provision.sh with pointers to the resources provisioned in your AWS account:
- If the script has run in the CloudShell (Option 1 above), you need to clone the repository locally in your machine and make sure to copy&paste the content of
web/aws-exports.jsfrom the CloudShell to your localweb/aws-exports.jsfile - If the script has run from a local shell (Option 2 above), there's nothing to do
cd web
python -m http.server 3000cd src
npm install
npm startOnce the web is running locally, it should then be possible to visit http://localhost:3000 in your browser.
Login into the application using the admin, person1 and person2 credentials (specified in the output of the provision.sh script above). You will be prompted to change password upon the first login of each identity. Use a password that you'll remember (or use a password manager), as you'll have to enter it when changing identities.
Open Postman and import the collection postman/GraphQLWorkshop.postman_collection.json. There are two collection variables to be set
- URL: GraphQL API URL taken from the output of
provision.sh - Authorization: copy the
XXXXX.accessTokenvariable from theSession storageof the browser after login. This variable needs to be updated when switching betweenadmin,person1andperson2identities, as the token is unique per identity and session
Remember to save the variables.
This Authorization blob is actually a JWT token. To inspect the contents, go to jwt.io and simply paste the JWT token in the left panel, the contents will then show up on the right panel. You'll see, among other fields, your unique user identifier, or subject, in the sub claim. We'll use this in the exercises below.
The user pool contains two groups, admin and guest, and three identities, admin, person1 and person2. admin user is member of the admin group, person1 is member of the guest group, person2 does not belong to any groups.
Authorization is defined so that only admin members can manage bookings, having to specify guest, dates and room for the operations. guest members identities can only view. Users without memberships cannot access any operations.
Test the following:
- Listing rooms and bookings as
adminandperson1both work - Listing rooms and bookings as
person2does not work- Inspect Network tab in your browser's developer tool to check for the API error
- Error might be reported only in the browser's Developer Console
- Adding a booking as
adminsucceeds - Adding a booking as
person1fails- Inspect Network tab in your browser's developer tool to check for the API error
- Error might be reported only in the browser's Developer Console
The following sections describe new requirements for the API. Use the AWS Console to make the required adjustments, remembering to apply/save your changes. Be aware of the eventual consistency characteristics of AWS, changes might take a few seconds to be effective.
Limit access to the guest field from the Booking type to admin members.
- In the AWS Console, go to the AWS AppSync service, select BookingAPI and Schema
- Modify the schema adding
@aws_authto theguestfield in theBookingtype, it should only contain theadmincognito group - Save the schema
- running listBookings as
adminsucceeds when querying forguestfield - running listBookings as
person1fails when querying forguestfield
- Inspect the GraphQL response, what's in
dataanderrorfields
Allow guest to add their own booking, without exposing guest as a parameter
- In the AWS Console, go to the AWS AppSync service, select BookingAPI and Schema
- Modify the schema to add a new mutation, similar to addBooking, with guest cognito group authorization, without guest parameter
- Save the schema
- Attach a new resolver to the new mutation from the panel on the right
- Select Update runtime and specify a Unit resolver (VTL)
- Copy the mapping templates from the addBooking mutation, but use
$ctx.identity.subas guest key, and save
- Adding a booking as guest succeeds
- Updates are not visible at once, one has to exit Bookings (Home, or Rooms) and load again Bookings
- Guest cannot remove bookings
Make guest bookings visible without refresh
- Modify the schema by adding the new mutation to the list of mutations that trigger the existing subscription
- Adding a booking as guest succeeds and appears without refresh
Allow guest to remove their own bookings, without exposing guest as parameter.
Summary: New mutation, guest auth, no guest parameter, use $ctx.identity.sub for authorization in resolver.
- Removing guest booking works
- Removing admin booking does not work
- Updates are not visible without refresh (fix by adding new mutation to subscription)
Display room price (per day) of bookings without issuing extra API calls.
OPTIONAL: modify frontend to display the new field. Requires NodeJS.
Add room field to Booking type of type Room, add resolver and mapping template
- listBookings accepts
roomfield and can return itsprice
- The new field requires
@aws_authto be added
Display bookings when listing rooms without issuing extra API calls.
OPTIONAL: modify frontend to display booking information the room list. Requires NodeJS.
Add bookings field to Room type of type Booking[], add resolver and mapping template
- listRooms accepts
bookingsfield and can return its properties
- The new field requires
@aws_authto be added
Add filtering, so that listBookings can filter results by guest and roomid.
Execute cleanup.sh, provide the Instance ID returned by the provision.sh script when asked.
bash cleanup.sh