├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── amplify.yml ├── metadata.yml ├── resources ├── code │ ├── .gitkeep │ └── website │ │ ├── CODE_OF_CONDUCT.md │ │ ├── CONTRIBUTING.md │ │ ├── CRA-README.md │ │ ├── LICENSE │ │ ├── NOTICE │ │ ├── package-lock.json │ │ ├── package.json │ │ ├── public │ │ ├── css │ │ │ ├── bootstrap.min.css │ │ │ ├── bootstrap.min.css.map │ │ │ ├── font.css │ │ │ ├── mapbox-gl.css │ │ │ ├── message.css │ │ │ ├── normalize.css │ │ │ └── ride.css │ │ ├── favicon.ico │ │ ├── fonts │ │ │ ├── fairplex-wide-n4.woff │ │ │ ├── fairplex-wide-n7.woff │ │ │ ├── glyphicons-halflings-regular.eot │ │ │ ├── glyphicons-halflings-regular.svg │ │ │ ├── glyphicons-halflings-regular.ttf │ │ │ ├── glyphicons-halflings-regular.woff │ │ │ └── glyphicons-halflings-regular.woff2 │ │ ├── images │ │ │ ├── bbd3207c.png │ │ │ ├── bucephalus.png │ │ │ ├── loading.gif │ │ │ ├── logo.png │ │ │ ├── rocinante.png │ │ │ ├── shadowfox.png │ │ │ ├── spinning-gears.gif │ │ │ ├── unicorn-map-bg.png │ │ │ ├── unicorn-silhouette.png │ │ │ ├── wr-home-W.png │ │ │ ├── wr-home-Xiaomi.png │ │ │ ├── wr-home-apple.png │ │ │ ├── wr-home-blackberry.png │ │ │ ├── wr-home-google.png │ │ │ ├── wr-home-kraken.png │ │ │ ├── wr-home-quote.png │ │ │ ├── wr-unicorn-one.png │ │ │ ├── wr-unicorn-three.png │ │ │ └── wr-unicorn-two.png │ │ ├── index.html │ │ ├── js │ │ │ ├── cognito-auth.js │ │ │ ├── config.js │ │ │ ├── esri-map.js │ │ │ ├── main.js │ │ │ ├── ride.js │ │ │ ├── vendor.js │ │ │ └── vendor │ │ │ │ ├── amazon-cognito-identity.min.js │ │ │ │ ├── aws-cognito-sdk.min.js │ │ │ │ ├── bootstrap.min.js │ │ │ │ ├── html5shiv.min.js │ │ │ │ ├── jquery-3.1.0.js │ │ │ │ ├── modernizr.js │ │ │ │ ├── moment.min.js │ │ │ │ ├── respond.min.js │ │ │ │ └── unicorn-icon │ │ ├── manifest.json │ │ ├── robots.txt │ │ └── unicorns.html │ │ ├── server │ │ └── requestUnicorn.js │ │ ├── src │ │ ├── amplify-config.js │ │ ├── auth │ │ │ ├── SignIn.js │ │ │ ├── SignUp.js │ │ │ └── index.js │ │ ├── components │ │ │ ├── BaseMap.js │ │ │ ├── DynamicImage.js │ │ │ ├── ESRIMap.js │ │ │ ├── EmailSignUp.js │ │ │ ├── LegalFooter.js │ │ │ ├── PageList.js │ │ │ ├── SiteFooter.js │ │ │ └── SiteNav.js │ │ ├── css │ │ │ ├── app.css │ │ │ ├── main.css │ │ │ └── ride.css │ │ ├── index.js │ │ └── pages │ │ │ ├── FAQ.js │ │ │ ├── Home.js │ │ │ ├── Investors.js │ │ │ ├── MainApp.js │ │ │ ├── Profile.js │ │ │ ├── Unicorns.js │ │ │ └── index.js │ │ └── yarn.lock ├── policies │ └── .gitkeep └── templates │ ├── .gitkeep │ ├── Cloud9WithNewVPC.yaml │ └── ServerlessBackend.yaml └── workshop ├── .DS_Store ├── buildspec.yml ├── config.toml ├── content ├── _index.en.md ├── cleanup │ ├── _index.en.md │ ├── backend │ │ └── _index.en.md │ ├── cloud9 │ │ └── _index.en.md │ ├── cognito │ │ └── _index.en.md │ ├── iam │ │ └── _index.en.md │ └── s3 │ │ └── _index.en.md ├── iam_auth │ ├── _index.en.md │ ├── architecture │ │ └── _index.en.md │ ├── conclusion │ │ └── _index.en.md │ ├── configure │ │ └── _index.en.md │ ├── s3 │ │ └── _index.en.md │ ├── store │ │ └── _index.en.md │ └── update │ │ └── _index.en.md ├── optional │ ├── _index.en.md │ ├── architecture │ │ └── _index.en.md │ ├── associate │ │ └── _index.en.md │ └── enable_auth │ │ └── _index.en.md ├── serverless │ ├── _index.en.md │ ├── api_gateway │ │ └── _index.en.md │ ├── architecture │ │ └── _index.en.md │ ├── backend │ │ ├── _index.en.md │ │ ├── ap-southeast-1.md │ │ ├── eu-west-1.md │ │ ├── us-east-1.md │ │ ├── us-east-2.md │ │ └── us-west-2.md │ ├── integration │ │ └── _index.en.md │ └── validation │ │ └── _index.en.md ├── setup │ ├── _index.en.md │ ├── cloud9 │ │ ├── _index.en.md │ │ ├── ap-southeast-1.md │ │ ├── eu-west-1.md │ │ ├── us-east-1.md │ │ ├── us-east-2.md │ │ └── us-west-2.md │ └── setupc9 │ │ └── _index.en.md └── user_auth │ ├── _index.en.md │ ├── architecture │ └── _index.en.md │ ├── identity_pool │ └── _index.en.md │ ├── integration │ └── _index.en.md │ ├── local_web │ └── _index.en.md │ ├── user_pool │ └── _index.en.md │ └── validation │ └── _index.en.md ├── layouts ├── partials │ ├── favicon.html │ ├── header.html │ ├── logo.html │ └── menu-footer.html └── shortcodes │ ├── tab.html │ └── tabs.html └── static ├── .DS_Store ├── css ├── jquery-ui.min.css ├── theme-aws.css └── theme-mine.css ├── images ├── apigateway-authorizer-cognito-confirmation.png ├── apigateway-authorizer-cognito-selection.png ├── apigateway-authorizer-iam-confirmation.png ├── apigateway-authorizer-iam-selection.png ├── apigateway-authorizer-settings.png ├── apigateway-authorizer-test.png ├── apigateway-method-request-settings.png ├── apigateway-test-authorizer.png ├── apn-logo.jpg ├── aws-open-source.jpg ├── cloud9-createscratchpadtab.png ├── cloud9-local-preview.png ├── cloud9-new-terminal.png ├── cloud9-resize-live-preview.png ├── cloud9_cfn_outputs.png ├── cloud9_initial_screen.png ├── cognito-app-clients.png ├── cognito-authorizer-request-console-log.png ├── cognito-create-user-pool.png ├── cognito-identitypool-copyId.png ├── cognito-identitypool-setup-step1.png ├── cognito-message-delivery.png ├── cognito-mfa-options.png ├── cognito-setup-scratchpad.png ├── cognito-userpool-copy-appclient-id.png ├── cognito-userpool-copy-userpool-id.png ├── cognito-userpool-setup-step1.png ├── cognito-userpool-setup-step2.png ├── cognito-userpool-setup-step3.png ├── cognito-userpool-setup-step4.png ├── cognito-userpool-setup-step5.png ├── cognito-userpool-setup-step6.png ├── cognito-userpool-setup-step7.png ├── cognito-wildrydes-messages.png ├── create-user-pool-authorizer.png ├── github-home.png ├── iam-cleanup-findAuthRole.png ├── iam-cognito-authrole-attach-apigateway-policy.png ├── iam-cognito-authrole-permissions-after-policy-update.png ├── iam-policies-wildrydesapi-search.png ├── iam-wildrydes-auth-role-add-inline-policy.png ├── iam-wildrydes-role-selection.png ├── iam-wildrydesapi-policy-details.png ├── logo.png ├── wildrydes-complete-architecture.png ├── wildrydes-module1-architecture.png ├── wildrydes-module2-architecture.png └── wildrydes-module3-architecture.png └── js ├── _tabs.js ├── jquery-3.3.1.min.js └── jquery-ui-1.12.1.min.js /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | ## Code of Conduct 2 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 3 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 4 | opensource-codeofconduct@amazon.com with any additional questions or comments. 5 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional 4 | documentation, we greatly value feedback and contributions from our community. 5 | 6 | Please read through this document before submitting any issues or pull requests to ensure we have all the necessary 7 | information to effectively respond to your bug report or contribution. 8 | 9 | 10 | ## Reporting Bugs/Feature Requests 11 | 12 | We welcome you to use the GitHub issue tracker to report bugs or suggest features. 13 | 14 | When filing an issue, please check existing open, or recently closed, issues to make sure somebody else hasn't already 15 | reported the issue. Please try to include as much information as you can. Details like these are incredibly useful: 16 | 17 | * A reproducible test case or series of steps 18 | * The version of our code being used 19 | * Any modifications you've made relevant to the bug 20 | * Anything unusual about your environment or deployment 21 | 22 | ## Contributing via Pull Requests 23 | Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that you are working against the latest source on the `dev` branch. 24 | 25 | ### Run project locally 26 | The static website is built using Hugo and to run it locally you need to install the [Hugo CLI](https://gohugo.io/getting-started/installing/). 27 | 28 | 1. Clone this repository. 29 | 2. Switch to the _dev_ branch. (`git checkout dev`). 30 | 3. Download the Learn theme by running `git clone https://github.com/matcornic/hugo-theme-learn.git workshop/themes/learn` from within the root of the project. 31 | 4. Run `hugo serve` from within the _workshop_ folder. 32 | 33 | Please keep in mind the following before sending a pull request. 34 | 35 | - You are working against the latest source on the `dev` branch. 36 | - You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already. 37 | - You open an issue to discuss any significant work - we would hate for your time to be wasted. 38 | 39 | To send us a pull request, please: 40 | 41 | 1. Fork the repository. 42 | 2. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change. 43 | 3. Ensure you test locally using Hugo CLI. 44 | 4. Commit to your fork using clear commit messages. 45 | 5. Send us a pull request, answering any default questions in the pull request interface. 46 | 6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation. 47 | 48 | GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and 49 | [creating a pull request](https://help.github.com/articles/creating-a-pull-request/). 50 | 51 | 52 | ## Finding contributions to work on 53 | Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels (enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any 'help wanted' issues is a great place to start. 54 | 55 | 56 | ## Code of Conduct 57 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 58 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 59 | opensource-codeofconduct@amazon.com with any additional questions or comments. 60 | 61 | 62 | ## Security issue notifications 63 | If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue. 64 | 65 | 66 | ## Licensing 67 | 68 | See the [LICENSE](LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution. 69 | 70 | We may ask you to sign a [Contributor License Agreement (CLA)](http://en.wikipedia.org/wiki/Contributor_License_Agreement) for larger changes. 71 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software is furnished to do so. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 10 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 11 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 12 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 13 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 14 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15 | 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Auth for Serverless Applications Workshop 2 | 3 | In this workshop, you will learn how to use Amazon Cognito for user signup, signin and managing the WildRydes rider profile. This application architecture demonstrates end-to-end authentication and authorization patterns through the use of Amazon Cognito, Amazon API Gateway, AWS Lambda, and AWS Identity and Access Management (IAM). 4 | 5 | ![Image](workshop/static/images/github-home.png) 6 | 7 | ## Getting Started 8 | 9 | Workshop URL: [https://auth.serverlessworkshops.io](https://auth.serverlessworkshops.io) 10 | 11 | ## Want to contribute? 12 | 13 | Check our [contribution guidelines](CONTRIBUTING.md) before submitting a pull request. Please submit your contributions to the `dev` branch. 14 | 15 | ## License 16 | 17 | This library is licensed under the MIT-0 License. See the LICENSE file. 18 | 19 | -------------------------------------------------------------------------------- /amplify.yml: -------------------------------------------------------------------------------- 1 | version: 0.1 2 | frontend: 3 | phases: 4 | build: 5 | commands: 6 | - tar -C resources/code/ -czf website.tar.gz . 7 | - aws s3 cp website.tar.gz s3://${S3_ARTIFACT_BUCKET}/${APP_NAME}/${AWS_BRANCH}/ --acl public-read 8 | - aws s3 cp resources/templates/Cloud9WithNewVPC.yaml s3://${S3_ARTIFACT_BUCKET}/${APP_NAME}/${AWS_BRANCH}/ --acl public-read 9 | - aws s3 cp resources/templates/ServerlessBackend.yaml s3://${S3_ARTIFACT_BUCKET}/${APP_NAME}/${AWS_BRANCH}/ --acl public-read 10 | - git clone https://github.com/matcornic/hugo-theme-learn.git workshop/themes/learn 11 | - hugo version 12 | - env HUGO_PARAMS_artifactUrlPrefix=https://${S3_ARTIFACT_BUCKET}.s3.amazonaws.com/${APP_NAME}/${AWS_BRANCH} hugo --source workshop --destination ../public --quiet 13 | artifacts: 14 | baseDirectory: /public 15 | files: 16 | - '**/*' 17 | -------------------------------------------------------------------------------- /metadata.yml: -------------------------------------------------------------------------------- 1 | #name - DNS-friendly name for the workshop. This will be used when generating the hosting URL (ie. https://my-first-workshop.workshops.aws/) 2 | name: serverless-auth 3 | #title - The title of your workshop 4 | title: Wildrydes Auth 5 | #description - A short description that will be displayed in search results 6 | description: Serverless Identity Management, Authentication, and Authorization Workshop 7 | #categories - Refer to official AWS categories covered by the workshop content here 8 | categories: 9 | - Networking 10 | - Compute 11 | #services - Refer to the official AWS service names covered by the workshop content here 12 | services: 13 | - Api Gateway 14 | - Lambda 15 | #level - Approximate skill level needed for this workshop 16 | level: 300 17 | #duration - Estimated duration in minutes 18 | duration: 120 19 | #cost - Cost in USD. If the content is offered without cost, enter 0 20 | cost: 0 21 | #author - Amazon alias of the primary author of the content 22 | author: cmcpeek 23 | #audience - Names of the personas associated with this workshop 24 | audience: 25 | - IT Professional 26 | - Developer -------------------------------------------------------------------------------- /resources/code/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/resources/code/.gitkeep -------------------------------------------------------------------------------- /resources/code/website/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | ## Code of Conduct 2 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 3 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 4 | opensource-codeofconduct@amazon.com with any additional questions or comments. 5 | -------------------------------------------------------------------------------- /resources/code/website/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional 4 | documentation, we greatly value feedback and contributions from our community. 5 | 6 | Please read through this document before submitting any issues or pull requests to ensure we have all the necessary 7 | information to effectively respond to your bug report or contribution. 8 | 9 | 10 | ## Reporting Bugs/Feature Requests 11 | 12 | We welcome you to use the GitHub issue tracker to report bugs or suggest features. 13 | 14 | When filing an issue, please check [existing open](https://github.com/aws-samples/aws-serverless-auth-workshop/issues), or [recently closed](https://github.com/aws-samples/aws-serverless-auth-workshop/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aclosed%20), issues to make sure somebody else hasn't already 15 | reported the issue. Please try to include as much information as you can. Details like these are incredibly useful: 16 | 17 | * A reproducible test case or series of steps 18 | * The version of our code being used 19 | * Any modifications you've made relevant to the bug 20 | * Anything unusual about your environment or deployment 21 | 22 | 23 | ## Contributing via Pull Requests 24 | Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that: 25 | 26 | 1. You are working against the latest source on the *master* branch. 27 | 2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already. 28 | 3. You open an issue to discuss any significant work - we would hate for your time to be wasted. 29 | 30 | To send us a pull request, please: 31 | 32 | 1. Fork the repository. 33 | 2. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change. 34 | 3. Ensure local tests pass. 35 | 4. Commit to your fork using clear commit messages. 36 | 5. Send us a pull request, answering any default questions in the pull request interface. 37 | 6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation. 38 | 39 | GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and 40 | [creating a pull request](https://help.github.com/articles/creating-a-pull-request/). 41 | 42 | 43 | ## Finding contributions to work on 44 | Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels ((enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any ['help wanted'](https://github.com/aws-samples/aws-serverless-auth-workshop/labels/help%20wanted) issues is a great place to start. 45 | 46 | 47 | ## Code of Conduct 48 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 49 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 50 | opensource-codeofconduct@amazon.com with any additional questions or comments. 51 | 52 | 53 | ## Security issue notifications 54 | If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue. 55 | 56 | 57 | ## Licensing 58 | 59 | See the [LICENSE](https://github.com/aws-samples/aws-serverless-auth-workshop/blob/master/LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution. 60 | 61 | We may ask you to sign a [Contributor License Agreement (CLA)](http://en.wikipedia.org/wiki/Contributor_License_Agreement) for larger changes. 62 | -------------------------------------------------------------------------------- /resources/code/website/NOTICE: -------------------------------------------------------------------------------- 1 | Wild Rydes 2 | Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | -------------------------------------------------------------------------------- /resources/code/website/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wild-rydes-react", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "10": "0.0.1", 7 | "acorn": "^8.8.2", 8 | "aws-amplify": "^5.0.15", 9 | "@aws-amplify/ui-react":"4.3.8", 10 | "@aws-sdk/invalid-dependency":"3.272.0", 11 | "@aws-sdk/client-pinpoint":"3.272.0", 12 | "@aws-amplify/analytics":"6.0.15", 13 | "axios": "^1.3.3", 14 | "esri-loader": "^3.7.0", 15 | "js-yaml": "^4.1.0", 16 | "lodash": "^4.17.21", 17 | "mem": "^9.0.2", 18 | "minimist": "^1.2.8", 19 | "normalize.css": "^8.0.1", 20 | "react": "^18.2.0", 21 | "react-dom": "^18.2.0", 22 | "react-router-dom": "^6.8.1", 23 | "react-scripts": "5.0.1", 24 | "set-value": "^4.1.0", 25 | "uuid": "^9.0.0" 26 | }, 27 | "scripts": { 28 | "start": "react-scripts start", 29 | "build": "react-scripts build", 30 | "test": "react-scripts test --env=jsdom", 31 | "eject": "react-scripts eject" 32 | }, 33 | "browserslist": { 34 | "production": [ 35 | ">0.2%", 36 | "not dead", 37 | "not op_mini all" 38 | ], 39 | "development": [ 40 | "last 1 chrome version", 41 | "last 1 firefox version", 42 | "last 1 safari version" 43 | ] 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /resources/code/website/public/css/font.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: "fairplex-wide"; 3 | font-style: normal; 4 | font-weight: 400; 5 | src: url("../fonts/fairplex-wide-n4.woff") format("woff2"); 6 | } 7 | @font-face { 8 | font-family: "fairplex-wide"; 9 | font-style: normal; 10 | font-weight: 700; 11 | src: url("../fonts/fairplex-wide-n7.woff") format("woff2"); 12 | } 13 | -------------------------------------------------------------------------------- /resources/code/website/public/css/message.css: -------------------------------------------------------------------------------- 1 | .panel-default { 2 | border-color: #dddddd; 3 | } 4 | .panel { 5 | background-color: #ffffff; 6 | border: 1px solid rgba(0, 0, 0, 0); 7 | border-radius: 4px; 8 | box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05); 9 | } 10 | 11 | .panel-default > .panel-heading { 12 | background-color: #f5f5f5; 13 | border-color: #dddddd; 14 | color: #333333; 15 | } 16 | .panel-heading { 17 | border-bottom: 1px solid rgba(0, 0, 0, 0); 18 | border-top-left-radius: 3px; 19 | border-top-right-radius: 3px; 20 | padding: 10px 15px; 21 | } 22 | 23 | .panel-title { 24 | color: inherit; 25 | font-size: 16px; 26 | margin-bottom: 0; 27 | margin-top: 0; 28 | } 29 | 30 | .configMessage { 31 | width: 100%; 32 | height: 100%; 33 | text-align: center; 34 | background: transparent; 35 | position: absolute; 36 | z-index: 2000; 37 | } 38 | 39 | .configMessage .panel { 40 | margin: auto; 41 | width: 40%; 42 | top: 50%; 43 | position: relative; 44 | transform: translateY(-50%); 45 | -ms-transform: translateY(-50%); 46 | -moz-transform: translateY(-50%); 47 | -webkit-transform: translateY(-50%); 48 | -o-transform: translateY(-50%); 49 | z-index: 100; 50 | } 51 | 52 | .configMessage .panel-body { 53 | text-align: left; 54 | } 55 | 56 | .configMessage .backdrop { 57 | position: absolute; 58 | width: 100%; 59 | height: 100%; 60 | background: #fff; 61 | opacity: 0.6; 62 | z-index: 50; 63 | } 64 | -------------------------------------------------------------------------------- /resources/code/website/public/css/ride.css: -------------------------------------------------------------------------------- 1 | html, body, #main, #map { 2 | padding: 0; 3 | margin: 0; 4 | height: 100%; 5 | width: 100%; 6 | } 7 | 8 | .info { 9 | position: absolute; 10 | right: 10px; 11 | top: 10px; 12 | z-index: 100; 13 | width: 275px; 14 | background: transparent; 15 | } 16 | 17 | .info .panel-body { 18 | background: transparent; 19 | } 20 | 21 | #request { 22 | position: relative; 23 | background: #fcc1d4 none repeat scroll 0 0; 24 | color: #000; 25 | border-color: #000; 26 | border-radius: 5px; 27 | text-align: center; 28 | width: 135px; 29 | } 30 | 31 | #request:disabled { 32 | color: #999; 33 | border-color: #999; 34 | } 35 | 36 | #accountLink { 37 | background: inherit; 38 | } 39 | 40 | #updates { 41 | list-style: none; 42 | margin-top: 5px; 43 | padding: 0; 44 | } 45 | 46 | #updates li { 47 | margin: 3px 0; 48 | border: 1px solid #ccc; 49 | border-radius: 5px; 50 | background-color: #f7f7f7; 51 | padding: 5px; 52 | } 53 | 54 | .authToken { 55 | word-wrap: break-word; 56 | width: 100%; 57 | } 58 | -------------------------------------------------------------------------------- /resources/code/website/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/resources/code/website/public/favicon.ico -------------------------------------------------------------------------------- /resources/code/website/public/fonts/fairplex-wide-n4.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/resources/code/website/public/fonts/fairplex-wide-n4.woff -------------------------------------------------------------------------------- /resources/code/website/public/fonts/fairplex-wide-n7.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/resources/code/website/public/fonts/fairplex-wide-n7.woff -------------------------------------------------------------------------------- /resources/code/website/public/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/resources/code/website/public/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /resources/code/website/public/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/resources/code/website/public/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /resources/code/website/public/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/resources/code/website/public/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /resources/code/website/public/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/resources/code/website/public/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /resources/code/website/public/images/bbd3207c.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/resources/code/website/public/images/bbd3207c.png -------------------------------------------------------------------------------- /resources/code/website/public/images/bucephalus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/resources/code/website/public/images/bucephalus.png -------------------------------------------------------------------------------- /resources/code/website/public/images/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/resources/code/website/public/images/loading.gif -------------------------------------------------------------------------------- /resources/code/website/public/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/resources/code/website/public/images/logo.png -------------------------------------------------------------------------------- /resources/code/website/public/images/rocinante.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/resources/code/website/public/images/rocinante.png -------------------------------------------------------------------------------- /resources/code/website/public/images/shadowfox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/resources/code/website/public/images/shadowfox.png -------------------------------------------------------------------------------- /resources/code/website/public/images/spinning-gears.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/resources/code/website/public/images/spinning-gears.gif -------------------------------------------------------------------------------- /resources/code/website/public/images/unicorn-map-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/resources/code/website/public/images/unicorn-map-bg.png -------------------------------------------------------------------------------- /resources/code/website/public/images/unicorn-silhouette.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/resources/code/website/public/images/unicorn-silhouette.png -------------------------------------------------------------------------------- /resources/code/website/public/images/wr-home-W.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/resources/code/website/public/images/wr-home-W.png -------------------------------------------------------------------------------- /resources/code/website/public/images/wr-home-Xiaomi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/resources/code/website/public/images/wr-home-Xiaomi.png -------------------------------------------------------------------------------- /resources/code/website/public/images/wr-home-apple.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/resources/code/website/public/images/wr-home-apple.png -------------------------------------------------------------------------------- /resources/code/website/public/images/wr-home-blackberry.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/resources/code/website/public/images/wr-home-blackberry.png -------------------------------------------------------------------------------- /resources/code/website/public/images/wr-home-google.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/resources/code/website/public/images/wr-home-google.png -------------------------------------------------------------------------------- /resources/code/website/public/images/wr-home-kraken.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/resources/code/website/public/images/wr-home-kraken.png -------------------------------------------------------------------------------- /resources/code/website/public/images/wr-home-quote.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/resources/code/website/public/images/wr-home-quote.png -------------------------------------------------------------------------------- /resources/code/website/public/images/wr-unicorn-one.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/resources/code/website/public/images/wr-unicorn-one.png -------------------------------------------------------------------------------- /resources/code/website/public/images/wr-unicorn-three.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/resources/code/website/public/images/wr-unicorn-three.png -------------------------------------------------------------------------------- /resources/code/website/public/images/wr-unicorn-two.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/resources/code/website/public/images/wr-unicorn-two.png -------------------------------------------------------------------------------- /resources/code/website/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | Wild Rydes 13 | 14 | 15 | 18 |
19 | 20 | 21 | -------------------------------------------------------------------------------- /resources/code/website/public/js/cognito-auth.js: -------------------------------------------------------------------------------- 1 | /*global WildRydes _config AmazonCognitoIdentity AWSCognito*/ 2 | 3 | var WildRydes = window.WildRydes || {}; 4 | 5 | (function scopeWrapper($) { 6 | var signinUrl = '/signin.html'; 7 | 8 | var poolData = { 9 | UserPoolId: _config.cognito.userPoolId, 10 | ClientId: _config.cognito.userPoolClientId 11 | }; 12 | 13 | var userPool; 14 | 15 | if (!(_config.cognito.userPoolId && 16 | _config.cognito.userPoolClientId && 17 | _config.cognito.region)) { 18 | $('#noCognitoMessage').show(); 19 | return; 20 | } 21 | 22 | userPool = new AmazonCognitoIdentity.CognitoUserPool(poolData); 23 | 24 | if (typeof AWSCognito !== 'undefined') { 25 | AWSCognito.config.region = _config.cognito.region; 26 | } 27 | 28 | WildRydes.signOut = function signOut() { 29 | userPool.getCurrentUser().signOut(); 30 | }; 31 | 32 | WildRydes.authToken = new Promise(function fetchCurrentAuthToken(resolve, reject) { 33 | var cognitoUser = userPool.getCurrentUser(); 34 | 35 | if (cognitoUser) { 36 | cognitoUser.getSession(function sessionCallback(err, session) { 37 | if (err) { 38 | reject(err); 39 | } else if (!session.isValid()) { 40 | resolve(null); 41 | } else { 42 | resolve(session.getIdToken().getJwtToken()); 43 | } 44 | }); 45 | } else { 46 | resolve(null); 47 | } 48 | }); 49 | 50 | 51 | /* 52 | * Cognito User Pool functions 53 | */ 54 | 55 | function register(email, password, onSuccess, onFailure) { 56 | var dataEmail = { 57 | Name: 'email', 58 | Value: email 59 | }; 60 | var attributeEmail = new AmazonCognitoIdentity.CognitoUserAttribute(dataEmail); 61 | 62 | userPool.signUp(toUsername(email), password, [attributeEmail], null, 63 | function signUpCallback(err, result) { 64 | if (!err) { 65 | onSuccess(result); 66 | } else { 67 | onFailure(err); 68 | } 69 | } 70 | ); 71 | } 72 | 73 | function signin(email, password, onSuccess, onFailure) { 74 | var authenticationDetails = new AmazonCognitoIdentity.AuthenticationDetails({ 75 | Username: toUsername(email), 76 | Password: password 77 | }); 78 | 79 | var cognitoUser = createCognitoUser(email); 80 | cognitoUser.authenticateUser(authenticationDetails, { 81 | onSuccess: onSuccess, 82 | onFailure: onFailure 83 | }); 84 | } 85 | 86 | function verify(email, code, onSuccess, onFailure) { 87 | createCognitoUser(email).confirmRegistration(code, true, function confirmCallback(err, result) { 88 | if (!err) { 89 | onSuccess(result); 90 | } else { 91 | onFailure(err); 92 | } 93 | }); 94 | } 95 | 96 | function createCognitoUser(email) { 97 | return new AmazonCognitoIdentity.CognitoUser({ 98 | Username: toUsername(email), 99 | Pool: userPool 100 | }); 101 | } 102 | 103 | function toUsername(email) { 104 | return email.replace('@', '-at-'); 105 | } 106 | 107 | /* 108 | * Event Handlers 109 | */ 110 | 111 | $(function onDocReady() { 112 | $('#signinForm').submit(handleSignin); 113 | $('#registrationForm').submit(handleRegister); 114 | $('#verifyForm').submit(handleVerify); 115 | }); 116 | 117 | function handleSignin(event) { 118 | var email = $('#emailInputSignin').val(); 119 | var password = $('#passwordInputSignin').val(); 120 | event.preventDefault(); 121 | signin(email, password, 122 | function signinSuccess() { 123 | console.log('Successfully Logged In'); 124 | window.location.href = 'ride.html'; 125 | }, 126 | function signinError(err) { 127 | alert(err); 128 | } 129 | ); 130 | } 131 | 132 | function handleRegister(event) { 133 | var email = $('#emailInputRegister').val(); 134 | var password = $('#passwordInputRegister').val(); 135 | var password2 = $('#password2InputRegister').val(); 136 | 137 | var onSuccess = function registerSuccess(result) { 138 | var cognitoUser = result.user; 139 | console.log('user name is ' + cognitoUser.getUsername()); 140 | var confirmation = ('Registration successful. Please check your email inbox or spam folder for your verification code.'); 141 | if (confirmation) { 142 | window.location.href = 'verify.html'; 143 | } 144 | }; 145 | var onFailure = function registerFailure(err) { 146 | alert(err); 147 | }; 148 | event.preventDefault(); 149 | 150 | if (password === password2) { 151 | register(email, password, onSuccess, onFailure); 152 | } else { 153 | alert('Passwords do not match'); 154 | } 155 | } 156 | 157 | function handleVerify(event) { 158 | var email = $('#emailInputVerify').val(); 159 | var code = $('#codeInputVerify').val(); 160 | event.preventDefault(); 161 | verify(email, code, 162 | function verifySuccess(result) { 163 | console.log('call result: ' + result); 164 | console.log('Successfully verified'); 165 | alert('Verification successful. You will now be redirected to the login page.'); 166 | window.location.href = signinUrl; 167 | }, 168 | function verifyError(err) { 169 | alert(err); 170 | } 171 | ); 172 | } 173 | }(jQuery)); 174 | -------------------------------------------------------------------------------- /resources/code/website/public/js/config.js: -------------------------------------------------------------------------------- 1 | window._config = { 2 | cognito: { 3 | userPoolId: 'us-west-2_O5JFdvjUm', 4 | userPoolClientId: '6k6nudo0cjga0jf83qmgplnhg4', 5 | region: 'us-west-2' 6 | }, 7 | api: { 8 | invokeUrl: '' // e.g. https://rc7nyt4tql.execute-api.us-west-2.amazonaws.com/prod', 9 | } 10 | }; 11 | -------------------------------------------------------------------------------- /resources/code/website/public/js/esri-map.js: -------------------------------------------------------------------------------- 1 | /*global WildRydes _config*/ 2 | 3 | var WildRydes = window.WildRydes || {}; 4 | WildRydes.map = WildRydes.map || {}; 5 | 6 | (function esriMapScopeWrapper($) { 7 | require([ 8 | 'esri/Map', 9 | 'esri/views/MapView', 10 | 'esri/Graphic', 11 | 'esri/geometry/Point', 12 | 'esri/symbols/TextSymbol', 13 | 'esri/symbols/PictureMarkerSymbol', 14 | 'esri/geometry/support/webMercatorUtils', 15 | 'dojo/domReady!' 16 | ], function requireCallback( 17 | Map, MapView, 18 | Graphic, Point, TextSymbol, 19 | PictureMarkerSymbol, webMercatorUtils 20 | ) { 21 | var wrMap = WildRydes.map; 22 | 23 | var map = new Map({ basemap: 'gray-vector' }); 24 | 25 | var view = new MapView({ 26 | center: [-122.31, 47.60], 27 | container: 'map', 28 | map: map, 29 | zoom: 12 30 | }); 31 | 32 | var pinSymbol = new TextSymbol({ 33 | color: '#f50856', 34 | text: '\ue61d', 35 | font: { 36 | size: 20, 37 | family: 'CalciteWebCoreIcons' 38 | } 39 | }); 40 | 41 | var unicornSymbol = new PictureMarkerSymbol({ 42 | url: '/images/unicorn-icon.png', 43 | width: '25px', 44 | height: '25px' 45 | }); 46 | 47 | var pinGraphic; 48 | var unicornGraphic; 49 | 50 | function updateCenter(newValue) { 51 | wrMap.center = { 52 | latitude: newValue.latitude, 53 | longitude: newValue.longitude 54 | }; 55 | } 56 | 57 | function updateExtent(newValue) { 58 | var min = webMercatorUtils.xyToLngLat(newValue.xmin, newValue.ymin); 59 | var max = webMercatorUtils.xyToLngLat(newValue.xmax, newValue.ymax); 60 | wrMap.extent = { 61 | minLng: min[0], 62 | minLat: min[1], 63 | maxLng: max[0], 64 | maxLat: max[1] 65 | }; 66 | } 67 | 68 | view.watch('extent', updateExtent); 69 | view.watch('center', updateCenter); 70 | view.then(function onViewLoad() { 71 | updateExtent(view.extent); 72 | updateCenter(view.center); 73 | }); 74 | 75 | view.on('click', function handleViewClick(event) { 76 | wrMap.selectedPoint = event.mapPoint; 77 | view.graphics.remove(pinGraphic); 78 | pinGraphic = new Graphic({ 79 | symbol: pinSymbol, 80 | geometry: wrMap.selectedPoint 81 | }); 82 | view.graphics.add(pinGraphic); 83 | $(wrMap).trigger('pickupChange'); 84 | }); 85 | 86 | wrMap.animate = function animate(origin, dest, callback) { 87 | var startTime; 88 | var step = function animateFrame(timestamp) { 89 | var progress; 90 | var progressPct; 91 | var point; 92 | var deltaLat; 93 | var deltaLon; 94 | if (!startTime) startTime = timestamp; 95 | progress = timestamp - startTime; 96 | progressPct = Math.min(progress / 2000, 1); 97 | deltaLat = (dest.latitude - origin.latitude) * progressPct; 98 | deltaLon = (dest.longitude - origin.longitude) * progressPct; 99 | point = new Point({ 100 | longitude: origin.longitude + deltaLon, 101 | latitude: origin.latitude + deltaLat 102 | }); 103 | view.graphics.remove(unicornGraphic); 104 | unicornGraphic = new Graphic({ 105 | geometry: point, 106 | symbol: unicornSymbol 107 | }); 108 | view.graphics.add(unicornGraphic); 109 | if (progressPct < 1) { 110 | requestAnimationFrame(step); 111 | } else { 112 | callback(); 113 | } 114 | }; 115 | requestAnimationFrame(step); 116 | }; 117 | 118 | wrMap.unsetLocation = function unsetLocation() { 119 | view.graphics.remove(pinGraphic); 120 | }; 121 | }); 122 | }(jQuery)); 123 | -------------------------------------------------------------------------------- /resources/code/website/public/js/main.js: -------------------------------------------------------------------------------- 1 | "use strict";!function(){var n=$("html"),t=function(){$(".btn-menu").on("click",function(t){t.preventDefault(),n.toggleClass("menu-opened")})},e=function(){t()};e()}(); -------------------------------------------------------------------------------- /resources/code/website/public/js/ride.js: -------------------------------------------------------------------------------- 1 | /*global WildRydes _config*/ 2 | 3 | var WildRydes = window.WildRydes || {}; 4 | WildRydes.map = WildRydes.map || {}; 5 | 6 | (function rideScopeWrapper($) { 7 | var authToken; 8 | WildRydes.authToken.then(function setAuthToken(token) { 9 | if (token) { 10 | authToken = token; 11 | } else { 12 | window.location.href = '/signin.html'; 13 | } 14 | }).catch(function handleTokenError(error) { 15 | alert(error); 16 | window.location.href = '/signin.html'; 17 | }); 18 | function requestUnicorn(pickupLocation) { 19 | $.ajax({ 20 | method: 'POST', 21 | url: _config.api.invokeUrl + '/ride', 22 | headers: { 23 | Authorization: authToken 24 | }, 25 | data: JSON.stringify({ 26 | PickupLocation: { 27 | Latitude: pickupLocation.latitude, 28 | Longitude: pickupLocation.longitude 29 | } 30 | }), 31 | contentType: 'application/json', 32 | success: completeRequest, 33 | error: function ajaxError(jqXHR, textStatus, errorThrown) { 34 | console.error('Error requesting ride: ', textStatus, ', Details: ', errorThrown); 35 | console.error('Response: ', jqXHR.responseText); 36 | alert('An error occured when requesting your unicorn:\n' + jqXHR.responseText); 37 | } 38 | }); 39 | } 40 | 41 | function completeRequest(result) { 42 | var unicorn; 43 | var pronoun; 44 | console.log('Response received from API: ', result); 45 | unicorn = result.Unicorn; 46 | pronoun = unicorn.Gender === 'Male' ? 'his' : 'her'; 47 | displayUpdate(unicorn.Name + ', your ' + unicorn.Color + ' unicorn, is on ' + pronoun + ' way.'); 48 | animateArrival(function animateCallback() { 49 | displayUpdate(unicorn.Name + ' has arrived. Giddy up!'); 50 | WildRydes.map.unsetLocation(); 51 | $('#request').prop('disabled', 'disabled'); 52 | $('#request').text('Set Pickup'); 53 | }); 54 | } 55 | 56 | // Register click handler for #request button 57 | $(function onDocReady() { 58 | $('#request').click(handleRequestClick); 59 | $(WildRydes.map).on('pickupChange', handlePickupChanged); 60 | 61 | WildRydes.authToken.then(function updateAuthMessage(token) { 62 | if (token) { 63 | displayUpdate('You are authenticated. Click to see your auth token.'); 64 | $('.authToken').text(token); 65 | } 66 | }); 67 | 68 | if (!_config.api.invokeUrl) { 69 | $('#noApiMessage').show(); 70 | } 71 | }); 72 | 73 | function handlePickupChanged() { 74 | var requestButton = $('#request'); 75 | requestButton.text('Request Unicorn'); 76 | requestButton.prop('disabled', false); 77 | } 78 | 79 | function handleRequestClick(event) { 80 | var pickupLocation = WildRydes.map.selectedPoint; 81 | event.preventDefault(); 82 | requestUnicorn(pickupLocation); 83 | } 84 | 85 | function animateArrival(callback) { 86 | var dest = WildRydes.map.selectedPoint; 87 | var origin = {}; 88 | 89 | if (dest.latitude > WildRydes.map.center.latitude) { 90 | origin.latitude = WildRydes.map.extent.minLat; 91 | } else { 92 | origin.latitude = WildRydes.map.extent.maxLat; 93 | } 94 | 95 | if (dest.longitude > WildRydes.map.center.longitude) { 96 | origin.longitude = WildRydes.map.extent.minLng; 97 | } else { 98 | origin.longitude = WildRydes.map.extent.maxLng; 99 | } 100 | 101 | WildRydes.map.animate(origin, dest, callback); 102 | } 103 | 104 | function displayUpdate(text) { 105 | $('#updates').append($('
  • ' + text + '
  • ')); 106 | } 107 | }(jQuery)); 108 | -------------------------------------------------------------------------------- /resources/code/website/public/js/vendor/html5shiv.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @preserve HTML5 Shiv 3.7.3 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed 3 | */ 4 | !function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=t.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=t.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),t.elements=c+" "+a,j(b)}function f(a){var b=s[a[q]];return b||(b={},r++,a[q]=r,s[r]=b),b}function g(a,c,d){if(c||(c=b),l)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():p.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||o.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),l)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return t.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(t,b.frag)}function j(a){a||(a=b);var d=f(a);return!t.shivCSS||k||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),l||i(a,d),a}var k,l,m="3.7.3",n=a.html5||{},o=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,p=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,q="_html5shiv",r=0,s={};!function(){try{var a=b.createElement("a");a.innerHTML="",k="hidden"in a,l=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){k=!0,l=!0}}();var t={elements:n.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:m,shivCSS:n.shivCSS!==!1,supportsUnknownElements:l,shivMethods:n.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=t,j(b),"object"==typeof module&&module.exports&&(module.exports=t)}("undefined"!=typeof window?window:this,document); -------------------------------------------------------------------------------- /resources/code/website/public/js/vendor/respond.min.js: -------------------------------------------------------------------------------- 1 | /*! Respond.js v1.4.2: min/max-width media query polyfill * Copyright 2013 Scott Jehl 2 | * Licensed under https://github.com/scottjehl/Respond/blob/master/LICENSE-MIT 3 | * */ 4 | 5 | !function(a){"use strict";a.matchMedia=a.matchMedia||function(a){var b,c=a.documentElement,d=c.firstElementChild||c.firstChild,e=a.createElement("body"),f=a.createElement("div");return f.id="mq-test-1",f.style.cssText="position:absolute;top:-100em",e.style.background="none",e.appendChild(f),function(a){return f.innerHTML='­',c.insertBefore(e,d),b=42===f.offsetWidth,c.removeChild(e),{matches:b,media:a}}}(a.document)}(this),function(a){"use strict";function b(){u(!0)}var c={};a.respond=c,c.update=function(){};var d=[],e=function(){var b=!1;try{b=new a.XMLHttpRequest}catch(c){b=new a.ActiveXObject("Microsoft.XMLHTTP")}return function(){return b}}(),f=function(a,b){var c=e();c&&(c.open("GET",a,!0),c.onreadystatechange=function(){4!==c.readyState||200!==c.status&&304!==c.status||b(c.responseText)},4!==c.readyState&&c.send(null))};if(c.ajax=f,c.queue=d,c.regex={media:/@media[^\{]+\{([^\{\}]*\{[^\}\{]*\})+/gi,keyframes:/@(?:\-(?:o|moz|webkit)\-)?keyframes[^\{]+\{(?:[^\{\}]*\{[^\}\{]*\})+[^\}]*\}/gi,urls:/(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g,findStyles:/@media *([^\{]+)\{([\S\s]+?)$/,only:/(only\s+)?([a-zA-Z]+)\s?/,minw:/\([\s]*min\-width\s*:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/,maxw:/\([\s]*max\-width\s*:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/},c.mediaQueriesSupported=a.matchMedia&&null!==a.matchMedia("only all")&&a.matchMedia("only all").matches,!c.mediaQueriesSupported){var g,h,i,j=a.document,k=j.documentElement,l=[],m=[],n=[],o={},p=30,q=j.getElementsByTagName("head")[0]||k,r=j.getElementsByTagName("base")[0],s=q.getElementsByTagName("link"),t=function(){var a,b=j.createElement("div"),c=j.body,d=k.style.fontSize,e=c&&c.style.fontSize,f=!1;return b.style.cssText="position:absolute;font-size:1em;width:1em",c||(c=f=j.createElement("body"),c.style.background="none"),k.style.fontSize="100%",c.style.fontSize="100%",c.appendChild(b),f&&k.insertBefore(c,k.firstChild),a=b.offsetWidth,f?k.removeChild(c):c.removeChild(b),k.style.fontSize=d,e&&(c.style.fontSize=e),a=i=parseFloat(a)},u=function(b){var c="clientWidth",d=k[c],e="CSS1Compat"===j.compatMode&&d||j.body[c]||d,f={},o=s[s.length-1],r=(new Date).getTime();if(b&&g&&p>r-g)return a.clearTimeout(h),h=a.setTimeout(u,p),void 0;g=r;for(var v in l)if(l.hasOwnProperty(v)){var w=l[v],x=w.minw,y=w.maxw,z=null===x,A=null===y,B="em";x&&(x=parseFloat(x)*(x.indexOf(B)>-1?i||t():1)),y&&(y=parseFloat(y)*(y.indexOf(B)>-1?i||t():1)),w.hasquery&&(z&&A||!(z||e>=x)||!(A||y>=e))||(f[w.media]||(f[w.media]=[]),f[w.media].push(m[w.rules]))}for(var C in n)n.hasOwnProperty(C)&&n[C]&&n[C].parentNode===q&&q.removeChild(n[C]);n.length=0;for(var D in f)if(f.hasOwnProperty(D)){var E=j.createElement("style"),F=f[D].join("\n");E.type="text/css",E.media=D,q.insertBefore(E,o.nextSibling),E.styleSheet?E.styleSheet.cssText=F:E.appendChild(j.createTextNode(F)),n.push(E)}},v=function(a,b,d){var e=a.replace(c.regex.keyframes,"").match(c.regex.media),f=e&&e.length||0;b=b.substring(0,b.lastIndexOf("/"));var g=function(a){return a.replace(c.regex.urls,"$1"+b+"$2$3")},h=!f&&d;b.length&&(b+="/"),h&&(f=1);for(var i=0;f>i;i++){var j,k,n,o;h?(j=d,m.push(g(a))):(j=e[i].match(c.regex.findStyles)&&RegExp.$1,m.push(RegExp.$2&&g(RegExp.$2))),n=j.split(","),o=n.length;for(var p=0;o>p;p++)k=n[p],l.push({media:k.split("(")[0].match(c.regex.only)&&RegExp.$2||"all",rules:m.length-1,hasquery:k.indexOf("(")>-1,minw:k.match(c.regex.minw)&&parseFloat(RegExp.$1)+(RegExp.$2||""),maxw:k.match(c.regex.maxw)&&parseFloat(RegExp.$1)+(RegExp.$2||"")})}u()},w=function(){if(d.length){var b=d.shift();f(b.href,function(c){v(c,b.href,b.media),o[b.href]=!0,a.setTimeout(function(){w()},0)})}},x=function(){for(var b=0;b 2 | 3 | 4 | 5 | 6 | 7 | Unicorns - Wild Rydes 8 | 9 | 10 | 11 | 12 |
    13 | 32 |
    33 |

    34 | Wild Rydes has a dedicated staff that recruits, trains, and tends to our herd of unicorns. We take great pride in the quality of unicorns and rydes that we provide to our customers, and our staff exercises the utmost care in vetting the unicorns that join our herd. 35 |

    36 |

    37 | Every unicorn goes through a rigorous due diligence process where we perform background checks, flying exams, and several rounds of interviews. Unicorns accepted to Wild Rydes are then treated to the best care and maintenance possible. We provide them excellent benefits, health care, and employee perks. This is part of our company philosophy in which happy unicorns lead to happy customers. 38 |

    39 |

    Meet a few of the unicorns that are part of our family.

    40 |
    41 |
    42 |
    43 |
    44 |
    45 | Jimmy Three Legs 46 |
    47 |
    48 |

    Bucephalus

    49 |
    Golden Swiss
    50 |

    51 | Bucephalus joined Wild Rydes in February 2016 and has been giving rydes almost daily. He says he most enjoys getting to know each of his ryders, which makes the job more interesting for him. In his spare time, Bucephalus enjoys watching sunsets and playing Pokemon Go. 52 |

    53 |
    54 |
    55 |
    56 |
    57 |
    58 |
    59 | Hot Shoe Henry 60 |
    61 |
    62 |

    Shadowfox

    63 |
    Brown Jersey
    64 |

    65 | Shadowfox joined Wild Rydes after completing a distinguished career in the military, where he toured the world in many critical missions. Shadowfox enjoys impressing his ryders with magic tricks that he learned from his previous owner. 66 |

    67 |
    68 |
    69 |
    70 |
    71 |
    72 |
    73 | Veronica 74 |
    75 |
    76 |

    Rocinante

    77 |
    Baby Flying Yellowback
    78 |

    79 | Rocinante recently joined the Wild Rydes team in Madrid, Spain. She was instrumental in forming Wild Rydes’ Spanish operations after a long, distinguished acting career in windmill shadow-jousting. 80 |

    81 |
    82 |
    83 |
    84 |
    85 | 104 |
    105 | 106 | 107 | 108 | -------------------------------------------------------------------------------- /resources/code/website/server/requestUnicorn.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | const express = require('express'); 16 | const bodyParser = require('body-parser'); 17 | const AWS = require('aws-sdk'); 18 | const awssem = require('aws-serverless-express/middleware'); 19 | const randomBytes = require('crypto').randomBytes; 20 | 21 | // Configure the appropriate region for the app 22 | const region = process.env.MOBILE_HUB_PROJECT_REGION || process.env.REGION || 'us-east-1'; 23 | AWS.config.update({ region: region }) 24 | let databaseTableName = 'Rides'; 25 | if (process.env.MOBILE_HUB_DYNAMIC_PREFIX) { 26 | databaseTableName = process.env.MOBILE_HUB_DYNAMIC_PREFIX + '-Rides'; 27 | } 28 | 29 | // In a real app, this would be placed into a database table 30 | const fleet = [ 31 | { Name: 'Bucephalus', Color: 'Golden', Gender: 'Male' }, 32 | { Name: 'Shadowfax', Color: 'White', Gender: 'Male' }, 33 | { Name: 'Rocinante', Color: 'Yellow', Gender: 'Female'} 34 | ]; 35 | 36 | // declare a new express app 37 | var app = express() 38 | app.use(awssem.eventContext({ deleteHeaders: false })); 39 | app.use(bodyParser.json()); 40 | app.use(function (req, res, next) { 41 | res.header("Access-Control-Allow-Origin", "*") 42 | res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept") 43 | next() 44 | }); 45 | 46 | // Create a DynamoDb connection 47 | const ddb = new AWS.DynamoDB.DocumentClient(); 48 | 49 | // Respond to POST /requestUnicorn 50 | app.post('/ride', function(req, res) { 51 | const requestContext = req.apiGateway.event.requestContext; 52 | 53 | const rideId = randomBytes(16) 54 | .toString('base64') 55 | .replace(/\+/g, '-') 56 | .replace(/\//g, '_') 57 | .replace(/=/g, ''); 58 | 59 | const username = requestContext.identity.cognitoIdentityId; 60 | const pickupLocation = req.body.PickupLocation; 61 | 62 | // Select a unicorn from the fleet. A more normal implementation 63 | // will use a routing algorithm to select from a database. 64 | const unicorn = fleet[Math.floor(Math.random() * fleet.length)]; 65 | 66 | // This is the item we will insert into the database 67 | const ddbItem = { 68 | RideId: rideId, 69 | User: username, 70 | Unicorn: unicorn, 71 | UnicornName: unicorn.Name, 72 | RequestTime: new Date().toISOString(), 73 | PickupLocation: pickupLocation 74 | }; 75 | 76 | console.log(`Inserting data into ${region}:${databaseTableName}`); 77 | ddb.put({ TableName: databaseTableName, Item: ddbItem }, 78 | function (err, data) { 79 | if (err) { 80 | console.log('error: ', err); 81 | res.status(500).json({ 82 | Error: err.message, 83 | Reference: req.requestId 84 | }); 85 | } else { 86 | console.log('success: ', data); 87 | res.status(201).json({ 88 | RideId: rideId, 89 | Unicorn: unicorn, 90 | UnicornName: unicorn.Name, 91 | Eta: 30, 92 | Rider: username 93 | }); 94 | } 95 | } 96 | ); 97 | }); 98 | 99 | // Work the local server proxy so that it listens on port 3000 100 | // Note that the yarn start server also runs on port 3000, so 101 | // you can't run them at the same time. 102 | app.listen(3000, function() { 103 | console.log("App started") 104 | }); 105 | 106 | // Export the app object. When executing the application local this 107 | // does nothing. However, to port it to AWS Lambda we will create a 108 | // wrapper around that will load the app from this file 109 | module.exports = app 110 | -------------------------------------------------------------------------------- /resources/code/website/src/amplify-config.js: -------------------------------------------------------------------------------- 1 | // This file is used for manual configuration of the Amplify library. 2 | // When Amplify is used in conjunction with the Amplify CLI toolchain or AWS Mobile Hub to manage backend resources, 3 | // an aws-exports.js file is auto-generated and can be used instead of the below to automatically configure the Amplify library. 4 | // In this workshop, we are using the Amplify client libraries without the CLI toolchain so you should edit this file manually. 5 | 6 | const awsConfig = { 7 | Auth: { 8 | identityPoolId: '', // example: 'us-east-2:c85f3c18-05fd-4bb5-8fd1-e77e7627a99e' 9 | region: '', // example: 'us-east-2' 10 | userPoolId: '', // example: 'us-east-2_teEUQbkUh' 11 | userPoolWebClientId: '' // example: '3k09ptd8kn8qk2hpk07qopr86' 12 | }, 13 | API: { 14 | endpoints: [ 15 | { 16 | name: 'WildRydesAPI', 17 | endpoint: '', // example: 'https://u8swuvl00f.execute-api.us-east-2.amazonaws.com/prod' 18 | region: '' // example: 'us-east-2' 19 | } 20 | ] 21 | }, 22 | Storage: { 23 | bucket: '', //example: 'wildrydesbackend-profilepicturesbucket-1wgssc97ekdph' 24 | region: '' // example: 'us-east-2' 25 | } 26 | } 27 | 28 | export default awsConfig; 29 | -------------------------------------------------------------------------------- /resources/code/website/src/auth/SignIn.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | import React from 'react'; 16 | import { Auth } from 'aws-amplify'; 17 | import DynamicImage from '../components/DynamicImage'; 18 | //import { withRouter } from 'react-router-dom'; 19 | import { useLocation, useNavigate, useParams } from 'react-router-dom'; 20 | 21 | import '../css/app.css'; 22 | 23 | /** 24 | * Sign-in Page 25 | */ 26 | class SignIn extends React.Component { 27 | constructor(props) { 28 | super(props); 29 | this.state = { 30 | stage: 0, 31 | email: '', 32 | password: '', 33 | code: '', 34 | userObject: null 35 | }; 36 | } 37 | 38 | async onSubmitForm(e) { 39 | e.preventDefault(); 40 | console.log('Form Submitted'); 41 | this.setState({ stage: 1 }); 42 | } 43 | 44 | async onSubmitVerification(e) { 45 | e.preventDefault(); 46 | console.log('Verification Submitted'); 47 | this.setState({ stage: 0, email: '', password: '', code: '' }); 48 | // Go back home 49 | this.props.history.replace('/'); 50 | } 51 | 52 | 53 | onEmailChanged(e) { 54 | this.setState({ email: e.target.value.toLowerCase() }); 55 | } 56 | 57 | onPasswordChanged(e) { 58 | this.setState({ password: e.target.value }); 59 | } 60 | 61 | onCodeChanged(e) { 62 | this.setState({ code: e.target.value }); 63 | } 64 | 65 | isValidEmail(email) { 66 | var re = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; 67 | return re.test(String(email).toLowerCase()); 68 | } 69 | 70 | renderSignIn() { 71 | const isValidEmail = this.isValidEmail(this.state.email); 72 | const isValidPassword = this.state.password.length > 1; 73 | 74 | return ( 75 |
    76 |
    77 | 78 |
    79 |
    80 |

    Sign in

    81 |
    this.onSubmitForm(e)}> 82 | this.onEmailChanged(e)}/> 83 | this.onPasswordChanged(e)}/> 84 | 85 |
    86 |
    87 |
    88 | ); 89 | } 90 | 91 | renderConfirm() { 92 | const isValidEmail = this.isValidEmail(this.state.email); 93 | const isValidCode = this.state.code.length === 6; 94 | 95 | return ( 96 |
    97 |
    98 | 99 |
    100 |
    101 |

    Enter MFA Code

    102 |
    this.onSubmitVerification(e)}> 103 | 104 | this.onCodeChanged(e)}/> 105 | 106 |
    107 |
    108 |
    109 | ); 110 | } 111 | 112 | render() { 113 | switch (this.state.stage) { 114 | case 0: 115 | default: 116 | return this.renderSignIn(); 117 | case 1: 118 | return this.renderConfirm(); 119 | } 120 | } 121 | } 122 | 123 | const withRouter = Component => props => { 124 | const location = useLocation(); 125 | const navigate = useNavigate(); 126 | const params = useParams(); 127 | 128 | return ( 129 | 135 | ); 136 | }; 137 | 138 | export default withRouter(SignIn); 139 | 140 | -------------------------------------------------------------------------------- /resources/code/website/src/auth/SignUp.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | import React from 'react'; 16 | import { Auth } from 'aws-amplify'; 17 | import DynamicImage from '../components/DynamicImage'; 18 | //import { withRouter } from 'react-router-dom'; 19 | import { useLocation, useNavigate, useParams } from 'react-router-dom'; 20 | 21 | import '../css/app.css'; 22 | 23 | /** 24 | * Registration Page 25 | */ 26 | class SignUp extends React.Component { 27 | constructor(props) { 28 | super(props); 29 | this.state = { 30 | stage: 0, 31 | email: '', 32 | phone: '', 33 | password: '', 34 | confirm: '', 35 | code: '' 36 | }; 37 | } 38 | 39 | async onSubmitForm(e) { 40 | e.preventDefault(); 41 | console.log('Form Submitted'); 42 | this.setState({ stage: 1 }); 43 | } 44 | 45 | async onSubmitVerification(e) { 46 | e.preventDefault(); 47 | console.log('Verification Submitted'); 48 | this.setState({ 49 | stage: 0, code: '', 50 | email: '', phone: '', 51 | password: '', confirm: '' 52 | }); 53 | // Go back to the home page 54 | this.props.history.replace('/'); 55 | } 56 | 57 | onEmailChanged(e) { 58 | this.setState({ email: e.target.value.toLowerCase() }); 59 | } 60 | 61 | onPhoneChanged(e) { 62 | this.setState({ phone: e.target.value }); 63 | } 64 | 65 | onPasswordChanged(e) { 66 | this.setState({ password: e.target.value }); 67 | } 68 | 69 | onConfirmationChanged(e) { 70 | this.setState({ confirm: e.target.value }); 71 | } 72 | 73 | onCodeChanged(e) { 74 | this.setState({ code: e.target.value }); 75 | } 76 | 77 | isValidEmail(email) { 78 | var re = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; 79 | return re.test(String(email).toLowerCase()); 80 | } 81 | 82 | renderSignUp() { 83 | const isValidEmail = this.isValidEmail(this.state.email); 84 | const isValidPassword = this.state.password.length > 1; 85 | const isValidConfirmation = isValidPassword && this.state.password === this.state.confirm; 86 | 87 | return ( 88 |
    89 |
    90 | 91 |
    92 |
    93 |

    Register

    94 |
    this.onSubmitForm(e)}> 95 | this.onEmailChanged(e)}/> 96 | this.onPhoneChanged(e)}/> 97 | this.onPasswordChanged(e)}/> 98 | this.onConfirmationChanged(e)}/> 99 | 100 |
    101 |
    102 |
    103 | ); 104 | } 105 | 106 | renderConfirm() { 107 | const isValidEmail = this.isValidEmail(this.state.email); 108 | const isValidCode = this.state.code.length === 6; 109 | 110 | return ( 111 |
    112 |
    113 | 114 |
    115 |
    116 |

    Verify Email

    117 |
    this.onSubmitVerification(e)}> 118 | 119 | this.onCodeChanged(e)}/> 120 | 121 |
    122 |
    123 |
    124 | ); 125 | } 126 | 127 | render() { 128 | switch (this.state.stage) { 129 | case 0: 130 | default: 131 | return this.renderSignUp(); 132 | case 1: 133 | return this.renderConfirm(); 134 | } 135 | } 136 | } 137 | 138 | 139 | const withRouter = Component => props => { 140 | const location = useLocation(); 141 | const navigate = useNavigate(); 142 | const params = useParams(); 143 | 144 | return ( 145 | 151 | ); 152 | }; 153 | 154 | export default withRouter(SignUp); 155 | -------------------------------------------------------------------------------- /resources/code/website/src/auth/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | import SignIn from './SignIn'; 16 | import SignUp from './SignUp'; 17 | 18 | export { 19 | SignIn, 20 | SignUp 21 | }; 22 | -------------------------------------------------------------------------------- /resources/code/website/src/components/BaseMap.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | import React from 'react'; 16 | import { loadModules } from 'esri-loader'; 17 | 18 | class BaseMap extends React.Component { 19 | static defaultProps = { 20 | mapOptions: { 21 | basemap: 'gray-vector' 22 | }, 23 | viewOptions: { 24 | zoom: 12, 25 | center: [ -122.31, 47.60 ] 26 | } 27 | }; 28 | 29 | constructor(props) { 30 | super(props); 31 | this.state = { status: 'loading' }; 32 | this.esriOptions = { 33 | url: 'https://js.arcgis.com/4.6/' 34 | }; 35 | this.style = { 36 | container: { 37 | height: '100vh', 38 | width: '100vw' 39 | }, 40 | map: { 41 | padding: 0, 42 | margin: 0, 43 | height: '100%', 44 | width: '100%' 45 | } 46 | }; 47 | } 48 | 49 | componentDidMount() { 50 | loadModules([ 'esri/Map', 'esri/views/MapView' ], this.esriOptions) 51 | .then(([Map, MapView]) => { 52 | const map = new Map(this.props.mapOptions); 53 | const view = new MapView({ 54 | container: 'esriMapView', 55 | map, 56 | ...this.props.viewOptions 57 | }); 58 | view.then(() => { 59 | this.setState({ map, view, status: 'loaded' }); 60 | }); 61 | }); 62 | } 63 | 64 | render() { 65 | return ( 66 |
    67 |
    68 | {this.state.status === 'loading' && (
    Loading...
    )} 69 |
    70 |
    71 | ); 72 | } 73 | } 74 | 75 | export default BaseMap; 76 | 77 | -------------------------------------------------------------------------------- /resources/code/website/src/components/DynamicImage.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | import React from 'react'; 16 | 17 | const DynamicImage = (props) => { 18 | const altText = props.alt || "dynamic image"; 19 | return ( 20 | {altText}/ 21 | ); 22 | }; 23 | 24 | export default DynamicImage; 25 | -------------------------------------------------------------------------------- /resources/code/website/src/components/ESRIMap.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | import React from 'react'; 16 | import { loadModules } from 'esri-loader'; 17 | 18 | class ESRIMap extends React.Component { 19 | static defaultProps = { 20 | mapOptions: { 21 | basemap: 'gray-vector' 22 | } 23 | }; 24 | 25 | constructor(props) { 26 | super(props); 27 | this.state = { status: 'loading' }; 28 | this.esriOptions = { 29 | url: 'https://js.arcgis.com/4.6/' 30 | }; 31 | this.style = { 32 | container: { 33 | height: '100vh', 34 | width: '100vw' 35 | }, 36 | map: { 37 | padding: 0, 38 | margin: 0, 39 | height: '100%', 40 | width: '100%' 41 | } 42 | }; 43 | } 44 | 45 | /** 46 | * Loads the ESRI modules and returns them as an object 47 | */ 48 | async loadEsriModules() { 49 | const [ 50 | Map, 51 | MapView, 52 | Graphic, 53 | Point, 54 | TextSymbol, 55 | PictureMarkerSymbol, 56 | webMercatorUtils 57 | ] = await loadModules([ 58 | 'esri/Map', 59 | 'esri/views/MapView', 60 | 'esri/Graphic', 61 | 'esri/geometry/Point', 62 | 'esri/symbols/TextSymbol', 63 | 'esri/symbols/PictureMarkerSymbol', 64 | 'esri/geometry/support/webMercatorUtils' 65 | ], this.esriOptions); 66 | 67 | return { 68 | Map, 69 | MapView, 70 | Graphic, 71 | Point, 72 | TextSymbol, 73 | PictureMarkerSymbol, 74 | webMercatorUtils 75 | }; 76 | } 77 | 78 | async componentDidMount() { 79 | try { 80 | const ESRI = await this.loadEsriModules(); 81 | this.xyToLngLat = ESRI.webMercatorUtils.xyToLngLat; 82 | 83 | const map = ESRI.Map({ basemap: 'gray-vector' }); 84 | const view = ESRI.MapView({ 85 | center: [-122.31, 47.60], 86 | container: 'esriMapView', 87 | map: map, 88 | zoom: 12 89 | }); 90 | 91 | const pinSymbol = new ESRI.TextSymbol({ 92 | color: '#f50856', 93 | text: '\ue61d', 94 | font: { size: 20, family: 'CalciteWebCoreIcons' } 95 | }); 96 | 97 | var unicornSymbol = new ESRI.PictureMarkerSymbol({ 98 | url: 'https://s3.amazonaws.com/aws-mobile-hub-images/wild-rydes/unicorn-icon.png', 99 | width: '25px', 100 | height: '25px' 101 | }); 102 | 103 | this.pinGraphic = null; 104 | if (this.props.pinLocation) { 105 | this.selectedPoint = this.props.pinLocation; 106 | this.pinGraphic = new ESRI.Graphic({ 107 | symbol: this.state.pinSymbol, 108 | geometry: this.selectedPoint 109 | }); 110 | view.graphics.add(this.pinGraphic); 111 | } 112 | 113 | // Watch for map re-centering 114 | view.watch('center', (position) => this.updateCenter(position)); 115 | 116 | // Watch for map pinch-and-zoom actions 117 | view.watch('extent', (extent) => this.updateExtent(extent)); 118 | 119 | // Watch for map click events 120 | view.on('click', (event) => { 121 | this.unsetLocation(); 122 | this.selectedPoint = event.mapPoint; 123 | this.pinGraphic = new ESRI.Graphic({ 124 | symbol: this.state.pinSymbol, 125 | geometry: this.selectedPoint 126 | }); 127 | view.graphics.add(this.pinGraphic); 128 | 129 | if (this.props.onMapClick) { 130 | this.props.onMapClick(this.selectedPoint); 131 | } 132 | }); 133 | 134 | view.then(() => { 135 | // Set the current map settings in the object 136 | // once it is rendered 137 | this.updateCenter(view.center); 138 | this.updateExtent(view.extent); 139 | 140 | // Store the status of the map 141 | this.setState({ 142 | map, 143 | view, 144 | pinSymbol, 145 | unicornSymbol, 146 | status: 'loaded' 147 | }); 148 | }); 149 | } catch (err) { 150 | console.error(err); 151 | } 152 | } 153 | 154 | /** 155 | * Updates the position of the map by re-centering. 156 | * 157 | * @param {Point} position the new center of the map 158 | */ 159 | updateCenter(position) { 160 | this.center = { 161 | latitude: position.latitude, 162 | longitude: position.longitude 163 | } 164 | } 165 | 166 | /** 167 | * Updates the extents of the map - used when zooming 168 | * 169 | * @param {Rectangle} extent 170 | */ 171 | updateExtent(extent) { 172 | if (typeof this.xyToLngLat !== 'undefined') { 173 | var min = this.xyToLngLat(extent.xmin, extent.ymin); 174 | var max = this.xyToLngLat(extent.xmax, extent.ymax); 175 | this.extent = { 176 | minLng: min[0], 177 | minLat: min[1], 178 | maxLng: max[0], 179 | maxLat: max[1] 180 | }; 181 | } 182 | } 183 | 184 | unsetLocation() { 185 | this.selectedPoint = null; 186 | if (this.pinGraphic !== null) { 187 | this.state.view.graphics.remove(this.pinGraphic); 188 | this.pinGraphic = null; 189 | } 190 | } 191 | 192 | render() { 193 | return ( 194 |
    195 |
    196 | {this.state.status === 'loading' && (
    Loading...
    )} 197 |
    198 |
    199 | ); 200 | } 201 | } 202 | 203 | export default ESRIMap; 204 | -------------------------------------------------------------------------------- /resources/code/website/src/components/EmailSignUp.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | import React from 'react'; 16 | 17 | class EmailSignUp extends React.Component { 18 | constructor(props) { 19 | super(props); 20 | this.state = { email: '', emailsubmitted: false }; 21 | } 22 | 23 | onEmailChanged(event) { 24 | this.setState({ email: event.target.value.toLowerCase() }); 25 | } 26 | 27 | /* TODO: HANDLE FORM INPUT */ 28 | onEmailSubmitted(event) { 29 | event.preventDefault(); 30 | 31 | this.setState({ email: '', emailsubmitted: true }); 32 | } 33 | /* END OF PINPOINT CHANGES */ 34 | 35 | render() { 36 | if (this.state.emailsubmitted) { 37 | return (

    Thank you for signing up

    ); 38 | } 39 | return ( 40 |
    41 |

    Sign Up

    42 |

    Wild Rydes is coming sooon! Enter your email to enter the limited private beta

    43 |
    this.onEmailSubmitted(event)} > 44 | this.onEmailChanged(event)}/> 45 | 46 |
    47 |
    48 | ); 49 | } 50 | } 51 | 52 | export default EmailSignUp; 53 | -------------------------------------------------------------------------------- /resources/code/website/src/components/LegalFooter.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | import React from 'react'; 16 | 17 | const LegalFooter = () => { 18 | return ( 19 |
    20 |
    21 | ©WildRydes Inc
    22 | All Rights Reserved 23 |
    24 |
    25 | ); 26 | }; 27 | 28 | export default LegalFooter; 29 | -------------------------------------------------------------------------------- /resources/code/website/src/components/PageList.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | import React from 'react'; 16 | import { Link } from 'react-router-dom'; 17 | 18 | const PageList = () => { 19 | const pages = [ 20 | { url: '/', title: 'Home' }, 21 | { url: '/unicorns', title: 'Meet the Unicorns' }, 22 | { url: '/investors', title: 'Investors & Board of Directors' }, 23 | { url: '/faq', title: 'FAQ' }, 24 | { url: '/profile', title: 'Profile' }, 25 | { url: '/register', title: 'Apply' } 26 | ]; 27 | 28 | return ( 29 |
      30 | { 31 | pages.map((v, i) => ( 32 |
    • {v.title}
    • 33 | )) 34 | } 35 |
    36 | ); 37 | }; 38 | 39 | export default PageList; 40 | -------------------------------------------------------------------------------- /resources/code/website/src/components/SiteFooter.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | import React from 'react'; 16 | import LegalFooter from './LegalFooter'; 17 | import PageList from './PageList'; 18 | 19 | const SiteFooter = () => { 20 | return ( 21 |
    22 |
    23 | 26 |
    27 | 28 |
    29 | ); 30 | }; 31 | 32 | export default SiteFooter; 33 | -------------------------------------------------------------------------------- /resources/code/website/src/components/SiteNav.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | import React from 'react'; 16 | import PageList from './PageList'; 17 | 18 | class SiteNav extends React.Component { 19 | constructor(props) { 20 | super(props); 21 | this.state = { 22 | menuOpened: false 23 | }; 24 | } 25 | 26 | onClick(event) { 27 | this.setState({ menuOpened: !this.state.menuOpened }); 28 | } 29 | 30 | render() { 31 | const cl = this.state.menuOpened ? 'menu-opened' : 'menu-closed'; 32 | const clickHandler = (event) => this.onClick(event); 33 | 34 | return ( 35 |
    36 | 39 | 42 |
    43 | ); 44 | } 45 | } 46 | 47 | export default SiteNav; 48 | -------------------------------------------------------------------------------- /resources/code/website/src/css/ride.css: -------------------------------------------------------------------------------- 1 | .info { 2 | position: absolute; 3 | right: 10px; 4 | top: 10px; 5 | z-index: 100; 6 | width: 275px; 7 | background: transparent; 8 | } 9 | 10 | .info .panel-body { 11 | background: transparent; 12 | } 13 | 14 | .panel { 15 | background-color: white; 16 | border: 1px solid rgba(0,0,0,0); 17 | border-radius: 4px; 18 | box-shadow: 0 1px 1px rgba(0,0,0,0.05); 19 | } 20 | 21 | .panel-default { 22 | border-color: #dddddd; 23 | } 24 | 25 | .panel-default > .panel-heading { 26 | background-color: #f5f5f5; 27 | border-color: #dddddd; 28 | color: #333333; 29 | } 30 | 31 | .panel-heading { 32 | border-bottom: 1px solid rgba(0, 0, 0, 0); 33 | border-top-left-radius: 3px; 34 | border-top-right-radius: 3px; 35 | padding: 10px 15px; 36 | } 37 | 38 | .panel-title { 39 | color: inherit; 40 | font-size: 16px; 41 | margin-bottom: 0; 42 | margin-top: 0; 43 | } 44 | 45 | .configMessage { 46 | width: 100%; 47 | height: 100%; 48 | text-align: center; 49 | background: transparent; 50 | position: absolute; 51 | z-index: 2000; 52 | } 53 | 54 | .configMessage .panel { 55 | margin: auto; 56 | width: 40%; 57 | top: 50%; 58 | position: relative; 59 | transform: translateY(-50%); 60 | -ms-transform: translateY(-50%); 61 | -moz-transform: translateY(-50%); 62 | -webkit-transform: translateY(-50%); 63 | -o-transform: translateY(-50%); 64 | z-index: 100; 65 | } 66 | 67 | .configMessage .panel-body { 68 | text-align: left; 69 | } 70 | 71 | .configMessage .backdrop { 72 | position: fixed; 73 | top: 0; 74 | left: 0; 75 | width: 100%; 76 | height: 100%; 77 | background: #ffffff; 78 | opacity: 0.6; 79 | z-index: 50; 80 | } 81 | 82 | .idToken { 83 | word-wrap: break-word; 84 | font-family: sans-serif; 85 | font-size: 8px; 86 | } 87 | 88 | #request { 89 | position: relative; 90 | background: #fcc1d4 none repeat scroll 0 0; 91 | color: #000; 92 | border-color: #000; 93 | border-radius: 5px; 94 | text-align: center; 95 | width: 135px; 96 | } 97 | 98 | #request:disabled { 99 | color: #999; 100 | border-color: #999; 101 | } 102 | 103 | #updates { 104 | list-style: none; 105 | margin-top: 5px; 106 | padding: 0; 107 | } 108 | 109 | #updates li { 110 | margin: 3px 0; 111 | border: 1px solid #ccc; 112 | border-radius: 5px; 113 | background-color: #f7f7f7; 114 | padding: 5px; 115 | } 116 | 117 | #main, #map { 118 | position: absolute; 119 | top: 0; 120 | left: 0; 121 | width: 100%; 122 | height: 100%; 123 | padding: 0; 124 | margin: 0; 125 | } 126 | -------------------------------------------------------------------------------- /resources/code/website/src/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | import React from 'react'; 16 | import ReactDOM from 'react-dom/client'; 17 | import { BrowserRouter, Navigate, Route, Routes } from 'react-router-dom'; 18 | import { Home, FAQ, Investors, MainApp, Unicorns, Profile } from './pages'; 19 | import { SignIn, SignUp } from './auth'; 20 | import 'normalize.css'; 21 | 22 | const isAuthenticated = () => false; 23 | 24 | const PrivateRoute = ({ component: Component, ...rest }) => ( 25 | ( 28 | isAuthenticated() === true 29 | ? 30 | : 31 | )} /> 32 | ); 33 | 34 | class App extends React.Component { 35 | render() { 36 | return ( 37 | 38 | 39 | } /> 40 | } /> 41 | } /> 42 | } /> 43 | } /> 44 | } /> 45 | } /> 46 | }/> 47 | 48 | 49 | ); 50 | } 51 | } 52 | 53 | const root = ReactDOM.createRoot(document.getElementById('root')); 54 | root.render( 55 | 56 | 57 | 58 | ); 59 | -------------------------------------------------------------------------------- /resources/code/website/src/pages/FAQ.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | import React from 'react'; 16 | import SiteNav from '../components/SiteNav'; 17 | import SiteFooter from '../components/SiteFooter'; 18 | 19 | import '../css/main.css'; 20 | 21 | const FAQ = () => { 22 | return ( 23 |
    24 |
    25 |
    Wild Rydes
    26 |
    27 |

    Frequently Asked Questions

    28 |
    29 | 30 |
    31 | 32 |
    33 |
    34 |
    35 |
    Q: Why should I use this app?
    36 |
    A: Unicorns are faster, safer, and more reliable. In recent times, their numbers have grown significantly, reaching a scale that makes it finally possible to harness them for mass transportation at an affordable cost.
    37 |
    Q: How do you recruit the unicorns? How can I know that my unicorn is trustworthy?
    38 |
    A: Our unicorns are recruited from only the most humane and highest standard unicorn farms. Our unicorns are grass-fed, free range creatures raised on vegan, non-GMO diets. These unicorns are also completely safe because unicorns have infallible morality and judgment.
    39 |
    Q: How do I request a unicorn?
    40 |
    A: Simply download our app, then tap a button to begin. Your unicorn will arrive shortly.
    41 |
    Q: How much does it cost?
    42 |
    A: Since Wild Rydes is a marketplace for flight-based transportation, the price you pay is based on factors such as distance and availability of unicorns. You set the maximum price you’re willing to pay for a given ryde and then Wild Rydes matches you with a unicorn that’s willing to accept your price.
    43 |
    Q: How does it work?
    44 |
    A: Our product is powered by a complex algorithm which efficiently matches idle unicorns with ryders based on factors such as proximity and shortest time-to-destination. The system is built on a serverless architecture, which makes running and scaling our backend services simple and cost-effective, allowing us to reliably serve the needs of Wild Rydes’ ever growing user base.
    45 |
    Q: What if I have a complaint about my unicorn?
    46 |
    A: Wild Rydes is a customer obsessed company. We value each customer and want to ensure a positive experience. Therefore, we’ve staffed our customer service team with serverless chatbots that are available 24/7 to assist you.
    47 |
    Q: How do I cancel my ride?
    48 |
    A: Tap the “Cancel Ryde” button in the Wild Rydes app.
    49 |
    Q: Can I use Wild Rydes internationally?
    50 |
    A: Yes, you can use Wild Rydes in most countries except for Antarctica, Cuba, Sudan, Iran, North Korea, Syria and any other country designated by the United States Treasury's Office of Foreign Assets Control.
    51 |
    Q: How do I pay for my ryde?
    52 |
    A: After creating a Wild Rydes account, fill in your payment method such as credit card, debit card, Bitcoin wallet, or Vespene gas repository. After you complete your Ryde, you will automatically be charged the fare.
    53 |
    Q: How many passengers can my unicorn take?
    54 |
    A: The number of passengers on a single ryde depends on the size of your unicorn. Most unicorns can take one passenger per ryde. You can also request a large size unicorn which can take up to two passengers. If you select Sleigh version, you can take up to 4 passengers.
    55 |
    Q: What if I lose an item during my ryde?
    56 |
    A: Unfortunately, it’s unlikely we can retrieve your lost item if it has fallen off the unicorn during your ryde.
    57 |
    Q: How do I share my route information with someone else?
    58 |
    A: During your ryde, you can share your route and ETA with someone else using the Wild Rydes app. Simply tap the “Share Route” button and select a contact. Soon, they’ll be able to watch the status of your ryde.
    59 |
    Q: How do I rate my unicorn?
    60 |
    A: After your ryde completes, you have the option to rate your unicorn on the app. Our unicorns are customer obsessed and strive for 5 star ratings. Your feedback helps us improve our service!
    61 |
    Q: What if my unicorn doesn’t match the photo in the app?
    62 |
    A: The unicorn photo in your app should match the unicorn that arrives to pick you up. If they do not match, then Wild Rydes recommends that you do not board the unicorn. You should then immediately report the imposter unicorn to Wild Rydes.
    63 |
    Q: Can I use Concur with Wild Rydes?
    64 |
    A: Yes, you can connect your Concur profile to the Wild Rydes app so you can track business trips made on Wild Rydes.
    65 |
    Q: Can I request a specific unicorn?
    66 |
    A: While we do not allow requesting specific unicorns, you can choose the type and size of unicorn using the app.
    67 |
    Q: Why do you charge a service fee?
    68 |
    A: The service fee is a fixed charge added to every ryde. This helps us pay for our on-going maintenance and operating costs required to run the service and tend to our unicorn herd.
    69 |
    70 |
    71 |
    72 | 73 |
    74 | ); 75 | }; 76 | 77 | export default FAQ; 78 | 79 | -------------------------------------------------------------------------------- /resources/code/website/src/pages/Investors.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | import React from 'react'; 16 | import SiteNav from '../components/SiteNav'; 17 | import SiteFooter from '../components/SiteFooter'; 18 | 19 | import '../css/main.css'; 20 | 21 | const Investor = (props) => { 22 | const cl = `title ${props.className}`; 23 | return ( 24 |
    25 |

    26 | {props.title} 27 |

    28 |
    {props.type}
    29 |

    {props.description}

    30 |
    31 | ); 32 | }; 33 | 34 | const InvestorsList = () => { 35 | const investors = [ 36 | { 37 | className: 'pcp', 38 | title: 'Penglai Communications and Post New Century Technology Corporation Ltd', 39 | type: 'Global Communications Provider', 40 | description: 'PCPNCTC was formed in 2008 to hold the telecommunications services, media, and IT businesses of Penglai Communications and Post LTD, a multinational mass media and telecommunications company. PCPL provides broadband subscription television services, fixed telephone, and mobile telephone across 20 countries and 3 continents.' 41 | }, 42 | { 43 | className: 'awesome', 44 | title: 'Tenderloin Capital', 45 | type: 'Venture Capital Firm', 46 | description: 'What makes us awesome sauce and not your typical venture firm? Backed by over three decades of experience and partnering successfully with entrepreneurs, Tenderloin Capital was founded to serve the needs of early-stage founders. It’s not just our experience that sets us apart; we relate to our entrepreneurs as people, not just as investments. Tenderloin Capital backs entrepreneurs who are building market-disrupting social-mobile-local-machine learned-artificially-intelligent cognitive experiences.' 47 | }, 48 | { 49 | className: 'barn', 50 | title: 'The Barn', 51 | type: 'Accelerator', 52 | description: 'The Barn is an institution for primarily incubating chicken eggs as well as the next revolutions in precision agriculture technology. The Barn created the industry defining model for funding sustainable, humane, non-GMO, and fairtrade early stage businesses in animal husbandry. We look forward to working with you.' 53 | } 54 | ]; 55 | 56 | return ( 57 |
    58 |
    59 | {investors.map((v, i) => ( 60 |
    61 | 62 |
    63 | ))} 64 |
    65 |
    66 | ); 67 | }; 68 | 69 | const BoardOfDirectors = () => ( 70 |
    71 |
    72 |
    73 |
    74 |

    Our Board of Directors

    75 |

    76 | Wild Rydes has a talented Board of Directors which advises the company on strategy and enabling business success. Using its collective leadership intangibles, the Board works with Wild Rydes to ideate solutions and form audacious ideas to the company’s most pressing business challenges. The Board and the Company work together to make informed problem solving decisions using process optimization and agile decision making techniques. 77 |

    78 |
    79 |
    80 |
    81 |
    82 |

    Dr. Tim Wagner

    83 |

    Chairman of the Board, Grand Master of the Serverless Rite

    84 |
    85 |
    86 |
    87 |
    88 |

    Vaughn R. Nicholson

    89 |

    EIR at Awesome Sauce Capital

    90 |
    91 |
    92 |
    93 |
    94 |
    95 |
    96 |

    Conway Bulle

    97 |

    Partner at The Barn

    98 |
    99 |
    100 |
    101 |
    102 |

    Dr. Samantha Walleford, PhD

    103 |

    Managing Partner at Tenderloin Capital

    104 |
    105 |
    106 |
    107 |
    108 |

    Qilin Fei

    109 |

    Chairman of the Central Committee for Planning at PENGLAI COMMUNICATIONS AND POST NEW CENTURY TECHNOLOGY CORPORATION LTD

    110 |
    111 |
    112 |
    113 |
    114 | ); 115 | 116 | const Investors = () => ( 117 |
    118 |
    119 |
    120 |
    Wild Rydes
    121 |
    122 |

    Backed By Top Decile Investors

    123 |

    We would not be anywhere without our trusted investors. We thank each of them for where we are today.

    124 |
    125 | 126 |
    127 | 128 |
    129 | 130 | 131 |
    132 | ); 133 | 134 | export default Investors; 135 | -------------------------------------------------------------------------------- /resources/code/website/src/pages/MainApp.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | import React from 'react'; 16 | import BaseMap from '../components/BaseMap'; 17 | import ESRIMap from '../components/ESRIMap'; 18 | import Amplify from 'aws-amplify'; 19 | import { Auth, API } from 'aws-amplify'; 20 | import awsConfig from '../amplify-config'; 21 | import '../css/ride.css'; 22 | 23 | const apiName = 'WildRydesAPI'; 24 | const apiPath = '/ride'; 25 | 26 | class MainApp extends React.Component { 27 | constructor(props) { 28 | super(props); 29 | this.state = { 30 | authToken: null, 31 | idToken: null, 32 | requestRideEnabled: false, 33 | updates: [ 34 | 'Welcome! Click the map to set your pickup location.' 35 | ] 36 | }; 37 | } 38 | 39 | async componentDidMount() { 40 | const session = await Auth.currentSession(); 41 | this.setState({ authToken: session.accessToken.jwtToken }); 42 | this.setState({ idToken: session.idToken.jwtToken }); 43 | } 44 | 45 | /** 46 | * Determines if the API is enabled 47 | * 48 | * @return {Boolean} true if API is configured 49 | */ 50 | hasApi() { 51 | // const api = awsConfig.API.endpoints.filter(v => v.endpoint !== ''); 52 | // return (typeof api !== 'undefined'); 53 | } 54 | 55 | /** 56 | * Calls the backend API to retrieve the Unicorn data 57 | * 58 | * @param {Number} latitude 59 | * @param {Number} longitude 60 | */ 61 | async getData(pin) { 62 | console.error('Request a Ride is not implemented'); 63 | } 64 | 65 | /** 66 | * Called when Request Ride is called 67 | */ 68 | async onClick() { 69 | if (!this.state.pin) { 70 | console.error('No pin present - skipping'); 71 | return true; 72 | } 73 | 74 | const updates = [ 'Requesting Unicorn' ]; 75 | try { 76 | this.setState({ 77 | requestRideEnabled: false, 78 | updates 79 | }); 80 | const data = await this.getData(this.state.pin); 81 | console.log(data); 82 | updates.push([ `Your unicorn, ${data.Unicorn.Name} will be with you in ${data.Eta}` ]); 83 | this.setState({ updates }); 84 | 85 | // Let's fake the arrival 86 | setTimeout(() => { 87 | console.log('Ride Complete'); 88 | const updateList = this.state.updates; 89 | updateList.push([ `${data.Unicorn.Name} has arrived` ]); 90 | this.setState({ 91 | updates: updateList, 92 | requestRideEnabled: false, 93 | pin: null 94 | }); 95 | }, data.Eta * 1000); 96 | } catch (err) { 97 | console.error(err); 98 | updates.push([ 'Error finding unicorn' ]); 99 | this.setState({ updates }); 100 | } 101 | } 102 | 103 | /** 104 | * Called when the mapClick happens 105 | * @param {Point} position the position of the map pin 106 | */ 107 | onMapClick(position) { 108 | console.log(`onMapClick(${JSON.stringify(position)})`); 109 | this.setState({ pin: position, requestRideEnabled: true }); 110 | } 111 | 112 | render() { 113 | const hasApi = this.hasApi(); 114 | 115 | // If API is not configured, but auth is, then output the 116 | // token. 117 | if (!hasApi) { 118 | return ( 119 |
    120 | 121 |
    122 |
    123 |
    124 |
    125 |

    Successfully Authenticated!

    126 |
    127 |
    128 |

    This page is not functional yet because there is no API configured.

    129 |

    Here is your user's identity token:

    130 |

    {this.state.idToken}

    131 |
    132 |
    133 |
    134 |
    135 | ); 136 | } 137 | 138 | // If the API is configured, then display the "requestUnicorn" 139 | // button. If data is available (i.e. unicorn is requested), 140 | // then display the additional patterns (unicorn on map). 141 | const updateList = this.state.updates.map( 142 | (v, i) =>
  • {v}
  • 143 | ); 144 | return ( 145 |
    146 |
    147 |
    148 | 149 |
    150 |
    151 |
      {updateList}
    152 |
    153 |
    154 |
    155 | { this.onMapClick(position); }}/> 156 |
    157 |
    158 | ); 159 | } 160 | } 161 | 162 | export default MainApp; 163 | -------------------------------------------------------------------------------- /resources/code/website/src/pages/Profile.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | import React from 'react'; 16 | import SiteNav from '../components/SiteNav'; 17 | import SiteFooter from '../components/SiteFooter'; 18 | import { Auth } from 'aws-amplify'; 19 | import { S3Image } from '@aws-amplify/ui-react'; 20 | import '../css/main.css'; 21 | 22 | class Profile extends React.Component { 23 | constructor(props) { 24 | super(props); 25 | this.state = { 26 | user: { 27 | attributes: { 28 | email: 'me@example.com', 29 | phone_number: '+1123456789' 30 | } 31 | } 32 | } 33 | } 34 | componentDidMount() { 35 | Auth.currentAuthenticatedUser().then(user => { 36 | console.log('Cognito User', user); 37 | this.setState({user, image_key: 'profile-' + user.attributes.sub + '.jpg'}); 38 | });; 39 | } 40 | 41 | async onImageLoad(url) { 42 | console.error('onImageLoad is not yet implemented'); 43 | } 44 | 45 | render() { 46 | return (
    47 |
    48 |
    49 | {/* this.onImageLoad(url)} picker/> */} 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 |
    E-mail:{this.state.user.attributes.email}
    Phone:{this.state.user.attributes.phone_number}
    62 |
    63 | 64 |
    65 | 66 |
    67 | ); 68 | } 69 | } 70 | 71 | export default Profile; 72 | -------------------------------------------------------------------------------- /resources/code/website/src/pages/Unicorns.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | import React from 'react'; 16 | import DynamicImage from '../components/DynamicImage'; 17 | import SiteNav from '../components/SiteNav'; 18 | import SiteFooter from '../components/SiteFooter'; 19 | 20 | import '../css/main.css'; 21 | 22 | const Unicorns = () => ( 23 |
    24 |
    25 |
    Wild Rydes
    26 |
    27 |

    Unicorns Are Our Friends

    28 |

    29 | The app is what makes this service exist, but the unicorns make it move. Meet them and see who you are riding with! 30 |

    31 |
    32 | 33 |
    34 |
    35 |

    36 | Wild Rydes has a dedicated staff that recruits, trains, and tends to our herd of unicorns. We take great pride in the quality of unicorns and rydes that we provide to our customers, and our staff exercises the utmost care in vetting the unicorns that join our herd. 37 |

    38 |

    39 | Every unicorn goes through a rigorous due diligence process where we perform background checks, flying exams, and several rounds of interviews. Unicorns accepted to Wild Rydes are then treated to the best care and maintenance possible. We provide them excellent benefits, health care, and employee perks. This is part of our company philosophy in which happy unicorns lead to happy customers. 40 |

    41 |

    Meet a few of the unicorns that are part of our family.

    42 |
    43 |
    44 |
    45 |
    46 |
    47 | 48 |
    49 |
    50 |

    Bucephalus

    51 |
    Golden Swiss
    52 |

    53 | Bucephalus joined Wild Rydes in February 2016 and has been giving rydes almost daily. He says he most enjoys getting to know each of his ryders, which makes the job more interesting for him. In his spare time, Bucephalus enjoys watching sunsets and playing Pokemon Go. 54 |

    55 |
    56 |
    57 |
    58 | 59 |
    60 |
    61 |
    62 | 63 |
    64 |
    65 |

    Shadowfox

    66 |
    Brown Jersey
    67 |

    68 | Shadowfox joined Wild Rydes after completing a distinguished career in the military, where he toured the world in many critical missions. Shadowfox enjoys impressing his ryders with magic tricks that he learned from his previous owner. 69 |

    70 |
    71 |
    72 |
    73 | 74 |
    75 |
    76 |
    77 | 78 |
    79 |
    80 |

    Rocinante

    81 |
    Baby Flying Yellowback
    82 |

    83 | Rocinante recently joined the Wild Rydes team in Madrid, Spain. She was instrumental in forming Wild Rydes’ Spanish operations after a long, distinguished acting career in windmill shadow-jousting. 84 |

    85 |
    86 |
    87 |
    88 |
    89 | 90 | 91 |
    92 | ); 93 | 94 | export default Unicorns; 95 | -------------------------------------------------------------------------------- /resources/code/website/src/pages/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | import Home from './Home'; 16 | import FAQ from './FAQ'; 17 | import Investors from './Investors'; 18 | import MainApp from './MainApp'; 19 | import Unicorns from './Unicorns'; 20 | import Profile from './Profile'; 21 | 22 | export { 23 | Home, 24 | FAQ, 25 | Investors, 26 | MainApp, 27 | Unicorns, 28 | Profile, 29 | }; 30 | -------------------------------------------------------------------------------- /resources/policies/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/resources/policies/.gitkeep -------------------------------------------------------------------------------- /resources/templates/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/resources/templates/.gitkeep -------------------------------------------------------------------------------- /workshop/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/workshop/.DS_Store -------------------------------------------------------------------------------- /workshop/buildspec.yml: -------------------------------------------------------------------------------- 1 | version: 0.2 2 | phases: 3 | install: 4 | runtime-versions: 5 | golang: 1.12 6 | nodejs: 10 7 | commands: 8 | - echo Entered the install phase... 9 | - apt-get -qq update && apt-get -qq install curl 10 | - apt-get -qq install asciidoctor 11 | - curl -s -L https://github.com/gohugoio/hugo/releases/download/v0.55.6/hugo_0.55.6_Linux-64bit.deb -o hugo.deb 12 | - dpkg -i hugo.deb 13 | finally: 14 | - echo Installation done 15 | build: 16 | commands: 17 | - echo Entered the build phase ... 18 | - echo Build started on `date` 19 | - cd $CODEBUILD_SRC_DIR/workshop/themes 20 | - git clone https://github.com/matcornic/hugo-theme-learn.git learn 21 | - cd ../ 22 | - hugo --quiet 23 | finally: 24 | - echo Building the HTML files finished 25 | artifacts: 26 | files: 27 | - "**/*" 28 | base-directory: $CODEBUILD_SRC_DIR/workshop/public/ 29 | discard-paths: no 30 | -------------------------------------------------------------------------------- /workshop/config.toml: -------------------------------------------------------------------------------- 1 | RelativeURLs=true 2 | CanonifyURLs=true 3 | languageCode = "en-US" 4 | defaultContentLanguage = "en" 5 | 6 | title = "Serverless Auth " 7 | theme = "learn" 8 | metaDataFormat = "yaml" 9 | defaultContentLanguageInSubdir= true 10 | 11 | uglyurls = true 12 | sectionPagesMenu = "main" 13 | pygmentsCodeFences = true 14 | pygmentsStyle = "monokai" 15 | 16 | [params] 17 | editURL = "https://github.com/aws-samples/aws-serverless-auth-workshop" 18 | description = "Serverless Identity Management, Authentication, and Authorization Workshop" 19 | author = "Chris McPeek " 20 | disableBreadcrumb = false 21 | disableNextPrev = false 22 | themeVariant = "aws" 23 | disableSearch = false 24 | disableAssetsBusting = true 25 | disableLanguageSwitchingButton = false 26 | disableShortcutsTitle = true 27 | disableInlineCopyToClipBoard = true 28 | artifactUrlPrefix = "https://serverless-workshops-artifacts.s3.amazonaws.com/wildrydes-auth/dev" 29 | 30 | [outputs] 31 | home = [ "HTML", "RSS", "JSON"] 32 | 33 | [blackfriday] 34 | plainIDAnchors = true 35 | hrefTargetBlank = true 36 | 37 | [Languages] 38 | [Languages.en] 39 | title = "" 40 | weight = 1 41 | languageName = "English" 42 | -------------------------------------------------------------------------------- /workshop/content/_index.en.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Serverless Identity Management, AuthN, and AuthZ Workshop" 3 | chapter = true 4 | weight = 1 5 | +++ 6 | In this workshop, you will build a serverless microservices application that enables users to request unicorn rides from the Wild Rydes fleet. The application will present users with a user interface for signing up, signing in, indicating their location to request a ride, and managing their rider profile. 7 | 8 | This application architecture demonstrates end-to-end authentication and authorization patterns through the use of [Amazon Cognito](https://aws.amazon.com/cognito/), [Amazon API Gateway](https://aws.amazon.com/api-gateway/), [AWS Lambda](https://aws.amazon.com/lambda/), and [AWS Identity and Access Management (IAM)](https://aws.amazon.com/iam/). A single page [React JS](https://reactjs.org/) web app hosts the HTML, CSS and Javascript to render the front-end which then connects to a public serverless backend API built using Amazon API Gateway and AWS Lambda. Amazon Cognito provides user identity management and authentication functions to secure the backend API. Finally, DynamoDB provides a persistence layer where data is stored and retrieved via the API's Lambda function. 9 | 10 | ![Architecture Diagram](../images/wildrydes-complete-architecture.png) 11 | 12 | 13 | ### Issues, Comments, Feedback? 14 | 15 | I’m open source! If you see an issue, want to contribute content, or have overall feedback please open an issue or pull request in our GitHub repository: [github.com/aws-samples/aws-serverless-auth-workshop/](https://github.com/aws-samples/aws-serverless-auth-workshop/). 16 | 17 | {{% button href="https://github.com/aws-samples/aws-serverless-auth-workshop/issues" icon="fas fa-bug" %}}Report an issue{{% /button %}} 18 | {{% button href="https://aws.amazon.com/serverless/developer-tools" icon="fas fa-graduation-cap" %}}Learn more{{% /button %}} 19 | -------------------------------------------------------------------------------- /workshop/content/cleanup/_index.en.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Cleanup Resources" 3 | chapter = true 4 | weight = 60 5 | pre = "4. " 6 | +++ 7 | 8 | To prevent your account from accruing additional charges, you should remove any resources that are no longer needed. -------------------------------------------------------------------------------- /workshop/content/cleanup/backend/_index.en.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Remove WildRydes Backend" 3 | weight = 64 4 | +++ 5 | 6 | Next, you will need to remove the ***CloudFormation*** stack for the API. This stack should be named **WildRydesBackend**. Once again, from the your terminal window, run: 7 | 8 | ```bash 9 | aws cloudformation delete-stack --stack-name WildRydesBackend 10 | ``` 11 | 12 | > If you changed the name of your stack from the default, you will need to update the stack name to what you changed it to. If you clicked the quick link in the instructions, no adjustment to the above command is needed. You can run `aws cloudformation describe-stacks` to find the your stack name. -------------------------------------------------------------------------------- /workshop/content/cleanup/cloud9/_index.en.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Remove Cloud9 and VPC Stack" 3 | weight = 65 4 | +++ 5 | 6 | Lastly, you will need to remove the ***CloudFormation Stack*** for the **Cloud9 instance** and its VPC. This stack should be named **WildRydes-Cloud9**. Deleting this stack will **shut down and permanently delete your Cloud9 environment** and all code or projects within so be sure you want to proceed before executing this command. 7 | 8 | ```bash 9 | aws cloudformation delete-stack --stack-name WildRydes-Cloud9 10 | ``` 11 | 12 | > If you changed the name of your stack from the default, you will need to update the stack name to what you changed it to. If you clicked the quick link in the instructions, no adjustment to the command above is needed. You can run `aws cloudformation describe-stacks` to find your stack name. -------------------------------------------------------------------------------- /workshop/content/cleanup/cognito/_index.en.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Remove Cognito Resources" 3 | weight = 62 4 | +++ 5 | 6 | 1. From your **Cloud9 developer environment** run the following: 7 | 8 | ```bash 9 | aws cognito-identity delete-identity-pool --identity-pool-id YOUR-IDENTITY-POOL-ID-HERE 10 | ``` 11 | 12 | > Copy and paste your Cognito identity pool ID from your scratch pad (example: us-west-2:b4b755cd-d359-42a1-9b49-f0e73f5b2571). 13 | 14 | > If you closed your scratch pad with your Cognito idenity pool ID, you can run the following list call via CLI to find the proper identiy pool ID, then run the delete call above. 15 | 16 | ```bash 17 | aws cognito-identity list-identity-pools --max-results 10 18 | ``` 19 | 20 | 1. Next, run the following command to delete the Cognito User Pool you created: 21 | 22 | ```bash 23 | aws cognito-idp delete-user-pool --user-pool-id YOUR-USER-POOL-ID-HERE 24 | ``` 25 | 26 | > Copy and paste your user pool ID from your scratch pad (example: us-west-2:us-west-2_srLwFQiEC) 27 | 28 | > If you closed your scratch pad with your user pool ID, you can run the following list call via CLI to find the proper user pool id, then run the delete call above. 29 | 30 | ```bash 31 | aws cognito-idp list-user-pools --max-results 10 32 | ``` 33 | -------------------------------------------------------------------------------- /workshop/content/cleanup/iam/_index.en.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Detach IAM Policy" 3 | weight = 63 4 | +++ 5 | 6 | #### Detach CognitoIdentityPoolAuthStandardPolicy IAM Policy 7 | 8 | 1. Before you delete the backend stack, you will need to remove the IAM Policy that you manually attached to the Auth role. 9 | 10 | Navigate to the Identity and Access Management (IAM) Console and search for the Auth role and click into it. 11 | 12 | ![Find Auth Role](../images/iam-cleanup-findAuthRole.png) 13 | 14 | 1. On the Role Summary page, find the policy named **WildRydesAPI-StandardUserPolicy** in the Permissions tab. Once you locate the policy, click the **X** to remove this policy from the IAM Role. A popup window will ask you to confirm that you want to remove it - click the red **Detach** button. -------------------------------------------------------------------------------- /workshop/content/cleanup/s3/_index.en.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Empty and remove S3 Bucket" 3 | weight = 61 4 | +++ 5 | 6 | 1. First, you need to empty the ***S3 bucket*** that was created by the Serverless Backend CloudFormation template. 7 | 8 | 1. Go the AWS Management Console, click **Services** then select **CloudFormation** under Management Tools. 9 | 10 | 1. In the **CloudFormation** console, click on your ***Wild Rydes*** stack name, such as `WildRydesBackend`. 11 | 12 | 1. Click on the **Outputs** tab. 13 | 14 | 1. Copy your bucket name to your clipboard. It is the name shown under Value for the key called `WildRydesProfilePicturesBucket`. 15 | 16 | 1. Open your Cloud9 developer environment. 17 | 18 | 1. Within the Cloud9 IDE, open up a terminal. You can do this by clicking the `+` icon in the lower pane and selecting **New Terminal**. 19 | 20 | ![Cloud9 Terminal](../images/cloud9-new-terminal.png) 21 | 22 | 1. Paste the following command and be sure to update your S3 bucket name: 23 | 24 | ```bash 25 | aws s3 rb s3://MY-BUCKET-NAME --force 26 | ``` -------------------------------------------------------------------------------- /workshop/content/iam_auth/_index.en.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "AWS integration with IAM-based AuthZ" 3 | chapter = true 4 | weight = 50 5 | pre = "3. " 6 | +++ 7 | 8 | In this module, you will expand your Wild Rydes application by enabling a profile management and profile photo management capabilities. [Amazon Cognito](https://aws.amazon.com/cognito/) will be used to store your user's profile information and custom attributes whereas [Amazon S3](https://aws.amazon.com/s3/) will store your user's profile pictures, with a link to the photo only being stored in the user's profile directly. -------------------------------------------------------------------------------- /workshop/content/iam_auth/architecture/_index.en.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Solution Architecture" 3 | weight = 51 4 | +++ 5 | 6 | Building on Modules 1 and 2, this module will add photo storage and management via an Amazon S3 bucket. For AWS resource access from a web application, Amazon Cognito will issue not only JWTs as we saw earlier, but then also allow users to assume an IAM role from within the application. This AWS IAM role will then allow their application to securely connect to upload and download photos from S3 (though any other AWS API would also work with this capability). To secure access to the photo storage and bucket, you will leverage IAM policies for fine-grained control. 7 | 8 | ![Module 3 architecture](../images/wildrydes-module3-architecture.png) 9 | 10 | --- 11 | #### Implementation Overview 12 | 13 | Each of the following sections provides an implementation overview and detailed, step-by-step instructions. The overview should provide enough context for you to complete the implementation if you're already familiar with the AWS Management Console or you want to explore the services yourself without following a walkthrough. 14 | 15 | If you're using the latest version of the Chrome, Firefox, or Safari web browsers the step-by-step instructions won't be visible until you expand the section. -------------------------------------------------------------------------------- /workshop/content/iam_auth/conclusion/_index.en.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Conclusion" 3 | weight = 56 4 | +++ 5 | 6 | Congratulations! You've completed the Wild Rydes Auth workshop. We hope that this time and interactive learning has been valuable for you. For further learning on this topic, please see our list of [Serverless Auth Resources](https://github.com/aws-samples/aws-serverless-workshops/blob/master/Auth/Resources.md). 7 | 8 | Please remember to run through the Clean up steps to ensure you decommission all resources spun up during the workshop today. 9 | 10 | Thank you for participating in this workshop! -------------------------------------------------------------------------------- /workshop/content/iam_auth/configure/_index.en.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Configure IAM permissions" 3 | weight = 53 4 | +++ 5 | 6 | Though you could now attempt uploading photos via AWS Amplify, Amplify would use your Cognito Identity Pool roles that were created in module 1 which currently has no policies associated so you would not have access to the S3 bucket created. You need to next update our roles to have policies that grant access to our S3 photo bucket. 7 | 8 | ### High-Level Instructions 9 | 10 | Browse to the IAM console and find your Cognito Identity Pool's authenticated user role. Create an in-line policy on this role which provides for [S3 bucket protected and private-level access](https://aws-amplify.github.io/docs/js/storage#file-access-levels) per-user by leveraging IAM policy variables. 11 | 12 | {{% expand "Step-by-step instructions (expand for details)" %}} 13 | 14 | 1. Go the AWS Management Console, click **Services** then select **IAM** under Security, Identity, and Compliance. 15 | 16 | 1. Choose **Roles**. 17 | 18 | 1. Search for ***WildRydes*** to find the two roles which were created by Cognito Identity Pools when you created the Identity Pool in module one. Should you not be able to find the roles here, you can alternatively go to the **Cognito Federated Identities** console, find the correct identity pool, then click **Edit Identity Pool** in the top-right corner to see the roles listed. Each identity pool has both an Unauthenticated user role and an Authenticated user role. 19 | 20 | 1. Once you have found the names of the roles, go back to the IAM console and select the Auth role for your authenticated users. 21 | 22 | > If the full name of the role is hidden from view due to column width, you can hover over the partially visible name of the role to see the full name of the role as a tool tip. 23 | 24 | ![IAM WildRydes Auth Role Selction](../images/iam-wildrydes-role-selection.png) 25 | 26 | 1. We want to grant permissions to this role explicitly so we will use an inline policy, which would be deleted with this role if it were ever to be deleted. 27 | 28 | 1. Choose **Add inline policy** on the right-hand side to create a new inline policy associated to this IAM role. 29 | 30 | ![Add inline policy to WildRydes auth role](../images/iam-wildrydes-auth-role-add-inline-policy.png) 31 | 32 | 1. Choose the **JSON** tab to allow you to free-form edit the new policy. 33 | 34 | 1. Paste the following IAM policy statements for S3 access. After pasting, you will need to go **replace the bucket name** listed in all caps with your bucket name (a total of 4 times). 35 | 36 | > Be sure to leave the parts of the resource names before and after the replacement value alone and not accidentally modify them. 37 | 38 | > The following policy makes use of IAM policy variables where ***${aws:userid}*** represents the current authenticated user's unique Cognito identity ID. This policy's effective permissions will allow all authenticated users to read objects from the root of the bucket and any /protected path, but only allow users to read their own private sub-path and write to their sub-path within the protected path. These are default paths that are integrated with AWS Amplify to easily set [file access levels](https://aws-amplify.github.io/docs/js/storage#file-access-levels). 39 | 40 | ``` 41 | { 42 | "Version": "2012-10-17", 43 | "Statement": [ 44 | { 45 | "Effect": "Allow", 46 | "Action": [ 47 | "s3:PutObject", 48 | "s3:GetObject", 49 | "s3:GetObjectVersion", 50 | "s3:DeleteObject", 51 | "s3:DeleteObjectVersion" 52 | ], 53 | "Resource": "arn:aws:s3:::REPLACE_WITH_YOUR_BUCKET_NAME/private/${aws:userid}/*" 54 | }, 55 | { 56 | "Effect": "Allow", 57 | "Action": [ 58 | "s3:GetObject", 59 | "s3:GetObjectVersion" 60 | ], 61 | "Resource": "arn:aws:s3:::REPLACE_WITH_YOUR_BUCKET_NAME/protected/*" 62 | }, 63 | { 64 | "Effect": "Allow", 65 | "Action": [ 66 | "s3:PutObject", 67 | "s3:DeleteObject", 68 | "s3:DeleteObjectVersion" 69 | ], 70 | "Resource": "arn:aws:s3:::REPLACE_WITH_YOUR_BUCKET_NAME/protected/${aws:userid}/*" 71 | }, 72 | { 73 | "Effect": "Allow", 74 | "Action": [ 75 | "s3:PutObject", 76 | "s3:GetObject", 77 | "s3:GetObjectVersion", 78 | "s3:DeleteObject", 79 | "s3:DeleteObjectVersion" 80 | ], 81 | "Resource": "arn:aws:s3:::REPLACE_WITH_YOUR_BUCKET_NAME/public/*" 82 | } 83 | ] 84 | } 85 | ``` 86 | 87 | 1. Choose **Review** policy. 88 | 89 | 1. Name the policy `WildRydes-S3Access`. 90 | 91 | 1. After reviewing for accuracy and any syntax errors, choose **Create policy**. 92 | -------------------------------------------------------------------------------- /workshop/content/iam_auth/s3/_index.en.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Setup S3 Bucket" 3 | weight = 52 4 | +++ 5 | 6 | You will need to configure AWS Amplify to securely store profile images in an S3 bucket. To save time, the Serverless Backend CloudFormation template that created the serverless backend API for this workshop also created an S3 bucket for this purpose with the cross-origin resource sharing (CORS) settings already set. You just need to associate this bucket with your application's code. 7 | 8 | ### High-Level Instructions 9 | 10 | Browse to your CloudFormation stack created in the earlier modules and find the name of the S3 bucket under Outputs. Once you have the name, open your ***amplify-config.js*** file again and update the storage section with the bucket's name and region. 11 | 12 | {{% expand "Step-by-step instructions (expand for details)" %}} 13 | 14 | 1. Go the AWS Management Console, click **Services** then select **CloudFormation** under Management Tools. 15 | 16 | 1. In the CloudFormation console, click on your Wild Rydes stack name, such as **WildRydesBackend**. 17 | 18 | 1. Click on the **Outputs** tab. 19 | 20 | 1. Copy your bucket name to your clipboard. It is the name shown under `Value` for the key called ***WildRydesProfilePicturesBucket***. 21 | 22 | 1. Next, return to your Cloud9 IDE and open the file **/website/src/amplify-config.js**. 23 | 24 | 1. Fill in values for both the bucket name, which you just copied, as well as the region where your CloudFormation template was launched 25 | 26 | 1. Your final structure for the storage configuration of **amplify-config.js** should look like the following. 27 | 28 | ```javascript 29 | Storage: { 30 | bucket: 'wildrydes-profilepicturesbucket-1rmvuic97osxd', 31 | region: 'us-east-1' 32 | } 33 | ``` 34 | -------------------------------------------------------------------------------- /workshop/content/iam_auth/store/_index.en.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Store Profile Pics in Profile" 3 | weight = 55 4 | +++ 5 | 6 | With our image uploads now working, all will work as expected until you close your browser, but at that point the reference between your user profile and your profile picture will be lost. To fix this, you will leverage a Cognito User Pools user attribute called ***picture*** to persist the S3 object key so the same image can be loaded upon each login and persisted to be shown to the unicorns when you request a ride. You will need to update ***/website/src/pages/Profile.js*** and a method called ***onImageLoad*** to make this possible. 7 | 8 | ### High-Level Instructions 9 | 10 | Implement a method to persist the images uploaded to the current user's Cognito ***picture*** attribute each time the image is changed. 11 | 12 | {{% expand "Step-by-step instructions (expand for details)" %}} 13 | 14 | 1. Open your Cloud9 IDE environment and open the file at ***/website/src/pages/Profile.js***. 15 | 16 | 1. The S3Image UI component has a built-in method called ***onImageLoad*** which provides in its invocation the full URL of any image uploaded. We will make use of this built-in function to persist our image URLs out to Cognito. 17 | 18 | 1. Replace the existing ***onImageLoad*** function with the following code: 19 | 20 | ```javascript 21 | async onImageLoad(url) { 22 | if (!this.state.user.getSession) { return }; 23 | console.log('Profile Picture URL:', url); 24 | try { 25 | let result = await Auth.updateUserAttributes(this.state.user, { 26 | 'picture': this.state.image_key 27 | }); 28 | console.log(result); 29 | } catch (ex) { 30 | console.error('Attribute update error:', ex); 31 | } 32 | } 33 | ``` 34 | 1. Now with this new method in place, upload a new photo after logging into Wild Rydes then close your browser. Open a new window and try logging in again. Your photo should load as it did previously. -------------------------------------------------------------------------------- /workshop/content/iam_auth/update/_index.en.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Update application" 3 | weight = 54 4 | +++ 5 | 6 | Now that your IAM policies and Amplify SDK are initialized, you will be able to upload photos and render S3 photos with minimal code using Amplify's built-in UI components. S3 image is the component used to both render image objects for a React application, as well as embeding an image picker to help with uploads. 7 | 8 | ### High-Level Instructions 9 | 10 | Authenticate in the Wild Rydes app if you're not already logged in, then browse to the ***/profile*** path. You will see that your Cognito User Pool attributes are being read dynamically by the system. Next, you will add an [image picker](https://aws-amplify.github.io/docs/js/storage#s3image) from AWS Amplify to render a UI component for uploading and displaying photos stored in S3. These profile photos will be used to personalize the rider experience so unicorns know who to look for when picking up passengers. 11 | 12 | {{% expand "Step-by-step instructions (expand for details)" %}} 13 | 14 | 1. After logging in to Wild Rydes (if you're not authenticated already), browse to the **/profile** path. 15 | 16 | 1. You should see that your e-mail address and phone number you registered with are displayed which are all of your currently populated attributes. 17 | 18 | 1. Open your Cloud9 IDE environment and open the file at ***/website/src/pages/Profile.js***. 19 | 20 | 1. **Uncomment** the line that says ***S3Image***. This instantiates an Amplify UI component for React apps for image rendering and uploading and only requires this single line of code. 21 | 22 | 1. Go back to the Wild Rydes app and visit the **/profile** path after logging in. You should now be able to upload photos with the new image picker. -------------------------------------------------------------------------------- /workshop/content/optional/_index.en.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Optional Fine-grained IAM Authorization" 3 | chapter = true 4 | weight = 40 5 | pre = "2a. " 6 | +++ 7 | 8 | In this optional extension to module 2, you will update your serverless backend for your Wild Rydes application leveraging [Amazon API Gateway](https://aws.amazon.com/api-gateway/) and [AWS Lambda](https://aws.amazon.com/lambda/) to use request signing with IAM-based authorization as a more secure authentication option. 9 | 10 | If you would like to skip this optional extension, you are able to proceed to module 3 directly, IAM-based Authorization. -------------------------------------------------------------------------------- /workshop/content/optional/architecture/_index.en.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Solution Architecture" 3 | weight = 41 4 | +++ 5 | 6 | Building on Module 2, this module updates our Serverless backend built earlier using Amazon API Gateway and AWS Lambda to use IAM-based authorization. This extends our authorization capability to offer fine-grained access control authorizing differently per API operation and enhancing security via request signing. By enabling IAM-based authorization, you will use the same type of authentication, authorization, and request signing used by all AWS services and SDKs. 7 | 8 | [Request signing](https://docs.aws.amazon.com/general/latest/gr/signing_aws_api_requests.html) is a more secure implementation of API request authentication where each API request made is signed with a signature unique to the request itself. Hence, no static API keys or bearer tokens are directly sent to the backend service and any man-in-the-middle attacks would not be able to use such API keys or bearer tokens to impersonate a valid user with the backend resources. AWS APIs and SDKs use a request signing algorithm named [Signature V4 (Sigv4)](https://docs.aws.amazon.com/general/latest/gr/signature-version-4.html) which is what you will enable your API to use in this module. 9 | 10 | > For production APIs, you should use either the token-based authorization OR request signing authorization via IAM demonstrated in this module, but not use both for the same API. 11 | 12 | ![Module 2 architecture](../images/wildrydes-module2-architecture.png) 13 | 14 | --- 15 | #### Implementation Overview 16 | 17 | Each of the following sections provides an implementation overview and detailed, step-by-step instructions. The overview should provide enough context for you to complete the implementation if you're already familiar with the AWS Management Console or you want to explore the services and documentation yourself without following a walkthrough. 18 | 19 | If you're using the latest version of the Chrome, Firefox, or Safari web browsers the step-by-step instructions won't be visible until you expand the section. 20 | -------------------------------------------------------------------------------- /workshop/content/optional/associate/_index.en.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Associate an API Gateway" 3 | weight = 42 4 | +++ 5 | 6 | For us to be able to use request signing and IAM-based fine-grained access control, we'll first need to associate an IAM policy that provides permissions to invoke API operations for your API Gateway deployment. For further details, you can review [controlling access to an API with IAM permissions](https://docs.aws.amazon.com/apigateway/latest/developerguide/permissions.html) documentation. 7 | 8 | ### High-Level Instructions 9 | 10 | In the IAM console, associate the **WildRydesAPI-StandardUserPolicy** with your Cognito Identity Pool's authenticated user role to provide all authenticated users access to invoke operations the **/ride** path. 11 | 12 | {{% expand "Step-by-step instructions (expand for details)" %}} 13 | 14 | 1. Go the AWS Management Console, click **Services** then select **IAM** under Security, Identity, and Compliance. 15 | 16 | 1. Choose **Policies**. 17 | 18 | 1. Search for ***WildRydes*** to see the ***WildRydesAPI-StandardUserPolicy*** which was created by the Serverless Backed CloudFormation template. 19 | 20 | ![WildRydes API IAM Policy Search](../images/iam-policies-wildrydesapi-search.png) 21 | 22 | 1. Click the **WildRydesAPI-StandardUserPolicy** policy name. 23 | 24 | 1. Review the policy which was created by CloudFormation to authorize requests to your API Gateway deployment. 25 | 26 | ![WildRydesAPI Policy Details](../images/iam-wildrydesapi-policy-details.png) 27 | 28 | > This policy allows access to invoke any method on the /ride path for any API stage of your API gateway backend. For more details about authoring IAM policies for API Gateway, visit the controlling access to an API with IAM permissions documentation. 29 | 30 | 1. Choose **Roles**. 31 | 32 | 1. Search for **WildRydes** to find the two roles which were created by Cognito Identity Pools when you created the Identity Pool in module one. Should you not be able to find the roles here, you can alternatively go to the **Cognito Federated Identities** console, find the correct identity pool, then click **Edit Identity Pool** in the top-right corner to see the roles listed. Each identity pool has both an Unauthenticated user role and an Authenticated user role. 33 | 34 | 1. Once you have found the names of the roles, go back to the IAM console and select the Auth role for your authenticated users. 35 | 36 | > If the full name of the role is hidden from view due to column width, you can hover over the partially visible name of the role to see the full name of the role as a tool tip. 37 | 38 | ![IAM WildRydes Auth Role Selction](../images/iam-wildrydes-role-selection.png) 39 | 40 | 1. Choose **Attach policies**. 41 | 42 | 1. Search for `WildRydes` and check the box next to the policy named ***WildRydesAPI-StandardUserPolicy***. 43 | 44 | ![Attach API Gateway IAM Policy](../images/iam-cognito-authrole-attach-apigateway-policy.png) 45 | 46 | 1. Choose **Attach policy**. 47 | 48 | 1. You should now see the ***WildRydesAPI-StandardUserPolicy*** policy associated with your Cognito IAM auth role. 49 | 50 | ![Permissions after adding IAM policy](../images/iam-cognito-authrole-permissions-after-policy-update.png) 51 | 52 | -------------------------------------------------------------------------------- /workshop/content/optional/enable_auth/_index.en.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Enable API Gateway Authorization" 3 | weight = 43 4 | +++ 5 | 6 | In addition to using JSON Web Tokens (JWTs) for authentication, API Gateway can leverage AWS request signing and parse the request signature to determine the requesting user. In this step, you'll update your authorization type to ***IAM*** for your API which will then use AWS's Identity and Access Management (IAM) capabilities to authorize requests via IAM policies. 7 | 8 | ### High-Level Instructions 9 | 10 | In the Amazon API Gateway console, update the authorization type to ***AWS_IAM*** for the ***POST*** method on the ***/ride*** resource. Next, re-deploy the API to make your change take effect. 11 | 12 | {{% expand "Step-by-step instructions (expand for details)" %}} 13 | 14 | 1. In the AWS Management Console choose **Services** then select **API Gateway** under Networking and Content Delivery. 15 | 16 | 1. Choose the API named ***WildRydes***. 17 | 18 | 1. Browse to **Resources** while within your Wild Rydes API in the API Gateway console. 19 | 20 | 1. Select the **POST** method under the ***/ride*** resource path. 21 | 22 | 1. Choose **Method Request** 23 | 24 | ![Method Request Selection](../images/apigateway-method-request-settings.png) 25 | 26 | 1. Choose the pencil icon next to `Authorization` to edit the setting. 27 | 28 | 1. Select **AWS_IAM** from the list of authorization options presented. 29 | 30 | ![API Gateway Authorizer Selection](../images/apigateway-authorizer-iam-selection.png) 31 | 32 | 1. **Save** your selection by clicking the checkmark icon next to the drop down. 33 | 34 | ![API Gateway Authorizer Confirmation](../images/apigateway-authorizer-iam-confirmation.png) 35 | 36 | 1. Next, choose the **Actions** button at the top of the resources list. 37 | 38 | 1. Choose **Deploy API** from the list of options presented. 39 | 40 | 1. For deployment stage, select `prod` then click **Deploy**. 41 | 42 | 1. You've now successfully deployed your new authentication integration to your API's production environment. 43 | 44 | --- 45 | #### Configure your Wild Rydes web app to authenticate API requests 46 | 47 | Now that you've deployed the new authorizer configuration to production, all API requests must be authenticated to be processed. 48 | 49 | 1. Return to your Wild Rydes app, sign in at ***/signin*** if necessary, and attempt to request a ride. 50 | 51 | 1. You should receive an ***Error finding unicorn***. If you open the developer console, you will see that we received a HTTP 401 error, which means it was an unauthorized request. 52 | 53 | > If at first your requests go through without any errors, try requesting a ride again in 30-60 seconds to allow time for the API Gateway changes to fully propagate. 54 | 55 | 1. Go back to Cloud9 and open the ***/website/src/pages/MainApp.js*** files. 56 | 57 | 1. Update your current ***getData*** method to the following method, which removes the ***Authorization*** header and adds debugging information to show us the request signature as requests are sent. The default behavior of the AWS Amplify library is the sign all requests with SigV4 signing when no authorization header is specified, so this will automatically sign all requests using this algorithm without extra development effort. **Save your changes** after making this update. 58 | 59 | ```javascript 60 | async getData(pin) { 61 | Amplify.Logger.LOG_LEVEL = 'DEBUG'; 62 | const apiRequest = { 63 | body: { 64 | PickupLocation: { 65 | Longitude: pin.longitude, 66 | Latitude: pin.latitude 67 | } 68 | }, 69 | headers: { 70 | 'Content-Type': 'application/json' 71 | } 72 | }; 73 | console.log('API Request:', apiRequest); 74 | return await API.post(apiName, apiPath, apiRequest); 75 | } 76 | ``` 77 | 78 | 1. Allow the application to refresh, sign-in again, and request a ride. 79 | 80 | 1. The unicorn ride request should be fulfilled as before now. To see the full request headers which were sent, look at the developer console for an message which includes the API Request details, including the full signature and headers of the request. 81 | 82 | > This message starts with POST /prod/ride then shows the headers of the request made. 83 | 84 | > You may notice that there were both x-amz-date and x-amz-security-token headers sent among other headers. These two headers are part of the overall request signature, along with the Authorization header. 85 | 86 | {{% /expand %}} 87 | 88 | If your API now invokes correctly and application functions as expected summoning unicorns again, you can proceed to the next module, IAM-based Authorization. 89 | -------------------------------------------------------------------------------- /workshop/content/serverless/_index.en.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Serverless API" 3 | chapter = true 4 | weight = 30 5 | pre = "2. " 6 | +++ 7 | 8 | In this module, you will add a serverless backend to your Wild Rydes application leveraging [Amazon API Gateway](https://aws.amazon.com/api-gateway/) and [AWS Lambda](https://aws.amazon.com/lambda/). You will then enable authentication and authorization on your API to secure the backend to only accept valid, authorized requests. -------------------------------------------------------------------------------- /workshop/content/serverless/architecture/_index.en.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Solution Architecture" 3 | weight = 31 4 | +++ 5 | 6 | Building on Module 1, this module will add a Serverless backend built using Amazon API Gateway and AWS Lambda. For persistence, you will use Amazon DynamoDB as a NoSQL data store. All of the above services are serverless so you can seamlessly scale your application as your demands grow. After creating the API, we will integrate our client application to call it via the AWS Amplify library. 7 | 8 | ![Solution Architecture](../images/wildrydes-module2-architecture.png) 9 | 10 | ### Implementation Overview 11 | 12 | Each of the following sections provides an implementation overview and detailed, step-by-step instructions. The overview should provide enough context for you to complete the implementation if you're already familiar with the AWS Management Console or you want to explore the services yourself without following a walkthrough. 13 | 14 | If you're using the latest version of the Chrome, Firefox, or Safari web browsers the step-by-step instructions won't be visible until you expand the section. -------------------------------------------------------------------------------- /workshop/content/serverless/backend/_index.en.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Create Serverless API Backend" 3 | weight = 32 4 | +++ 5 | 6 | You will be creating your Serverless API built with Amazon API Gateway, AWS Lambda, and Amazon DynamoDB via a CloudFormation template. Since this workshop is focused on authentication and authorization, this template will create the backend infrastructure, but not enable any security settings and the rest of the module will enable and configure such settings. 7 | 8 | ### High-Level Instructions 9 | 10 | Create a new WildRydes Serverless Backend stack by launching a CloudFormation stack based on the ***ServerlessBackend.yaml*** file in the module 2 folder. Name the stack `WildRydesBackend`. 11 | 12 | This WildRydes backend CloudFormation template will provision your API Gateway deployment with Lambda functions for compute, a DynamoDB database for persistence, and an S3 bucket for photo uploads which will be used in module 3. Additionally, the necessary function invocation permissions and execution role for the Lambda function will also be provisioned. 13 | 14 | Click on the link for the region you have chosen: 15 | {{< tabs name="Region" >}} 16 | {{{< tab name="N. Virginia (us-east-1)" include="us-east-1.md" />}} 17 | {{{< tab name="Ohio (us-east-2)" include="us-east-2.md" />}} 18 | {{{< tab name="Oregon (us-west-2)" include="us-west-2.md" />}} 19 | {{{< tab name="Ireland (eu-west-1)" include="eu-west-1.md" />}} 20 | {{{< tab name="Singapore (ap-southeast-1)" include="ap-southeast-1.md" />}} 21 | {{< /tabs >}} 22 | 23 | {{% expand "Step-by-step instructions (expand for details)" %}} 24 | 25 | 1. Launch the CloudFormation stack from the links above, choosing the link appropriate for the region you selected for this workshop. **Be sure to select the same region as you were using previously in this workshop to launch this CloudFormation stack** 26 | 27 | 1. On the next screen, Step 2, confirm the stack name is `WildRydesBackend` and click ***Next***. 28 | 29 | 1. On the Configure Stack Options page, accept all the defaults and click ***Next***. 30 | 31 | 1. Choose to ***Acknowledge that the CloudFormation template may create IAM resources with custom names***. Finally, click ***Create stack***. 32 | 33 | 1. It will take a few minutes for the Stack to create. Choose the ***Stack Info*** tab to go to the overall stack status page and wait until the stack is fully launched and shows a status of **CREATE_COMPLETE**. Click the refresh icon to see progress updates. 34 | 35 | 1. With the **WildRydesBackend** stack selected, click on the ***Outputs*** tab and copy the value shown for the **WildRydesApiInvokeUrl** to your Cloud9 scratchpad editor tab. -------------------------------------------------------------------------------- /workshop/content/serverless/backend/ap-southeast-1.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Singapore" 3 | chapter = false 4 | disableToc = true 5 | hidden = true 6 | +++ 7 | 8 | Launch Serverless API backend in ap-southeast-1: [![Launch Module in ap-southeast-1](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/images/cloudformation-launch-stack-button.png)][Launch ap-southeast-1] 9 | 10 | [Launch ap-southeast-1]: https://console.aws.amazon.com/cloudformation/home?region=ap-southeast-1#/stacks/new?stackName=WildRydesBackend&templateURL={{%siteparam "artifactURLPrefix" %}}/ServerlessBackend.yaml 11 | -------------------------------------------------------------------------------- /workshop/content/serverless/backend/eu-west-1.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Ireland" 3 | chapter = false 4 | disableToc = true 5 | hidden = true 6 | +++ 7 | 8 | Launch Serverless API backend in eu-west-1: [![Launch Module in eu-west-1](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/images/cloudformation-launch-stack-button.png)][Launch eu-west-1] 9 | 10 | [Launch eu-west-1]: https://console.aws.amazon.com/cloudformation/home?region=eu-west-1#/stacks/new?stackName=WildRydesBackend&templateURL={{%siteparam "artifactURLPrefix" %}}/ServerlessBackend.yaml 11 | -------------------------------------------------------------------------------- /workshop/content/serverless/backend/us-east-1.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "N. Virginia" 3 | chapter = false 4 | disableToc = true 5 | hidden = true 6 | +++ 7 | 8 | Launch Serverless API backend in us-east-1: [![Launch Module in us-east-1](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/images/cloudformation-launch-stack-button.png)][Launch us-east-1] 9 | 10 | [Launch us-east-1]: https://console.aws.amazon.com/cloudformation/home?region=us-east-1#/stacks/new?stackName=WildRydesBackend&templateURL={{%siteparam "artifactURLPrefix" %}}/ServerlessBackend.yaml 11 | -------------------------------------------------------------------------------- /workshop/content/serverless/backend/us-east-2.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Ohio" 3 | chapter = false 4 | disableToc = true 5 | hidden = true 6 | +++ 7 | 8 | Launch Serverless API backend in us-east-2: [![Launch Module in us-east-2](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/images/cloudformation-launch-stack-button.png)][Launch us-east-2] 9 | 10 | [Launch us-east-2]: https://console.aws.amazon.com/cloudformation/home?region=us-east-2#/stacks/new?stackName=WildRydesBackend&templateURL={{%siteparam "artifactURLPrefix" %}}/ServerlessBackend.yaml 11 | -------------------------------------------------------------------------------- /workshop/content/serverless/backend/us-west-2.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Oregon" 3 | chapter = false 4 | disableToc = true 5 | hidden = true 6 | +++ 7 | 8 | Launch Serverless API backend in us-west-2: [![Launch Module in us-west-2](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/images/cloudformation-launch-stack-button.png)][Launch us-west-2] 9 | 10 | [Launch us-west-2]: https://console.aws.amazon.com/cloudformation/home?region=us-west-2#/stacks/new?stackName=WildRydesBackend&templateURL={{%siteparam "artifactURLPrefix" %}}/ServerlessBackend.yaml 11 | -------------------------------------------------------------------------------- /workshop/content/serverless/integration/_index.en.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Integrate API into Wild Rydes" 3 | weight = 33 4 | +++ 5 | 6 | Now that you have created our Serverless API, you need to update your Wild Rydes web application to integrate with it. You will leverage the AWS Amplify client library to make API calls and inject security seamlessly to support your authentication and authorization scenarios. 7 | 8 | ### High-Level Instructions 9 | 10 | First, expand your **amplify-config.js** file to store your new API Gateway endpoint. Next, within **MainApp.js** under pages, enable the **hasAPI** method by uncommenting its functionality. Additionally, update the **getData** method to capture the latitude and longitude selected on the map and send to the API as a PickupLocation object including both the latitude and longitude. 11 | 12 | {{% expand "Step-by-step instructions (expand for details)" %}} 13 | 14 | 1. First, you need to update the **/website/src/amplify-config.js** file to include your new API Gateway endpoint. Store the endpoint including the /prod at the end in the endpoint property under the **WildRydesAPI** section. 15 | 16 | > Do not change the name `WildRydesAPI` in this configuration file or later functionality in the workshop will not work. An example of the API configuration portion of the amplify-config file after updating the configuration properly is shown below: 17 | 18 | ```javascript 19 | API: { 20 | endpoints: [ 21 | { 22 | name: 'WildRydesAPI', 23 | endpoint: 'https://1ngrgqjt6c.execute-api.us-east-1.amazonaws.com/prod', 24 | region: 'us-east-1' 25 | } 26 | ] 27 | }, 28 | ``` 29 | 30 | 1. Next, you need to enable the hasAPI method by uncommenting its code within **/website/src/pages/MainApp.js**. 31 | 32 | ```javascript 33 | hasApi() { 34 | const api = awsConfig.API.endpoints.filter(v => v.endpoint !== ''); 35 | return (typeof api !== 'undefined'); 36 | } 37 | ``` 38 | 39 | 1. Finally, within the same file, we will implement the API request for a ride as a POST request to our API which sends a body containing the requested latitude and longitude as the pickup location. Update the **getData()** method to be as follows: 40 | 41 | ```javascript 42 | async getData(pin) { 43 | const apiRequest = { 44 | body: { 45 | PickupLocation: { 46 | Longitude: pin.longitude, 47 | Latitude: pin.latitude 48 | } 49 | }, 50 | headers: { 51 | 'Authorization': '', // To be updated 52 | 'Content-Type': 'application/json' 53 | } 54 | }; 55 | console.log('API Request:', apiRequest); 56 | return await API.post(apiName, apiPath, apiRequest); 57 | } 58 | ``` 59 | -------------------------------------------------------------------------------- /workshop/content/serverless/validation/_index.en.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Validate API Functionality" 3 | weight = 34 4 | +++ 5 | 6 | Now that you've integrated code changes to call your new Serverless API, you should test the end-to-end user experience to ensure the application is working correctly. The API currently requires no authentication so any request will currently be accepted until we enable required authentication. 7 | 8 | ### High-Level Instructions 9 | 10 | Go back to your browser tab with Wild Rydes running and sign-in again at `/signin`. Once signed in, click anywhere on the map to indicate a pickup location, then select the ***Request*** button to call your ride. 11 | 12 | You should be informed of your unicorn's arrival momentarily. -------------------------------------------------------------------------------- /workshop/content/setup/_index.en.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Setup" 3 | date = 2020-03-04 4 | chapter = true 5 | weight = 10 6 | pre = "0. " 7 | +++ 8 | 9 | ### AWS Account 10 | 11 | In order to complete this workshop, you'll need an AWS account and access to create and manage AWS resources that are used in this workshop, including Cloud9, Cognito, API Gateway, Lambda, DynamoDB and IAM policies and roles. 12 | _The IAM user/role used for this workshop will require administrative and IAM full access permissions._ 13 | 14 | If you currently don't have an AWS account, you can create one here: [https://aws.amazon.com/premiumsupport/knowledge-center/create-and-activate-aws-account](https://aws.amazon.com/premiumsupport/knowledge-center/create-and-activate-aws-account) 15 | -------------------------------------------------------------------------------- /workshop/content/setup/cloud9/_index.en.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Create a Cloud9 Workspace" 3 | weight = 13 4 | +++ 5 | 6 | {{% notice tip %}} 7 | Ad blockers, javascript disablers, and tracking blockers should be disabled for 8 | the cloud9 domain, or connecting to the workspace might be impacted. 9 | Cloud9 requires third-party-cookies. You can whitelist the [specific domains]( https://docs.aws.amazon.com/cloud9/latest/user-guide/troubleshooting.html#troubleshooting-env-loading). 10 | {{% /notice %}} 11 | 12 | ### AWS Cloud9 IDE 13 | 14 | [AWS Cloud9](https://aws.amazon.com/cloud9/) is a cloud-based integrated development environment (IDE) that lets you write, run, and debug code from any machine with just a browser. It includes a code editor, debugger and terminal. Cloud9 comes pre-packaged with essential tools for popular programming languages and the AWS Command Line Interface (CLI) pre-installed so you don't need to install files or configure your laptop for this workshop. 15 | 16 | ### Launch Cloud9 IDE 17 | 18 | In this section you will launch a CloudFormation stack that will create a new [AWS VPC](https://aws.amazon.com/vpc) environment and a [Cloud9 IDE](https://aws.amazon.com/cloud9) instance that you will use in the rest of the workshop. 19 | 20 | Click on the link for the region you have chosen: 21 | {{< tabs name="Region" >}} 22 | {{{< tab name="N. Virginia (us-east-1)" include="us-east-1.md" />}} 23 | {{{< tab name="Ohio (us-east-2)" include="us-east-2.md" />}} 24 | {{{< tab name="Oregon (us-west-2)" include="us-west-2.md" />}} 25 | {{{< tab name="Ireland (eu-west-1)" include="eu-west-1.md" />}} 26 | {{{< tab name="Singapore (ap-southeast-1)" include="ap-southeast-1.md" />}} 27 | {{< /tabs >}} 28 | 29 | {{%expand "Step-by-step instructions (expand to see)" %}} 30 | 31 | 1. Launch the CloudFormation stack from the links above, choosing the link appropriate for the region you selected for this workshop. 32 | 33 | 2. On the next screen, Step 2, confirm the stack name is `WildRydes-Cloud9` and click **Next**. 34 | 35 | 3. On the Configure Stack Options page, accept all the defaults and click **Next**. 36 | 37 | 4. On the Review page, review the summary details then click **Create stack**. 38 | 39 | 5. It will take a few minutes for the stack to create. Choose the **Stack Info** tab to go to the overall stack status page and wait until the stack is fully launched and shows a status of *CREATE_COMPLETE*. Click the refresh icon periodically to see progress update. 40 | 41 | 6. With the *WildRydes-Cloud9* stack selected, click on the **Outputs** tab and copy the value shown for the *Cloud9IDE* to the clipboard. Browse to that URL in a new browser tab to load your IDE environment. 42 | 43 | > Note: When you launch the stack, CloudFormation deploys a nested CloudFormation stack to launch the Cloud9 resources. You can safely ignore that template which is prefixed with "aws-cloud9-WildRydes-". 44 | 45 | ![cloudformation outputs](../images/cloud9_cfn_outputs.png) 46 | 47 | {{% /expand%}} 48 | 49 | Once you have launched and navigated to your Cloud9 workspace URL shown in your CloudFormation stack outputs, you should have an IDE environment as shown below: 50 | 51 | ![cloud9 environment](../images/cloud9_initial_screen.png) 52 | -------------------------------------------------------------------------------- /workshop/content/setup/cloud9/ap-southeast-1.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Singapore" 3 | chapter = false 4 | disableToc = true 5 | hidden = true 6 | +++ 7 | 8 | Create a Cloud9 environment in ap-southeast-1: [![Launch Module in ap-southeast-1](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/images/cloudformation-launch-stack-button.png)][Launch ap-southeast-1] 9 | 10 | [Launch ap-southeast-1]: https://console.aws.amazon.com/cloudformation/home?region=ap-southeast-1#/stacks/new?stackName=WildRydes-Cloud9&templateURL=https://s3.amazonaws.com/wildrydes-ap-southeast-1/Auth/0_GettingStarted/Cloud9WithNewVPC.yaml 11 | -------------------------------------------------------------------------------- /workshop/content/setup/cloud9/eu-west-1.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Ireland" 3 | chapter = false 4 | disableToc = true 5 | hidden = true 6 | +++ 7 | 8 | Create a Cloud9 environment in eu-west-1: [![Launch Module in eu-west-1](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/images/cloudformation-launch-stack-button.png)][Launch eu-west-1] 9 | 10 | [Launch eu-west-1]: https://console.aws.amazon.com/cloudformation/home?region=eu-west-1#/stacks/new?stackName=WildRydes-Cloud9&templateURL=https://s3.amazonaws.com/wildrydes-eu-west-1/Auth/0_GettingStarted/Cloud9WithNewVPC.yaml 11 | -------------------------------------------------------------------------------- /workshop/content/setup/cloud9/us-east-1.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "N. Virginia" 3 | chapter = false 4 | disableToc = true 5 | hidden = true 6 | +++ 7 | 8 | Create a Cloud9 environment in us-east-1: [![Launch Module in us-east-1](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/images/cloudformation-launch-stack-button.png)][Launch us-east-1] 9 | 10 | [Launch us-east-1]: https://console.aws.amazon.com/cloudformation/home?region=us-east-1#/stacks/new?stackName=WildRydes-Cloud9&templateURL={{%siteparam "artifactUrlPrefix" %}}/Cloud9WithNewVPC.yaml 11 | -------------------------------------------------------------------------------- /workshop/content/setup/cloud9/us-east-2.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Ohio" 3 | chapter = false 4 | disableToc = true 5 | hidden = true 6 | +++ 7 | 8 | Create a Cloud9 environment in us-east-2: [![Launch Module in us-east-2](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/images/cloudformation-launch-stack-button.png)][Launch us-east-2] 9 | 10 | [Launch us-east-2]: https://console.aws.amazon.com/cloudformation/home?region=us-east-2#/stacks/new?stackName=WildRydes-Cloud9&templateURL=https://s3.amazonaws.com/wildrydes-us-east-2/Auth/0_GettingStarted/Cloud9WithNewVPC.yaml 11 | -------------------------------------------------------------------------------- /workshop/content/setup/cloud9/us-west-2.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Oregon" 3 | chapter = false 4 | disableToc = true 5 | hidden = true 6 | +++ 7 | 8 | Create a Cloud9 environment in us-west-2: [![Launch Module in us-west-2](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/images/cloudformation-launch-stack-button.png)][Launch us-west-2] 9 | 10 | [Launch us-west-2]: https://console.aws.amazon.com/cloudformation/home?region=us-west-2#/stacks/new?stackName=WildRydes-Cloud9&templateURL=https://s3.amazonaws.com/wildrydes-us-west-2/Auth/0_GettingStarted/Cloud9WithNewVPC.yaml 11 | -------------------------------------------------------------------------------- /workshop/content/setup/setupc9/_index.en.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Setup Cloud9 Workspace" 3 | weight = 14 4 | +++ 5 | 6 | In the ***bash*** terminal in Cloud9, you can run AWS CLI commands just like you would on your local computer. Verify that your user is logged in by running the following: 7 | ```plaintext 8 | aws sts get-caller-identity 9 | ``` 10 | 11 | You should see output indicating your account and user information: 12 | 13 | ```JSON 14 | { 15 | "Account": "123456789012", 16 | "UserId": "AKIAI44QH8DHBEXAMPLE", 17 | "Arn": "arn:aws:iam::123456789012:user/Alice" 18 | } 19 | ``` 20 | 21 | Keep your AWS Cloud9 IDE opened in a tab throughout this workshop as you'll be using it for most activities. 22 | 23 | ### Expand Cloud9 storage 24 | 25 | In order to accomodate dependencies, the underlying drive has already been expanded and we only need to increase the partition size with these 2 commands: 26 | 27 | ```plaintext 28 | sudo growpart /dev/xvda 1 29 | sudo resize2fs /dev/xvda1 30 | ``` 31 | 32 | ### Download Workshop Code 33 | 34 | Download the WildRydes website artifacts to your Cloud9 IDE environment by running the following command in the Cloud9 terminal window: 35 | 36 | ```plaintext 37 | curl -O {{% siteparam "artifactUrlPrefix" %}}/website.tar.gz 38 | tar xvf website.tar.gz 39 | ``` 40 | 41 | ### Initialize your developer workspace 42 | 43 | 1. Run the following commands to upgrade your Node.js version to the latest version of Node.js 10. The [AWS Amplify](https://aws-amplify.github.io/) Javascript library which we will be using requires Node.js 10 or higher. 44 | 45 | ```plaintext 46 | nvm i 16 47 | nvm alias default 16 48 | ``` 49 | 50 | 2. Install the yarn package manager and website dependencies by running the following commands: 51 | 52 | ```plaintext 53 | npm install -g yarn 54 | cd ~/environment/website/ 55 | yarn install 56 | ``` 57 | 58 | {{% notice tip %}} 59 | Keep an open scratch pad in Cloud9 or a text editor on your local computer for notes. When the step-by-step directions tell you to note something such as an ID or Amazon Resource Name (ARN), copy and paste that into the scratch pad tab. 60 | {{% /notice %}} 61 | 62 | -------------------------------------------------------------------------------- /workshop/content/user_auth/_index.en.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "User Authentication" 3 | chapter = true 4 | weight = 20 5 | pre = "1. " 6 | +++ 7 | 8 | In this module, you will create an Amazon Cognito User Pool and Identity Pool for the Wild Rydes application. The Cognito User Pool will store user profile information and provide sign-up and sign-in capabilities, with the Cognito Identity Pool providing the ability to assume an Identity and Access Management (IAM) role from within the application. 9 | 10 | Since Wild Rydes is a ride sharing application, a key requirement is that all users must sign-up and sign-in before they're allowed to request a ride. You will configure the application to integrate with [Amazon Cognito](https://aws.amazon.com/cognito/) for these purposes via the [AWS Amplify](https://aws-amplify.github.io/) JavaScript library. -------------------------------------------------------------------------------- /workshop/content/user_auth/architecture/_index.en.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Solution Architecture" 3 | weight = 21 4 | +++ 5 | 6 | The architecture for this module is very straightforward. All of your static web content including HTML, CSS, JavaScript, images and other files will be served locally from your Cloud9 workspace. As you make changes to the website application code, all changes will be automatically updated and shown in your browser via live reload capabilities. 7 | 8 | For this module, we will be creating a Cognito User Pool as our secure user directory then configuring our application to use the AWS Amplify library to easily integrate Amazon Cognito into our application. 9 | 10 | ![Module 1 Architecture](../images/wildrydes-module1-architecture.png) 11 | 12 | ### Implementation Overview 13 | 14 | Each of the following sections provides an implementation overview and detailed, step-by-step instructions. The high-level overview should provide context for you to complete the implementation yourself if you're comfortable with the AWS Management Console and are comfortable exploring the services and documentation yourself without following a walkthrough. 15 | 16 | If you're using the latest version of the Chrome, Firefox, or Safari web browsers the step-by-step instructions won't be visible until you expand the section. 17 | 18 | -------------------------------------------------------------------------------- /workshop/content/user_auth/identity_pool/_index.en.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Creating a Cognito Identity Pool" 3 | weight = 24 4 | +++ 5 | 6 | Cognito Identity Pools are used to provide AWS credentials via IAM roles to end-user applications. Since we'll be integrating our Cognito deployment and users with other AWS services, we'll go ahead and create this identity pool now. 7 | 8 | ### High-Level Instructions 9 | 10 | You will need to create a Cognito Identity Pool linked to the Cognito User Pool and app client ID you just created. Your application will not require un-authenticated users to access any AWS resources, so you do not need to enable access to unauthenticated identities. 11 | 12 | {{%expand "Step-by-step instructions (expand for details)" %}} 13 | 14 | 1. In the Cognito console, choose **Federated Identities** in the header bar to switch to the console for Cognito Federated Identities. 15 | 16 | 2. Choose **Create new identity pool**. 17 | 18 | 3. Input `wildrydes_identity_pool` as the Identity pool name. 19 | 20 | 4. Expand **Authentication providers**. 21 | 22 | 5. Within the Cognito tab, input the User Pool ID and App client Id you copied previously to the scratchpad tab. 23 | 24 | ![Create Identity Pool](../images/cognito-identitypool-setup-step1.png) 25 | 26 | 6. Choose **Create Pool**. 27 | 28 | 7. Choose **Allow** to allow Cognito Identity Pools to setup IAM roles for your application's users. Permissions and settings of these roles can be customized later. 29 | 30 | 8. Copy/paste the ***Identity Pool ID***, highlighted in red within the code sample in the Get AWS Credentials section, into your Cloud9 scatchpad editor tab. 31 | 32 | > Do not copy the quatation marks, but include the region code and ":" character. 33 | 34 | ![Get AWS Credentials](../images/cognito-identitypool-copyId.png) 35 | 36 | 9. Your scratchpad should now have values for the following Cognito resources: 37 | 38 | ![Cognito scratchpad](../images/cognito-setup-scratchpad.png) 39 | 40 | {{% /expand %}} -------------------------------------------------------------------------------- /workshop/content/user_auth/local_web/_index.en.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Running the website locally" 3 | chapter = false 4 | weight = 22 5 | +++ 6 | 7 | 1. From your Cloud9 workspace, select the terminal window and when you are within your ***~/environment/website/*** directory, run the following command to start the local web server 8 | 9 | ```bash 10 | yarn start 11 | ``` 12 | 13 | Wait for the development server to start. You can ignore any message saying ***Compiled with warnings*** as we will resolve these warnings as we add our functionality to the application. 14 | 15 | 2. Now that the development server has started, click **Preview Running Application** in the top of the screen next to the Run button. 16 | 17 | ![Preview Running Application](../images/cloud9-local-preview.png) 18 | 19 | 3. The web application will load in a small window next to the terminal at the bottom of the Cloud9 IDE. Click the **re-size** button next to the word **Browser** to open this window in a new tab. 20 | 21 | ![resize button](../images/cloud9-resize-live-preview.png) 22 | 23 | As you make changes to the web application, this tab will automatically refresh to reflect your changes. Leave this tab open and return to the Cloud9 IDE tab to continue the workshop. 24 | 25 | Though the Wild Rydes website may look functional, there is currently no integration for sign-up or sign-in requests to go anywhere. 26 | -------------------------------------------------------------------------------- /workshop/content/user_auth/user_pool/_index.en.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Creating Cognito User Pool" 3 | chapter = false 4 | weight = 23 5 | +++ 6 | 7 | Amazon Cognito User Pools lets you add user sign-up and sign-in capabilities to your web and mobile apps quickly and easily. In this step, we'll create a Cognito user pool for our Wild Rydes app. 8 | 9 | ### High-Level Instructions 10 | 11 | Use the AWS console to create an Amazon Cognito User Pool requiring e-mail verification 12 | 13 | {{% notice tip%}} 14 | The console's region will default to the last region you were using previously. Change this to the same region where you launched your Cloud9 environment previously. 15 | {{% /notice %}} 16 | 17 | {{% expand "Step-by-Step instructions (expand for details)" %}} 18 | 1. In the AWS Management Console choose **Services** then select **Cognito** under Security, Identity, and Compliance. 19 | 20 | 2. Choose your desired **Region** in top-right of the console if not already selected. This should match the region where you launched your Cloud9 environment previously. 21 | 22 | 3. Choose **Create User Pool**. 23 | 24 | ![User Pool Configuration](../images/cognito-create-user-pool.png) 25 | 26 | 4. Under **Cognito user pool sign-in options**, check User name, Email, and Phone Number checkboxes, then select **Next**. 27 | 28 | 5. Leave the Password Policy defaults, then scroll down to Multi-factor authentication and select **No MFA**. 29 | 30 | ![User Pool MFA Options](../images/cognito-mfa-options.png) 31 | 32 | 6. Leave all other defaults settings, then select **Next**. 33 | 34 | 7. On the **Configure sign-up experience** page, leave all defaults and select **Next**. 35 | 36 | 8. On the **Configure message delivery** page, select **Send email with Cognito**. 37 | 38 | ![Cognito Message Delivery](../images/cognito-message-delivery.png) 39 | 40 | 9. Scroll down to the **SMS** section, then select **Create a new IAM role** and enter **wildrydes-cognito-messages** for the IAM role name. Then select **Next**. 41 | 42 | ![Cognito Messages IAM Role](../images/cognito-wildrydes-messages.png) 43 | 44 | 10. Next, enter `WildRydes` as the **User pool name**. 45 | 46 | 11. Next, scroll down to the **Initial app client** section and leave Public client selected. For App client name, enter `wildrydes-web-app`. 47 | 48 | 12. Make sure **Don't generate a client secret** is selected, then click **Next** 49 | 50 | 13. Review the summary of all provided settings for accuracy then choose **Create user pool**. 51 | 52 | 14. Within Cloud9, click the + symbol and choose to create **New File**. You will use this new blank editor tab as a scratchpad for various resource names and variables. 53 | 54 | ![Cloud9 Scratchpad](../images/cloud9-createscratchpadtab.png) 55 | 56 | 15. Back in the AWS Cognito console, copy your new User Pool Id into the scratchpad tab. 57 | 58 | ![Cognito Pool ID](../images/cognito-userpool-copy-userpool-id.png) 59 | 60 | 16. Click the **App Integration** tab and scroll all the way down to the bottom. Then copy the Client ID into the scratch tab. 61 | 62 | ![Cognito App Clients](../images/cognito-app-clients.png) 63 | 64 | 17. Copy the ***App client ID*** over to your scratchpad. You will be using both of these values later on. 65 | 66 | ![Cognito App Client ID](../images/cognito-userpool-copy-appclient-id.png) 67 | 68 | {{% /expand %}} -------------------------------------------------------------------------------- /workshop/content/user_auth/validation/_index.en.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "Validating sign-up and sign-in" 3 | weight = 26 4 | +++ 5 | 6 | Now that you have integrated our Amplify code into our application, you need to test the site to see that authentication is working end-to-end. 7 | 8 | ### High-Level Instructions 9 | 10 | Return to your browser tab where you started your Wild Rydes application earlier after popping out from the Cloud9 IDE once in preview mode. This page automatically refreshes after you save any code changes so should now reflect all of your changes and be ready for testing. 11 | 12 | Visit the ***/register*** path to sign-up as a new user, providing a valid phone number with `+country_code` first preceeding the number. For a US-based phone number, an example would be `+14251234567`. You should then see that a verification message is sent with a one-time code upon registering, which is required before you're able to sign-in. 13 | 14 | After signing up as a new user, sign-in with the same user at the ***/signin*** path. If the page loads a map, sign-in was successful and you have successfully integrated Cognito for app authentication. 15 | 16 | {{% expand "Step-by-step instructions (expand for details)" %}} 17 | 18 | 1. Visit `/register` path of your Cloud9's website to go to the registration page. 19 | 20 | 2. Input your e-mail address, phone number with `+country_code` first preceeding the number, as well as your password twice. For a US-based phone number, an example would be `+14251234567`. 21 | 22 | > Your password must include 8 characters, including uppercase and lowercase characters, and at least 1 number and 1 special character. 23 | 24 | 3. Choose **Let's Ryde** to submit registration. 25 | 26 | 4. On the verify e-mail screen, enter the one-time code sent to your e-mail address provided then choose **Verify**. 27 | 28 | > Be sure to check your spam folder for the e-mail with your verification code if you do not see it in your inbox. 29 | 30 | 5. Assuming no errors were encountered, you will be redirected to the Sign-in screen. Now, re-enter the same e-mail address and password you chose at registration. 31 | 32 | 6. If the page then loads a map, sign-in was successful and you have successfully integrated Cognito for app authentication. 33 | 34 | 7. Optionally, you may scroll down beyond the map to copy your user's identity token and decode it by pasting it into the 'encoded' input box at [JWT.io](http://jwt.io/). You will see all of your user's attributes are encoded within the token, along with other standard attributes such as the time the token was issued, the time the token expires, the user's unique ID, and more. 35 | 36 | -------------------------------------------------------------------------------- /workshop/layouts/partials/favicon.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /workshop/layouts/partials/header.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | {{ .Hugo.Generator }} 11 | {{ partial "meta.html" . }} 12 | {{ partial "favicon.html" . }} 13 | {{ .Title }} :: {{ .Site.Title }} 14 | 15 | {{ $assetBusting := not .Site.Params.disableAssetsBusting }} 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | {{with .Site.Params.themeVariant}} 27 | 28 | {{end}} 29 | 30 | 31 | 32 | 35 | 45 | {{ partial "custom-header.html" . }} 46 | 47 | 48 | 49 | {{ partial "menu.html" . }} 50 |
    51 |
    52 |
    53 | {{if not .IsHome}} 54 |
    55 |
    56 | {{ if and (or .IsPage .IsSection) .Site.Params.editURL }} 57 | {{ $File := .File }} 58 | {{ $Site := .Site }} 59 | {{with $File.Path }} 60 | 67 | {{ end }} 68 | {{ end }} 69 | {{$toc := (and (not .Params.disableToc) (not .Params.chapter))}} 70 | 83 | {{ if $toc }} 84 | {{ partial "toc.html" . }} 85 | {{ end }} 86 |
    87 |
    88 | {{ end }} 89 | 90 | {{ if .Params.chapter }} 91 |
    92 | {{ end }} 93 |
    94 |

    {{.Title}}

    95 | 96 | {{define "breadcrumb"}} 97 | {{$parent := .page.Parent }} 98 | {{ if $parent }} 99 | {{ $value := (printf "%s > %s" $parent.Permalink $parent.Title .value) }} 100 | {{ template "breadcrumb" dict "page" $parent "value" $value }} 101 | {{else}} 102 | {{.value|safeHTML}} 103 | {{end}} 104 | {{end}} 105 | -------------------------------------------------------------------------------- /workshop/layouts/partials/logo.html: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /workshop/layouts/partials/menu-footer.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | GitHub 5 | 6 | 7 |

    8 | 9 | Privacy | Site Terms | © 2020, Amazon Web Services, Inc. or its affiliates. All rights reserved. 10 | 11 | -------------------------------------------------------------------------------- /workshop/layouts/shortcodes/tab.html: -------------------------------------------------------------------------------- 1 | {{ if .Parent }} 2 | {{ $name := trim (.Get "name") " " }} 3 | {{ $include := trim (.Get "include") " "}} 4 | {{ $codelang := .Get "codelang" }} 5 | {{ if not (.Parent.Scratch.Get "tabs") }} 6 | {{ .Parent.Scratch.Set "tabs" slice }} 7 | {{ end }} 8 | {{ with .Inner }} 9 | {{ if $codelang }} 10 | {{ $.Parent.Scratch.Add "tabs" (dict "name" $name "content" (highlight . $codelang "") ) }} 11 | {{ else }} 12 | {{ $.Parent.Scratch.Add "tabs" (dict "name" $name "content" . ) }} 13 | {{ end }} 14 | {{ else }} 15 | {{ $.Parent.Scratch.Add "tabs" (dict "name" $name "include" $include "codelang" $codelang) }} 16 | {{ end }} 17 | {{ else }} 18 | {{- errorf "[%s] %q: tab shortcode missing its parent" .Page.Site.Language.Lang .Page.Path -}} 19 | {{ end}} 20 | -------------------------------------------------------------------------------- /workshop/layouts/shortcodes/tabs.html: -------------------------------------------------------------------------------- 1 | {{ .Page.Scratch.Add "tabset-counter" 1 }} 2 | {{ $tab_set_id := .Get "name" | default (printf "tabset-%s-%d" (.Page.RelPermalink) (.Page.Scratch.Get "tabset-counter") ) | anchorize }} 3 | {{ $tabs := .Scratch.Get "tabs" }} 4 | {{ if .Inner }}{{/* We don't use the inner content, but Hugo will complain if we don't reference it. */}}{{ end }} 5 |
    6 |
      7 | {{ range $i, $e := $tabs }} 8 | {{ $id := printf "%s-%d" $tab_set_id $i }} 9 |
    • {{ trim .name " " }}
    • 10 | {{ end }} 11 |
    12 | {{ range $i, $e := $tabs }} 13 | {{ $id := printf "%s-%d" $tab_set_id $i }} 14 |
    15 | {{ with .content }} 16 | {{ . }} 17 | {{ else }} 18 | {{ if eq $.Page.BundleType "leaf" }} 19 | {{/* find the file somewhere inside the bundle. Note the use of double asterisk */}} 20 | {{ with $.Page.Resources.GetMatch (printf "**%s*" .include) }} 21 | {{ if ne .ResourceType "page" }} 22 | {{/* Assume it is a file that needs code highlighting. */}} 23 | {{ $codelang := $e.codelang | default ( path.Ext .Name | strings.TrimPrefix ".") }} 24 | {{ highlight .Content $codelang "" }} 25 | {{ else}} 26 | {{ .Content }} 27 | {{ end }} 28 | {{ end }} 29 | {{ else}} 30 | {{ $path := path.Join $.Page.Dir .include }} 31 | {{ $page := $.Page.Site.GetPage "page" $path }} 32 | {{ with $page }} 33 | {{ .Content }} 34 | {{ else }} 35 | {{ errorf "[%s] tabs include not found for path %q" $.Page.Site.Language.Lang $path}} 36 | {{ end }} 37 | {{ end }} 38 | {{ end }} 39 |
    40 | {{ end }} 41 |
    42 | {{ $elem := $tab_set_id | safeJS }} 43 | 44 | -------------------------------------------------------------------------------- /workshop/static/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/workshop/static/.DS_Store -------------------------------------------------------------------------------- /workshop/static/css/theme-mine.css: -------------------------------------------------------------------------------- 1 | 2 | :root{ 3 | 4 | --MAIN-TEXT-color:#323235; /* Color of text by default */ 5 | --MAIN-TITLES-TEXT-color: #778ba5; /* Color of titles h2-h3-h4-h5 */ 6 | --MAIN-LINK-color:#4881cd; /* Color of links */ 7 | --MAIN-LINK-HOVER-color:#599af1; /* Color of hovered links */ 8 | --MAIN-ANCHOR-color: #4881cd; /* color of anchors on titles */ 9 | 10 | --MENU-HEADER-BG-color:#283e5b; /* Background color of menu header */ 11 | --MENU-HEADER-BORDER-color:#435c7c; /*Color of menu header border */ 12 | 13 | --MENU-SEARCH-BG-color:#202c3c; /* Search field background color (by default borders + icons) */ 14 | --MENU-SEARCH-BOX-color: #4d6584; /* Override search field border color */ 15 | --MENU-SEARCH-BOX-ICONS-color: #4d6584; /* Override search field icons color */ 16 | 17 | --MENU-SECTIONS-ACTIVE-BG-color:#0a0c0e; /* Background color of the active section and its childs */ 18 | --MENU-SECTIONS-BG-color:#1c222a; /* Background color of other sections */ 19 | --MENU-SECTIONS-LINK-color: #ccc; /* Color of links in menu */ 20 | --MENU-SECTIONS-LINK-HOVER-color: #e6e6e6; /* Color of links in menu, when hovered */ 21 | --MENU-SECTION-ACTIVE-CATEGORY-color: #777; /* Color of active category text */ 22 | --MENU-SECTION-ACTIVE-CATEGORY-BG-color: #fff; /* Color of background for the active category (only) */ 23 | 24 | --MENU-VISITED-color: #33a1ff; /* Color of 'page visited' icons in menu */ 25 | --MENU-SECTION-HR-color: #20272b; /* Color of
    separator in menu */ 26 | 27 | } 28 | 29 | body { 30 | color: var(--MAIN-TEXT-color) !important; 31 | } 32 | 33 | textarea:focus, input[type="email"]:focus, input[type="number"]:focus, input[type="password"]:focus, input[type="search"]:focus, input[type="tel"]:focus, input[type="text"]:focus, input[type="url"]:focus, input[type="color"]:focus, input[type="date"]:focus, input[type="datetime"]:focus, input[type="datetime-local"]:focus, input[type="month"]:focus, input[type="time"]:focus, input[type="week"]:focus, select[multiple=multiple]:focus { 34 | border-color: none; 35 | box-shadow: none; 36 | } 37 | 38 | h2, h3, h4, h5 { 39 | color: var(--MAIN-TITLES-TEXT-color) !important; 40 | } 41 | 42 | a { 43 | color: var(--MAIN-LINK-color); 44 | } 45 | 46 | .anchor { 47 | color: var(--MAIN-ANCHOR-color); 48 | } 49 | 50 | a:hover { 51 | color: var(--MAIN-LINK-HOVER-color); 52 | } 53 | 54 | #sidebar ul li.visited > a .read-icon { 55 | color: var(--MENU-VISITED-color); 56 | } 57 | 58 | #sidebar #footer { 59 | padding-top: 20px !important; 60 | } 61 | 62 | #sidebar #footer h2.github-title { 63 | font-size: 20px; 64 | color: #fd9827 !important; 65 | margin: 10px 0px 5px; 66 | padding: 0px; 67 | font-weight: normal !important; 68 | margin-top: 10px; 69 | padding-top: 30px; 70 | border-top: 1px dotted #384657; 71 | } 72 | 73 | #sidebar #footer h3.github-title { 74 | font-size: 14px; 75 | margin: 10px 0px 5px; 76 | padding: 0px; 77 | text-transform: uppercase; 78 | letter-spacing: .15px; 79 | } 80 | 81 | #sidebar #footer h5.copyright, #sidebar #footer p.build-number { 82 | font-size: 10px; 83 | letter-spacing: .15px; 84 | line-height: 150% !important; 85 | } 86 | 87 | #body a.highlight:after { 88 | display: block; 89 | content: ""; 90 | height: 1px; 91 | width: 0%; 92 | -webkit-transition: width 0.5s ease; 93 | -moz-transition: width 0.5s ease; 94 | -ms-transition: width 0.5s ease; 95 | transition: width 0.5s ease; 96 | background-color: var(--MAIN-LINK-HOVER-color); 97 | } 98 | #sidebar { 99 | background-color: var(--MENU-SECTIONS-BG-color); 100 | } 101 | #sidebar #header-wrapper { 102 | background: var(--MENU-HEADER-BG-color); 103 | color: var(--MENU-SEARCH-BOX-color); 104 | border-color: var(--MENU-HEADER-BORDER-color); 105 | } 106 | #sidebar .searchbox { 107 | border-color: var(--MENU-SEARCH-BOX-color); 108 | background: var(--MENU-SEARCH-BG-color); 109 | } 110 | #sidebar ul.topics > li.parent, #sidebar ul.topics > li.active { 111 | background: var(--MENU-SECTIONS-ACTIVE-BG-color); 112 | } 113 | #sidebar .searchbox * { 114 | color: var(--MENU-SEARCH-BOX-ICONS-color); 115 | } 116 | 117 | #sidebar a { 118 | color: var(--MENU-SECTIONS-LINK-color); 119 | } 120 | 121 | #sidebar a:hover { 122 | color: var(--MENU-SECTIONS-LINK-HOVER-color); 123 | } 124 | 125 | #sidebar ul li.active > a { 126 | background: var(--MENU-SECTION-ACTIVE-CATEGORY-BG-color); 127 | color: var(--MENU-SECTION-ACTIVE-CATEGORY-color) !important; 128 | } 129 | 130 | #sidebar hr { 131 | border-color: var(--MENU-SECTION-HR-color); 132 | } 133 | 134 | #navigation a.nav-prev, #navigation a.nav-next { 135 | color: #f19e39 !important; 136 | } 137 | 138 | #navigation a.nav-prev:hover, #navigation a.nav-next:hover { 139 | color: #e07d04 !important; 140 | } 141 | 142 | div.notices p:first-child:before { 143 | position: absolute; 144 | top: 2px; 145 | color: #fff; 146 | font-family: 'Font Awesome\ 5 Free'; 147 | content: #F06A; 148 | font-weight: 900; /* Fix version 5.0.9 */ 149 | left: 10px; 150 | } 151 | 152 | .ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default, .ui-button, html .ui-button.ui-state-disabled:hover, html .ui-button.ui-state-disabled:active { 153 | border: 1px solid #dddddd; 154 | font-weight: normal; 155 | color: #454545; 156 | } 157 | 158 | .ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active, a.ui-button:active, .ui-button:active, .ui-button.ui-state-active:hover { 159 | border: 1px solid var(--MENU-HEADER-BG-color); 160 | background: var(--MENU-HEADER-BG-color); 161 | font-weight: normal; 162 | color: #fff; 163 | } 164 | 165 | .ui-widget.ui-widget-content { 166 | border: 1px solid #eeeeee; 167 | } 168 | 169 | .ui-widget-header { 170 | border: 1px solid #eeeeee; 171 | } 172 | 173 | .hljs { 174 | background-color: none; 175 | } 176 | 177 | pre { 178 | background-color: var(--MENU-SECTIONS-BG-color) !important; 179 | } 180 | 181 | div.notices.info p { 182 | border-top: 30px solid #fd9827; 183 | background: #FFF2DB; 184 | } 185 | -------------------------------------------------------------------------------- /workshop/static/images/apigateway-authorizer-cognito-confirmation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/workshop/static/images/apigateway-authorizer-cognito-confirmation.png -------------------------------------------------------------------------------- /workshop/static/images/apigateway-authorizer-cognito-selection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/workshop/static/images/apigateway-authorizer-cognito-selection.png -------------------------------------------------------------------------------- /workshop/static/images/apigateway-authorizer-iam-confirmation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/workshop/static/images/apigateway-authorizer-iam-confirmation.png -------------------------------------------------------------------------------- /workshop/static/images/apigateway-authorizer-iam-selection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/workshop/static/images/apigateway-authorizer-iam-selection.png -------------------------------------------------------------------------------- /workshop/static/images/apigateway-authorizer-settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/workshop/static/images/apigateway-authorizer-settings.png -------------------------------------------------------------------------------- /workshop/static/images/apigateway-authorizer-test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/workshop/static/images/apigateway-authorizer-test.png -------------------------------------------------------------------------------- /workshop/static/images/apigateway-method-request-settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/workshop/static/images/apigateway-method-request-settings.png -------------------------------------------------------------------------------- /workshop/static/images/apigateway-test-authorizer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/workshop/static/images/apigateway-test-authorizer.png -------------------------------------------------------------------------------- /workshop/static/images/apn-logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/workshop/static/images/apn-logo.jpg -------------------------------------------------------------------------------- /workshop/static/images/aws-open-source.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/workshop/static/images/aws-open-source.jpg -------------------------------------------------------------------------------- /workshop/static/images/cloud9-createscratchpadtab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/workshop/static/images/cloud9-createscratchpadtab.png -------------------------------------------------------------------------------- /workshop/static/images/cloud9-local-preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/workshop/static/images/cloud9-local-preview.png -------------------------------------------------------------------------------- /workshop/static/images/cloud9-new-terminal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/workshop/static/images/cloud9-new-terminal.png -------------------------------------------------------------------------------- /workshop/static/images/cloud9-resize-live-preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/workshop/static/images/cloud9-resize-live-preview.png -------------------------------------------------------------------------------- /workshop/static/images/cloud9_cfn_outputs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/workshop/static/images/cloud9_cfn_outputs.png -------------------------------------------------------------------------------- /workshop/static/images/cloud9_initial_screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/workshop/static/images/cloud9_initial_screen.png -------------------------------------------------------------------------------- /workshop/static/images/cognito-app-clients.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/workshop/static/images/cognito-app-clients.png -------------------------------------------------------------------------------- /workshop/static/images/cognito-authorizer-request-console-log.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/workshop/static/images/cognito-authorizer-request-console-log.png -------------------------------------------------------------------------------- /workshop/static/images/cognito-create-user-pool.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/workshop/static/images/cognito-create-user-pool.png -------------------------------------------------------------------------------- /workshop/static/images/cognito-identitypool-copyId.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/workshop/static/images/cognito-identitypool-copyId.png -------------------------------------------------------------------------------- /workshop/static/images/cognito-identitypool-setup-step1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/workshop/static/images/cognito-identitypool-setup-step1.png -------------------------------------------------------------------------------- /workshop/static/images/cognito-message-delivery.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/workshop/static/images/cognito-message-delivery.png -------------------------------------------------------------------------------- /workshop/static/images/cognito-mfa-options.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/workshop/static/images/cognito-mfa-options.png -------------------------------------------------------------------------------- /workshop/static/images/cognito-setup-scratchpad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/workshop/static/images/cognito-setup-scratchpad.png -------------------------------------------------------------------------------- /workshop/static/images/cognito-userpool-copy-appclient-id.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/workshop/static/images/cognito-userpool-copy-appclient-id.png -------------------------------------------------------------------------------- /workshop/static/images/cognito-userpool-copy-userpool-id.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/workshop/static/images/cognito-userpool-copy-userpool-id.png -------------------------------------------------------------------------------- /workshop/static/images/cognito-userpool-setup-step1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/workshop/static/images/cognito-userpool-setup-step1.png -------------------------------------------------------------------------------- /workshop/static/images/cognito-userpool-setup-step2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/workshop/static/images/cognito-userpool-setup-step2.png -------------------------------------------------------------------------------- /workshop/static/images/cognito-userpool-setup-step3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/workshop/static/images/cognito-userpool-setup-step3.png -------------------------------------------------------------------------------- /workshop/static/images/cognito-userpool-setup-step4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/workshop/static/images/cognito-userpool-setup-step4.png -------------------------------------------------------------------------------- /workshop/static/images/cognito-userpool-setup-step5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/workshop/static/images/cognito-userpool-setup-step5.png -------------------------------------------------------------------------------- /workshop/static/images/cognito-userpool-setup-step6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/workshop/static/images/cognito-userpool-setup-step6.png -------------------------------------------------------------------------------- /workshop/static/images/cognito-userpool-setup-step7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/workshop/static/images/cognito-userpool-setup-step7.png -------------------------------------------------------------------------------- /workshop/static/images/cognito-wildrydes-messages.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/workshop/static/images/cognito-wildrydes-messages.png -------------------------------------------------------------------------------- /workshop/static/images/create-user-pool-authorizer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/workshop/static/images/create-user-pool-authorizer.png -------------------------------------------------------------------------------- /workshop/static/images/github-home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/workshop/static/images/github-home.png -------------------------------------------------------------------------------- /workshop/static/images/iam-cleanup-findAuthRole.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/workshop/static/images/iam-cleanup-findAuthRole.png -------------------------------------------------------------------------------- /workshop/static/images/iam-cognito-authrole-attach-apigateway-policy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/workshop/static/images/iam-cognito-authrole-attach-apigateway-policy.png -------------------------------------------------------------------------------- /workshop/static/images/iam-cognito-authrole-permissions-after-policy-update.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/workshop/static/images/iam-cognito-authrole-permissions-after-policy-update.png -------------------------------------------------------------------------------- /workshop/static/images/iam-policies-wildrydesapi-search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/workshop/static/images/iam-policies-wildrydesapi-search.png -------------------------------------------------------------------------------- /workshop/static/images/iam-wildrydes-auth-role-add-inline-policy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/workshop/static/images/iam-wildrydes-auth-role-add-inline-policy.png -------------------------------------------------------------------------------- /workshop/static/images/iam-wildrydes-role-selection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/workshop/static/images/iam-wildrydes-role-selection.png -------------------------------------------------------------------------------- /workshop/static/images/iam-wildrydesapi-policy-details.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/workshop/static/images/iam-wildrydesapi-policy-details.png -------------------------------------------------------------------------------- /workshop/static/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/workshop/static/images/logo.png -------------------------------------------------------------------------------- /workshop/static/images/wildrydes-complete-architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/workshop/static/images/wildrydes-complete-architecture.png -------------------------------------------------------------------------------- /workshop/static/images/wildrydes-module1-architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/workshop/static/images/wildrydes-module1-architecture.png -------------------------------------------------------------------------------- /workshop/static/images/wildrydes-module2-architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/workshop/static/images/wildrydes-module2-architecture.png -------------------------------------------------------------------------------- /workshop/static/images/wildrydes-module3-architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-serverless-auth-workshop/335a2600336c09eca95375d3adbf8ea1bb0131ad/workshop/static/images/wildrydes-module3-architecture.png -------------------------------------------------------------------------------- /workshop/static/js/_tabs.js: -------------------------------------------------------------------------------- 1 | $('.tab-content').find('.tab-pane').each(function(idx, item) { 2 | var navTabs = $(this).closest('.code-tabs').find('.nav-tabs'), 3 | title = $(this).attr('title'); 4 | navTabs.append('
  • '+title+'