├── src
├── Main.js
├── amplifyorange.png
├── amplifywhite.png
├── AppwithAuth.js
├── App.test.js
├── index.css
├── App.css
├── aws-exports.js
├── Header.js
├── index.js
├── Buttons.js
├── logo.svg
├── App.js
├── serviceWorker.js
└── Form.js
├── authscreens.jpg
├── public
├── favicon.ico
├── manifest.json
└── index.html
├── amplify
├── backend
│ ├── backend-config.json
│ └── auth
│ │ └── amplifyauthdemob1911f49
│ │ ├── parameters.json
│ │ └── amplifyauthdemob1911f49-cloudformation-template.yml
├── .config
│ └── project-config.json
└── team-provider-info.json
├── .gitignore
├── package.json
└── README.md
/src/Main.js:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/authscreens.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arelaxtest/amplify-auth-demo/HEAD/authscreens.jpg
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arelaxtest/amplify-auth-demo/HEAD/public/favicon.ico
--------------------------------------------------------------------------------
/src/amplifyorange.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arelaxtest/amplify-auth-demo/HEAD/src/amplifyorange.png
--------------------------------------------------------------------------------
/src/amplifywhite.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arelaxtest/amplify-auth-demo/HEAD/src/amplifywhite.png
--------------------------------------------------------------------------------
/src/AppwithAuth.js:
--------------------------------------------------------------------------------
1 | import { withAuthenticator } from 'aws-amplify-react'
2 | import App from './App'
3 |
4 | export default withAuthenticator(App)
5 |
--------------------------------------------------------------------------------
/amplify/backend/backend-config.json:
--------------------------------------------------------------------------------
1 | {
2 | "auth": {
3 | "amplifyauthdemob1911f49": {
4 | "service": "Cognito",
5 | "providerPlugin": "awscloudformation",
6 | "dependsOn": []
7 | }
8 | }
9 | }
--------------------------------------------------------------------------------
/src/App.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from './App';
4 |
5 | it('renders without crashing', () => {
6 | const div = document.createElement('div');
7 | ReactDOM.render(, div);
8 | ReactDOM.unmountComponentAtNode(div);
9 | });
10 |
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | }
10 | ],
11 | "start_url": ".",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
5 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
6 | sans-serif;
7 | -webkit-font-smoothing: antialiased;
8 | -moz-osx-font-smoothing: grayscale;
9 | }
10 |
11 | code {
12 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
13 | monospace;
14 | }
15 |
--------------------------------------------------------------------------------
/amplify/.config/project-config.json:
--------------------------------------------------------------------------------
1 | {
2 | "projectName": "amplify-auth-demo",
3 | "version": "2.0",
4 | "frontend": "javascript",
5 | "javascript": {
6 | "framework": "react",
7 | "config": {
8 | "SourceDir": "src",
9 | "DistributionDir": "build",
10 | "BuildCommand": "npm run-script build",
11 | "StartCommand": "npm run-script start"
12 | }
13 | },
14 | "providers": [
15 | "awscloudformation"
16 | ]
17 | }
--------------------------------------------------------------------------------
/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | text-align: center;
3 | }
4 |
5 | .App-logo {
6 | animation: App-logo-spin infinite 20s linear;
7 | height: 40vmin;
8 | pointer-events: none;
9 | }
10 |
11 | .App-header {
12 | background-color: #282c34;
13 | min-height: 100vh;
14 | display: flex;
15 | flex-direction: column;
16 | align-items: center;
17 | justify-content: center;
18 | font-size: calc(10px + 2vmin);
19 | color: white;
20 | }
21 |
22 | .App-link {
23 | color: #61dafb;
24 | }
25 |
26 | @keyframes App-logo-spin {
27 | from {
28 | transform: rotate(0deg);
29 | }
30 | to {
31 | transform: rotate(360deg);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
25 | #amplify
26 | amplify/\#current-cloud-backend
27 | amplify/.config/local-*
28 | amplify/mock-data
29 | amplify/backend/amplify-meta.json
30 | amplify/backend/awscloudformation
31 | build/
32 | dist/
33 | node_modules/
34 | aws-exports.js
35 | awsconfiguration.json
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "amplify-auth",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "aws-amplify": "^1.1.36",
7 | "aws-amplify-react": "^2.3.6",
8 | "glamor": "^2.20.40",
9 | "install": "^0.13.0",
10 | "react": "^16.8.6",
11 | "react-dom": "^16.8.6",
12 | "react-icons": "^3.6.1",
13 | "react-scripts": "3.0.0"
14 | },
15 | "scripts": {
16 | "start": "react-scripts start",
17 | "build": "react-scripts build",
18 | "test": "react-scripts test",
19 | "eject": "react-scripts eject"
20 | },
21 | "eslintConfig": {
22 | "extends": "react-app"
23 | },
24 | "browserslist": {
25 | "production": [
26 | ">0.2%",
27 | "not dead",
28 | "not op_mini all"
29 | ],
30 | "development": [
31 | "last 1 chrome version",
32 | "last 1 firefox version",
33 | "last 1 safari version"
34 | ]
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/aws-exports.js:
--------------------------------------------------------------------------------
1 | // WARNING: DO NOT EDIT. This file is automatically generated by AWS Amplify. It will be overwritten.
2 |
3 | const awsmobile = {
4 | "aws_project_region": "us-east-2",
5 | "aws_cognito_identity_pool_id": "us-east-2:c5348ad1-cd39-4a98-a0f7-56ec39f7fc30",
6 | "aws_cognito_region": "us-east-2",
7 | "aws_user_pools_id": "us-east-2_XT5c8jAIY",
8 | "aws_user_pools_web_client_id": "d0ijscdpsk43duo6jnt7pdonp",
9 | "oauth": {
10 | "domain": "amplify-auth-abcedf-local.auth.us-east-2.amazoncognito.com",
11 | "scope": [
12 | "phone",
13 | "email",
14 | "openid",
15 | "profile",
16 | "aws.cognito.signin.user.admin"
17 | ],
18 | "redirectSignIn": "http://localhost:3000/,https://master.d3h5j4begww46c.amplifyapp.com/",
19 | "redirectSignOut": "http://localhost:3000/,https://master.d3h5j4begww46c.amplifyapp.com/",
20 | "responseType": "code"
21 | },
22 | "federationTarget": "COGNITO_USER_POOLS"
23 | };
24 |
25 |
26 | export default awsmobile;
27 |
--------------------------------------------------------------------------------
/src/Header.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import AmplifyLogo from './amplifyorange.png'
3 |
4 | export default function Header(props) {
5 | return (
6 |
7 |
props.updateFormState('base')}>
8 |

13 |
Amplify Auth Demo
14 |
15 |
16 | )
17 | }
18 |
19 | const styles = {
20 | container: {
21 | padding: 20,
22 | position: 'fixed',
23 | top: 0,
24 | left: 0,
25 | right: 0,
26 | maxHeight: 65,
27 | boxShadow: '0px 2px 2px rgba(0, 0, 0, .1)'
28 | },
29 | header: {
30 | margin: 0,
31 | fontSize: 24,
32 | marginLeft: 9,
33 | fontWeight: '300',
34 | marginTop: -3,
35 | color: 'rgb(255, 153, 0)',
36 | cursor: 'pointer',
37 | },
38 | headerContent: {
39 | cursor: 'pointer',
40 | display: 'flex'
41 | },
42 | image: {
43 | height: 22,
44 | cursor: 'pointer',
45 | }
46 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # AWS Amplify Auth Example
2 |
3 | 
4 |
5 | ### The Complete Guide to Authentication with the Amplify Framework
6 |
7 | This repo goes along with the Dev.to blog post [The Complete Guide to User Authentication with the Amplify Framework](https://dev.to/dabit3/the-complete-guide-to-user-authentication-with-the-amplify-framework-2inh) & the demo at [amplifyauth.dev](https://www.amplifyauth.dev/).
8 |
9 | ### Methods used to authenticate in this app:
10 |
11 | ```js
12 | // launch Hosted UI (Buttons.js)
13 | Auth.federatedSignIn()
14 |
15 | // specify OAuth provider (Buttons.js)
16 | Auth.federatedSignIn({provider: 'Facebook'})
17 | Auth.federatedSignIn({provider: 'Google'})
18 |
19 | // Manually sign up & sign in users (Form.js)
20 | Auth.signUp({
21 | username, password, attributes: { email }
22 | })
23 | Auth.confirmSignUp(username, confirmationCode)
24 | Auth.signIn(username, password)
25 | ```
26 |
27 | To learn how to build this app, check out [the post](https://dev.to/dabit3/the-complete-guide-to-user-authentication-with-the-amplify-framework-2inh) or view [the documentation](https://aws-amplify.github.io/docs/js/authentication).
--------------------------------------------------------------------------------
/amplify/team-provider-info.json:
--------------------------------------------------------------------------------
1 | {
2 | "local": {
3 | "awscloudformation": {
4 | "AuthRoleName": "amplify-auth-demo-local-20190825011505-authRole",
5 | "UnauthRoleArn": "arn:aws:iam::678088849394:role/amplify-auth-demo-local-20190825011505-unauthRole",
6 | "AuthRoleArn": "arn:aws:iam::678088849394:role/amplify-auth-demo-local-20190825011505-authRole",
7 | "Region": "us-east-2",
8 | "DeploymentBucketName": "amplify-auth-demo-local-20190825011505-deployment",
9 | "UnauthRoleName": "amplify-auth-demo-local-20190825011505-unauthRole",
10 | "StackName": "amplify-auth-demo-local-20190825011505",
11 | "StackId": "arn:aws:cloudformation:us-east-2:678088849394:stack/amplify-auth-demo-local-20190825011505/025a9aa0-c6c5-11e9-b644-0285144e27ac"
12 | },
13 | "categories": {
14 | "auth": {
15 | "amplifyauthdemob1911f49": {
16 | "hostedUIProviderCreds": "[{\"ProviderName\":\"Google\",\"client_id\":\"706485322260-k6ddckfol7fgfhu94tre7rld744p9sq3.apps.googleusercontent.com\",\"client_secret\":\"pUf4ANrkru-u_24xuVXn2D8d\"}]"
17 | }
18 | }
19 | }
20 | }
21 | }
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
22 | AWS Amplify Authentication Demo
23 |
24 |
25 |
26 |
27 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import './index.css';
4 | import App from './App';
5 |
6 | import * as serviceWorker from './serviceWorker';
7 | import Amplify, { Auth } from 'aws-amplify'
8 | import config from './aws-exports'
9 |
10 | var urlsIn = config.oauth.redirectSignIn.split(",");
11 | var urlsOut = config.oauth.redirectSignOut.split(",");
12 | const oauth = {
13 | domain: config.oauth.domain,
14 | scope: config.oauth.scope,
15 | redirectSignIn: config.oauth.redirectSignIn,
16 | redirectSignOut: config.oauth.redirectSignOut,
17 | responseType: config.oauth.responseType
18 | };
19 | var hasLocalhost = (hostname) => Boolean(hostname.match(/localhost/) || hostname.match(/127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}/));
20 | var hasHostname = (hostname) => Boolean(hostname.includes(window.location.hostname));
21 | var isLocalhost = hasLocalhost(window.location.hostname);
22 | if (isLocalhost) {
23 | urlsIn.forEach((e) => { if (hasLocalhost(e)) { oauth.redirectSignIn = e; }});
24 | urlsOut.forEach((e) => { if (hasLocalhost(e)) { oauth.redirectSignOut = e; }});
25 | }
26 | else {
27 | urlsIn.forEach((e) => { if (hasHostname(e)) { oauth.redirectSignIn = e; }});
28 | urlsOut.forEach((e) => { if (hasHostname(e)) { oauth.redirectSignOut = e; }});
29 | }
30 | var configUpdate = config;
31 | configUpdate.oauth = oauth;
32 | Amplify.configure(configUpdate);
33 |
34 | ReactDOM.render(, document.getElementById('root'));
35 |
36 | // If you want your app to work offline and load faster, you can change
37 | // unregister() to register() below. Note this comes with some pitfalls.
38 | // Learn more about service workers: https://bit.ly/CRA-PWA
39 | serviceWorker.unregister();
40 |
--------------------------------------------------------------------------------
/amplify/backend/auth/amplifyauthdemob1911f49/parameters.json:
--------------------------------------------------------------------------------
1 | {
2 | "identityPoolName": "amplifyauthdemob1911f49_identitypool_b1911f49",
3 | "allowUnauthenticatedIdentities": false,
4 | "resourceNameTruncated": "amplifb1911f49",
5 | "userPoolName": "amplifyauthdemob1911f49_userpool_b1911f49",
6 | "autoVerifiedAttributes": [
7 | "email"
8 | ],
9 | "mfaConfiguration": "OFF",
10 | "mfaTypes": [
11 | "SMS Text Message"
12 | ],
13 | "smsAuthenticationMessage": "Your authentication code is {####}",
14 | "smsVerificationMessage": "Your verification code is {####}",
15 | "emailVerificationSubject": "Your verification code",
16 | "emailVerificationMessage": "Your verification code is {####}",
17 | "defaultPasswordPolicy": false,
18 | "passwordPolicyMinLength": 8,
19 | "passwordPolicyCharacters": [],
20 | "requiredAttributes": [
21 | "email"
22 | ],
23 | "userpoolClientGenerateSecret": true,
24 | "userpoolClientRefreshTokenValidity": 30,
25 | "userpoolClientWriteAttributes": [
26 | "email"
27 | ],
28 | "userpoolClientReadAttributes": [
29 | "email"
30 | ],
31 | "userpoolClientLambdaRole": "amplifb1911f49_userpoolclient_lambda_role",
32 | "userpoolClientSetAttributes": false,
33 | "resourceName": "amplifyauthdemob1911f49",
34 | "authSelections": "identityPoolAndUserPool",
35 | "authRoleArn": {
36 | "Fn::GetAtt": [
37 | "AuthRole",
38 | "Arn"
39 | ]
40 | },
41 | "unauthRoleArn": {
42 | "Fn::GetAtt": [
43 | "UnauthRole",
44 | "Arn"
45 | ]
46 | },
47 | "useDefault": "defaultSocial",
48 | "hostedUI": true,
49 | "triggers": "{}",
50 | "hostedUIDomainName": "amplify-auth-abcedf",
51 | "authProvidersUserPool": [
52 | "Google"
53 | ],
54 | "hostedUIProviderMeta": "[{\"ProviderName\":\"Google\",\"authorize_scopes\":\"openid email profile\",\"AttributeMapping\":{\"email\":\"email\",\"username\":\"sub\"}}]",
55 | "parentStack": {
56 | "Ref": "AWS::StackId"
57 | },
58 | "permissions": [],
59 | "dependsOn": [],
60 | "oAuthMetadata": "{\"AllowedOAuthFlows\":[\"code\"],\"AllowedOAuthScopes\":[\"phone\",\"email\",\"openid\",\"profile\",\"aws.cognito.signin.user.admin\"],\"CallbackURLs\":[\"http://localhost:3000/\",\"https://master.d3h5j4begww46c.amplifyapp.com/\"],\"LogoutURLs\":[\"http://localhost:3000/\",\"https://master.d3h5j4begww46c.amplifyapp.com/\"]}"
61 | }
--------------------------------------------------------------------------------
/src/Buttons.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import './App.css'
3 |
4 | import { Auth } from 'aws-amplify'
5 | import { FaFacebook, FaGoogle, FaEnvelope } from 'react-icons/fa'
6 | import AmplifyOrange from './amplifyorange.png'
7 |
8 | function Buttons(props) {
9 | return (
10 |
11 |
12 |
19 |
20 |
31 |
32 |
33 | );
34 | }
35 |
36 | const styles = {
37 | container: {
38 | height: '80vh',
39 | width: '100vw',
40 | display: 'flex',
41 | justifyContent: 'center',
42 | alignItems: 'center',
43 | flexDirection: 'column'
44 | },
45 | button: {
46 | width: '100%',
47 | maxWidth: 250,
48 | marginBottom: 10,
49 | display: 'flex',
50 | justifyContent: 'flex-start',
51 | alignItems: 'center',
52 | padding: '0px 16px',
53 | borderRadius: 2,
54 | boxShadow: '0px 1px 3px rgba(0, 0, 0, .3)',
55 | cursor: 'pointer',
56 | outline: 'none',
57 | border: 'none',
58 | minHeight: 40
59 | },
60 | facebook: {
61 | backgroundColor: "#3b5998"
62 | },
63 | email: {
64 | backgroundColor: '#db4437'
65 | },
66 | checkAuth: {
67 | backgroundColor: '#02bd7e'
68 | },
69 | hostedUI: {
70 | backgroundColor: 'rgba(0, 0, 0, .6)'
71 | },
72 | signOut: {
73 | backgroundColor: 'black'
74 | },
75 | withAuthenticator: {
76 | backgroundColor: '#FF9900'
77 | },
78 | icon: {
79 | height: 16,
80 | marginLeft: -1
81 | },
82 | text: {
83 | color: 'white',
84 | fontSize: 14,
85 | marginLeft: 10,
86 | fontWeight: 'bold'
87 | },
88 | blackText: {
89 | color: 'black'
90 | },
91 | grayText: {
92 | color: 'rgba(0, 0, 0, .75)'
93 | },
94 | orangeText: {
95 | color: '#FF9900'
96 | }
97 | }
98 |
99 | export default Buttons
100 |
--------------------------------------------------------------------------------
/src/logo.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { useReducer, useEffect, useState } from 'react';
2 | import './App.css'
3 | import Header from './Header'
4 | import Buttons from './Buttons'
5 | import Form from './Form'
6 |
7 | import { Hub, Auth } from 'aws-amplify'
8 | import { FaSignOutAlt } from 'react-icons/fa'
9 |
10 | const initialUserState = { user: null, loading: true }
11 |
12 | function App() {
13 | const [userState, dispatch] = useReducer(reducer, initialUserState)
14 | const [formState, updateFormState] = useState('base')
15 |
16 | useEffect(() => {
17 | // set listener for auth events
18 | Hub.listen('auth', (data) => {
19 | const { payload } = data
20 | if (payload.event === 'signIn') {
21 | setImmediate(() => dispatch({ type: 'setUser', user: payload.data }))
22 | setImmediate(() => window.history.pushState({}, null, 'http://localhost:3000/'))
23 | updateFormState('base')
24 | }
25 | // this listener is needed for form sign ups since the OAuth will redirect & reload
26 | if (payload.event === 'signOut') {
27 | setTimeout(() => dispatch({ type: 'setUser', user: null }), 350)
28 | }
29 | })
30 | // we check for the current user unless there is a redirect to ?signedIn=true
31 | if (!window.location.search.includes('?signedin=true')) {
32 | checkUser(dispatch)
33 | }
34 | }, [])
35 |
36 | // This renders the custom form
37 | if (formState === 'email') {
38 | return (
39 |
40 |
41 |
42 |
43 | )
44 | }
45 |
46 | return (
47 |
48 |
49 | {
50 | userState.loading && (
51 |
54 | )
55 | }
56 | {
57 | !userState.user && !userState.loading && (
58 |
61 | )
62 | }
63 | {
64 | userState.user && userState.user.signInUserSession && (
65 |
66 |
67 | Welcome {userState.user.signInUserSession.idToken.payload.email}
68 |
69 |
76 |
77 | )
78 | }
79 |
80 |
81 | )
82 | }
83 |
84 | function reducer (state, action) {
85 | switch(action.type) {
86 | case 'setUser':
87 | return { ...state, user: action.user, loading: false }
88 | case 'loaded':
89 | return { ...state, loading: false }
90 | default:
91 | return state
92 | }
93 | }
94 |
95 | async function checkUser(dispatch) {
96 | try {
97 | const user = await Auth.currentAuthenticatedUser()
98 | console.log('user: ', user)
99 | dispatch({ type: 'setUser', user })
100 | } catch (err) {
101 | console.log('err: ', err)
102 | dispatch({ type: 'loaded' })
103 | }
104 | }
105 |
106 | function signOut() {
107 | Auth.signOut()
108 | .then(data => {
109 | console.log('signed out: ', data)
110 | })
111 | .catch(err => console.log(err));
112 | }
113 |
114 | function Footer () {
115 | return (
116 |
117 |
To view the code for this app, click here. To learn more about AWS Amplify, click here.
122 |
123 | )
124 | }
125 |
126 | const styles = {
127 | appContainer: {
128 | paddingTop: 85,
129 | },
130 | loading: {
131 |
132 | },
133 | button: {
134 | marginTop: 15,
135 | width: '100%',
136 | maxWidth: 250,
137 | marginBottom: 10,
138 | display: 'flex',
139 | justifyContent: 'flex-start',
140 | alignItems: 'center',
141 | padding: '0px 16px',
142 | borderRadius: 2,
143 | boxShadow: '0px 1px 3px rgba(0, 0, 0, .3)',
144 | cursor: 'pointer',
145 | outline: 'none',
146 | border: 'none',
147 | minHeight: 40
148 | },
149 | text: {
150 | color: 'white',
151 | fontSize: 14,
152 | marginLeft: 10,
153 | fontWeight: 'bold'
154 | },
155 | signOut: {
156 | backgroundColor: 'black'
157 | },
158 | footer: {
159 | fontWeight: '600',
160 | padding: '0px 25px',
161 | textAlign: 'right',
162 | color: 'rgba(0, 0, 0, 0.6)'
163 | },
164 | anchor: {
165 | color: 'rgb(255, 153, 0)',
166 | textDecoration: 'none'
167 | },
168 | body: {
169 | padding: '0px 30px',
170 | height: '78vh'
171 | }
172 | }
173 |
174 | export default App
175 |
--------------------------------------------------------------------------------
/src/serviceWorker.js:
--------------------------------------------------------------------------------
1 | // This optional code is used to register a service worker.
2 | // register() is not called by default.
3 |
4 | // This lets the app load faster on subsequent visits in production, and gives
5 | // it offline capabilities. However, it also means that developers (and users)
6 | // will only see deployed updates on subsequent visits to a page, after all the
7 | // existing tabs open on the page have been closed, since previously cached
8 | // resources are updated in the background.
9 |
10 | // To learn more about the benefits of this model and instructions on how to
11 | // opt-in, read https://bit.ly/CRA-PWA
12 |
13 | const isLocalhost = Boolean(
14 | window.location.hostname === 'localhost' ||
15 | // [::1] is the IPv6 localhost address.
16 | window.location.hostname === '[::1]' ||
17 | // 127.0.0.1/8 is considered localhost for IPv4.
18 | window.location.hostname.match(
19 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
20 | )
21 | );
22 |
23 | export function register(config) {
24 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
25 | // The URL constructor is available in all browsers that support SW.
26 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);
27 | if (publicUrl.origin !== window.location.origin) {
28 | // Our service worker won't work if PUBLIC_URL is on a different origin
29 | // from what our page is served on. This might happen if a CDN is used to
30 | // serve assets; see https://github.com/facebook/create-react-app/issues/2374
31 | return;
32 | }
33 |
34 | window.addEventListener('load', () => {
35 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
36 |
37 | if (isLocalhost) {
38 | // This is running on localhost. Let's check if a service worker still exists or not.
39 | checkValidServiceWorker(swUrl, config);
40 |
41 | // Add some additional logging to localhost, pointing developers to the
42 | // service worker/PWA documentation.
43 | navigator.serviceWorker.ready.then(() => {
44 | console.log(
45 | 'This web app is being served cache-first by a service ' +
46 | 'worker. To learn more, visit https://bit.ly/CRA-PWA'
47 | );
48 | });
49 | } else {
50 | // Is not localhost. Just register service worker
51 | registerValidSW(swUrl, config);
52 | }
53 | });
54 | }
55 | }
56 |
57 | function registerValidSW(swUrl, config) {
58 | navigator.serviceWorker
59 | .register(swUrl)
60 | .then(registration => {
61 | registration.onupdatefound = () => {
62 | const installingWorker = registration.installing;
63 | if (installingWorker == null) {
64 | return;
65 | }
66 | installingWorker.onstatechange = () => {
67 | if (installingWorker.state === 'installed') {
68 | if (navigator.serviceWorker.controller) {
69 | // At this point, the updated precached content has been fetched,
70 | // but the previous service worker will still serve the older
71 | // content until all client tabs are closed.
72 | console.log(
73 | 'New content is available and will be used when all ' +
74 | 'tabs for this page are closed. See https://bit.ly/CRA-PWA.'
75 | );
76 |
77 | // Execute callback
78 | if (config && config.onUpdate) {
79 | config.onUpdate(registration);
80 | }
81 | } else {
82 | // At this point, everything has been precached.
83 | // It's the perfect time to display a
84 | // "Content is cached for offline use." message.
85 | console.log('Content is cached for offline use.');
86 |
87 | // Execute callback
88 | if (config && config.onSuccess) {
89 | config.onSuccess(registration);
90 | }
91 | }
92 | }
93 | };
94 | };
95 | })
96 | .catch(error => {
97 | console.error('Error during service worker registration:', error);
98 | });
99 | }
100 |
101 | function checkValidServiceWorker(swUrl, config) {
102 | // Check if the service worker can be found. If it can't reload the page.
103 | fetch(swUrl)
104 | .then(response => {
105 | // Ensure service worker exists, and that we really are getting a JS file.
106 | const contentType = response.headers.get('content-type');
107 | if (
108 | response.status === 404 ||
109 | (contentType != null && contentType.indexOf('javascript') === -1)
110 | ) {
111 | // No service worker found. Probably a different app. Reload the page.
112 | navigator.serviceWorker.ready.then(registration => {
113 | registration.unregister().then(() => {
114 | window.location.reload();
115 | });
116 | });
117 | } else {
118 | // Service worker found. Proceed as normal.
119 | registerValidSW(swUrl, config);
120 | }
121 | })
122 | .catch(() => {
123 | console.log(
124 | 'No internet connection found. App is running in offline mode.'
125 | );
126 | });
127 | }
128 |
129 | export function unregister() {
130 | if ('serviceWorker' in navigator) {
131 | navigator.serviceWorker.ready.then(registration => {
132 | registration.unregister();
133 | });
134 | }
135 | }
136 |
--------------------------------------------------------------------------------
/src/Form.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useReducer } from 'react'
2 |
3 | import { Auth } from 'aws-amplify'
4 |
5 | const initialFormState = {
6 | username: '', password: '', email: '', confirmationCode: ''
7 | }
8 |
9 | function reducer(state, action) {
10 | switch(action.type) {
11 | case 'updateFormState':
12 | return {
13 | ...state, [action.e.target.name]: action.e.target.value
14 | }
15 | default:
16 | return state
17 | }
18 | }
19 |
20 | async function signUp({ username, password, email }, updateFormType) {
21 | try {
22 | await Auth.signUp({
23 | username, password, attributes: { email }
24 | })
25 | console.log('sign up success!')
26 | updateFormType('confirmSignUp')
27 | } catch (err) {
28 | console.log('error signing up..', err)
29 | }
30 | }
31 |
32 | async function confirmSignUp({ username, confirmationCode }, updateFormType) {
33 | try {
34 | await Auth.confirmSignUp(username, confirmationCode)
35 | console.log('confirm sign up success!')
36 | updateFormType('signIn')
37 | } catch (err) {
38 | console.log('error signing up..', err)
39 | }
40 | }
41 |
42 | async function signIn({ username, password }) {
43 | try {
44 | await Auth.signIn(username, password)
45 | console.log('sign in success!')
46 | } catch (err) {
47 | console.log('error signing up..', err)
48 | }
49 | }
50 |
51 | export default function Form() {
52 | const [formType, updateFormType] = useState('signUp')
53 | const [formState, updateFormState] = useReducer(reducer, initialFormState)
54 | function renderForm() {
55 | switch(formType) {
56 | case 'signUp':
57 | return (
58 | signUp(formState, updateFormType)}
60 | updateFormState={e => updateFormState({ type: 'updateFormState', e })}
61 | />
62 | )
63 | case 'confirmSignUp':
64 | return (
65 | confirmSignUp(formState, updateFormType)}
67 | updateFormState={e => updateFormState({ type: 'updateFormState', e })}
68 | />
69 | )
70 | case 'signIn':
71 | return (
72 | signIn(formState)}
74 | updateFormState={e => updateFormState({ type: 'updateFormState', e })}
75 | />
76 | )
77 | default:
78 | return null
79 | }
80 | }
81 |
82 |
83 | return (
84 |
85 |
86 | {renderForm(formState)}
87 |
88 | {
89 | formType === 'signUp' && (
90 |
91 | Already have an account? updateFormType('signIn')}
94 | >Sign In
95 |
96 | )
97 | }
98 | {
99 | formType === 'signIn' && (
100 |
101 | Need an account? updateFormType('signUp')}
104 | >Sign Up
105 |
106 | )
107 | }
108 |
109 | )
110 | }
111 |
112 | function SignUp(props) {
113 | return (
114 |
115 | {e.persist();props.updateFormState(e)}}
118 | style={styles.input}
119 | placeholder='username'
120 | />
121 | {e.persist();props.updateFormState(e)}}
125 | style={styles.input}
126 | placeholder='password'
127 | />
128 | {e.persist();props.updateFormState(e)}}
131 | style={styles.input}
132 | placeholder='email'
133 | />
134 |
137 |
138 | )
139 | }
140 |
141 | function SignIn(props) {
142 | return (
143 |
144 | {e.persist();props.updateFormState(e)}}
147 | style={styles.input}
148 | placeholder='username'
149 | />
150 | {e.persist();props.updateFormState(e)}}
154 | style={styles.input}
155 | placeholder='password'
156 | />
157 |
160 |
161 | )
162 | }
163 |
164 | function ConfirmSignUp(props) {
165 | return (
166 |
167 | {e.persist();props.updateFormState(e)}}
171 | style={styles.input}
172 | />
173 |
176 |
177 | )
178 | }
179 |
180 | const styles = {
181 | container: {
182 | display: 'flex',
183 | flexDirection: 'column',
184 | marginTop: 150,
185 | justifyContent: 'center',
186 | alignItems: 'center'
187 | },
188 | input: {
189 | height: 45,
190 | marginTop: 8,
191 | width: 300,
192 | maxWidth: 300,
193 | padding: '0px 8px',
194 | fontSize: 16,
195 | outline: 'none',
196 | border: 'none',
197 | borderBottom: '2px solid rgba(0, 0, 0, .3)'
198 | },
199 | button: {
200 | backgroundColor: '#006bfc',
201 | color: 'white',
202 | width: 316,
203 | height: 45,
204 | marginTop: 10,
205 | fontWeight: '600',
206 | fontSize: 14,
207 | cursor: 'pointer',
208 | border:'none',
209 | outline: 'none',
210 | borderRadius: 3,
211 | boxShadow: '0px 1px 3px rgba(0, 0, 0, .3)',
212 | },
213 | footer: {
214 | fontWeight: '600',
215 | padding: '0px 25px',
216 | textAlign: 'center',
217 | color: 'rgba(0, 0, 0, 0.6)'
218 | },
219 | anchor: {
220 | color: '#006bfc',
221 | cursor: 'pointer'
222 | }
223 | }
--------------------------------------------------------------------------------
/amplify/backend/auth/amplifyauthdemob1911f49/amplifyauthdemob1911f49-cloudformation-template.yml:
--------------------------------------------------------------------------------
1 | AWSTemplateFormatVersion: 2010-09-09
2 |
3 | Parameters:
4 | env:
5 | Type: String
6 | authRoleArn:
7 | Type: String
8 | unauthRoleArn:
9 | Type: String
10 |
11 |
12 |
13 |
14 | identityPoolName:
15 | Type: String
16 |
17 | allowUnauthenticatedIdentities:
18 | Type: String
19 |
20 | resourceNameTruncated:
21 | Type: String
22 |
23 | userPoolName:
24 | Type: String
25 |
26 | autoVerifiedAttributes:
27 | Type: CommaDelimitedList
28 |
29 | mfaConfiguration:
30 | Type: String
31 |
32 | mfaTypes:
33 | Type: CommaDelimitedList
34 |
35 | smsAuthenticationMessage:
36 | Type: String
37 |
38 | smsVerificationMessage:
39 | Type: String
40 |
41 | emailVerificationSubject:
42 | Type: String
43 |
44 | emailVerificationMessage:
45 | Type: String
46 |
47 | defaultPasswordPolicy:
48 | Type: String
49 |
50 | passwordPolicyMinLength:
51 | Type: Number
52 |
53 | passwordPolicyCharacters:
54 | Type: CommaDelimitedList
55 |
56 | requiredAttributes:
57 | Type: CommaDelimitedList
58 |
59 | userpoolClientGenerateSecret:
60 | Type: String
61 |
62 | userpoolClientRefreshTokenValidity:
63 | Type: Number
64 |
65 | userpoolClientWriteAttributes:
66 | Type: CommaDelimitedList
67 |
68 | userpoolClientReadAttributes:
69 | Type: CommaDelimitedList
70 |
71 | userpoolClientLambdaRole:
72 | Type: String
73 |
74 | userpoolClientSetAttributes:
75 | Type: String
76 |
77 | resourceName:
78 | Type: String
79 |
80 | authSelections:
81 | Type: String
82 |
83 | useDefault:
84 | Type: String
85 |
86 | hostedUI:
87 | Type: String
88 |
89 | triggers:
90 | Type: String
91 |
92 | hostedUIDomainName:
93 | Type: String
94 |
95 | authProvidersUserPool:
96 | Type: CommaDelimitedList
97 |
98 | hostedUIProviderMeta:
99 | Type: String
100 |
101 | parentStack:
102 | Type: String
103 |
104 | permissions:
105 | Type: CommaDelimitedList
106 |
107 | dependsOn:
108 | Type: CommaDelimitedList
109 |
110 | hostedUIProviderCreds:
111 | Type: String
112 |
113 | oAuthMetadata:
114 | Type: String
115 |
116 | Conditions:
117 | ShouldNotCreateEnvResources: !Equals [ !Ref env, NONE ]
118 |
119 | Resources:
120 |
121 |
122 | # BEGIN SNS ROLE RESOURCE
123 | SNSRole:
124 | # Created to allow the UserPool SMS Config to publish via the Simple Notification Service during MFA Process
125 | Type: AWS::IAM::Role
126 | Properties:
127 | RoleName: !If [ShouldNotCreateEnvResources, 'amplifb1911f49_sns-role', !Join ['',['amplifb1911f49_sns-role', '-', !Ref env]]]
128 | AssumeRolePolicyDocument:
129 | Version: "2012-10-17"
130 | Statement:
131 | - Sid: ""
132 | Effect: "Allow"
133 | Principal:
134 | Service: "cognito-idp.amazonaws.com"
135 | Action:
136 | - "sts:AssumeRole"
137 | Condition:
138 | StringEquals:
139 | sts:ExternalId: amplifb1911f49_role_external_id
140 | Policies:
141 | -
142 | PolicyName: amplifb1911f49-sns-policy
143 | PolicyDocument:
144 | Version: "2012-10-17"
145 | Statement:
146 | -
147 | Effect: "Allow"
148 | Action:
149 | - "sns:Publish"
150 | Resource: "*"
151 | # BEGIN USER POOL RESOURCES
152 | UserPool:
153 | # Created upon user selection
154 | # Depends on SNS Role for Arn if MFA is enabled
155 | Type: AWS::Cognito::UserPool
156 | UpdateReplacePolicy: Retain
157 | Properties:
158 | UserPoolName: !If [ShouldNotCreateEnvResources, !Ref userPoolName, !Join ['',[!Ref userPoolName, '-', !Ref env]]]
159 |
160 | Schema:
161 |
162 | -
163 | Name: email
164 | Required: true
165 | Mutable: true
166 |
167 |
168 |
169 |
170 | AutoVerifiedAttributes: !Ref autoVerifiedAttributes
171 |
172 |
173 | EmailVerificationMessage: !Ref emailVerificationMessage
174 | EmailVerificationSubject: !Ref emailVerificationSubject
175 |
176 | Policies:
177 | PasswordPolicy:
178 | MinimumLength: !Ref passwordPolicyMinLength
179 | RequireLowercase: false
180 | RequireNumbers: false
181 | RequireSymbols: false
182 | RequireUppercase: false
183 |
184 | MfaConfiguration: !Ref mfaConfiguration
185 | SmsVerificationMessage: !Ref smsVerificationMessage
186 | SmsConfiguration:
187 | SnsCallerArn: !GetAtt SNSRole.Arn
188 | ExternalId: amplifb1911f49_role_external_id
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 | # Updating lambda role with permissions to Cognito
200 |
201 |
202 | UserPoolClientWeb:
203 | # Created provide application access to user pool
204 | # Depends on UserPool for ID reference
205 | Type: "AWS::Cognito::UserPoolClient"
206 | Properties:
207 | ClientName: amplifb1911f49_app_clientWeb
208 |
209 | RefreshTokenValidity: !Ref userpoolClientRefreshTokenValidity
210 | UserPoolId: !Ref UserPool
211 | DependsOn: UserPool
212 | UserPoolClient:
213 | # Created provide application access to user pool
214 | # Depends on UserPool for ID reference
215 | Type: "AWS::Cognito::UserPoolClient"
216 | Properties:
217 | ClientName: amplifb1911f49_app_client
218 |
219 | GenerateSecret: !Ref userpoolClientGenerateSecret
220 | RefreshTokenValidity: !Ref userpoolClientRefreshTokenValidity
221 | UserPoolId: !Ref UserPool
222 | DependsOn: UserPool
223 | # BEGIN USER POOL LAMBDA RESOURCES
224 | UserPoolClientRole:
225 | # Created to execute Lambda which gets userpool app client config values
226 | Type: 'AWS::IAM::Role'
227 | Properties:
228 | RoleName: !If [ShouldNotCreateEnvResources, !Ref userpoolClientLambdaRole, !Join ['',[!Ref userpoolClientLambdaRole, '-', !Ref env]]]
229 | AssumeRolePolicyDocument:
230 | Version: '2012-10-17'
231 | Statement:
232 | - Effect: Allow
233 | Principal:
234 | Service:
235 | - lambda.amazonaws.com
236 | Action:
237 | - 'sts:AssumeRole'
238 | DependsOn: UserPoolClient
239 | UserPoolClientLambda:
240 | # Lambda which gets userpool app client config values
241 | # Depends on UserPool for id
242 | # Depends on UserPoolClientRole for role ARN
243 | Type: 'AWS::Lambda::Function'
244 | Properties:
245 | Code:
246 | ZipFile: !Join
247 | - |+
248 | - - 'const response = require(''cfn-response'');'
249 | - 'const aws = require(''aws-sdk'');'
250 | - 'const identity = new aws.CognitoIdentityServiceProvider();'
251 | - 'exports.handler = (event, context, callback) => {'
252 | - ' if (event.RequestType == ''Delete'') { '
253 | - ' response.send(event, context, response.SUCCESS, {})'
254 | - ' }'
255 | - ' if (event.RequestType == ''Update'' || event.RequestType == ''Create'') {'
256 | - ' const params = {'
257 | - ' ClientId: event.ResourceProperties.clientId,'
258 | - ' UserPoolId: event.ResourceProperties.userpoolId'
259 | - ' };'
260 | - ' identity.describeUserPoolClient(params).promise()'
261 | - ' .then((res) => {'
262 | - ' response.send(event, context, response.SUCCESS, {''appSecret'': res.UserPoolClient.ClientSecret});'
263 | - ' })'
264 | - ' .catch((err) => {'
265 | - ' response.send(event, context, response.FAILED, {err});'
266 | - ' });'
267 | - ' }'
268 | - '};'
269 | Handler: index.handler
270 | Runtime: nodejs8.10
271 | Timeout: '300'
272 | Role: !GetAtt
273 | - UserPoolClientRole
274 | - Arn
275 | DependsOn: UserPoolClientRole
276 | UserPoolClientLambdaPolicy:
277 | # Sets userpool policy for the role that executes the Userpool Client Lambda
278 | # Depends on UserPool for Arn
279 | # Marked as depending on UserPoolClientRole for easier to understand CFN sequencing
280 | Type: 'AWS::IAM::Policy'
281 | Properties:
282 | PolicyName: amplifb1911f49_userpoolclient_lambda_iam_policy
283 | Roles:
284 | - !If [ShouldNotCreateEnvResources, !Ref userpoolClientLambdaRole, !Join ['',[!Ref userpoolClientLambdaRole, '-', !Ref env]]]
285 | PolicyDocument:
286 | Version: '2012-10-17'
287 | Statement:
288 | - Effect: Allow
289 | Action:
290 | - 'cognito-idp:DescribeUserPoolClient'
291 | Resource: !GetAtt UserPool.Arn
292 | DependsOn: UserPoolClientLambda
293 | UserPoolClientLogPolicy:
294 | # Sets log policy for the role that executes the Userpool Client Lambda
295 | # Depends on UserPool for Arn
296 | # Marked as depending on UserPoolClientLambdaPolicy for easier to understand CFN sequencing
297 | Type: 'AWS::IAM::Policy'
298 | Properties:
299 | PolicyName: amplifb1911f49_userpoolclient_lambda_log_policy
300 | Roles:
301 | - !If [ShouldNotCreateEnvResources, !Ref userpoolClientLambdaRole, !Join ['',[!Ref userpoolClientLambdaRole, '-', !Ref env]]]
302 | PolicyDocument:
303 | Version: 2012-10-17
304 | Statement:
305 | - Effect: Allow
306 | Action:
307 | - 'logs:CreateLogGroup'
308 | - 'logs:CreateLogStream'
309 | - 'logs:PutLogEvents'
310 | Resource: !Sub
311 | - arn:aws:logs:${region}:${account}:log-group:/aws/lambda/${lambda}:log-stream:*
312 | - { region: !Ref "AWS::Region", account: !Ref "AWS::AccountId", lambda: !Ref UserPoolClientLambda}
313 | DependsOn: UserPoolClientLambdaPolicy
314 | UserPoolClientInputs:
315 | # Values passed to Userpool client Lambda
316 | # Depends on UserPool for Id
317 | # Depends on UserPoolClient for Id
318 | # Marked as depending on UserPoolClientLambdaPolicy for easier to understand CFN sequencing
319 | Type: 'Custom::LambdaCallout'
320 | Properties:
321 | ServiceToken: !GetAtt UserPoolClientLambda.Arn
322 | clientId: !Ref UserPoolClient
323 | userpoolId: !Ref UserPool
324 | DependsOn: UserPoolClientLogPolicy
325 |
326 | HostedUICustomResource:
327 | Type: 'AWS::Lambda::Function'
328 | Properties:
329 | Code:
330 | ZipFile: !Join
331 | - |+
332 | - - 'const response = require(''cfn-response'');'
333 | - 'const aws = require(''aws-sdk'');'
334 | - 'const identity = new aws.CognitoIdentityServiceProvider();'
335 | - 'exports.handler = (event, context, callback) => {'
336 | - ' const userPoolId = event.ResourceProperties.userPoolId;'
337 | - ' const inputDomainName = event.ResourceProperties.hostedUIDomainName;'
338 | - ' let deleteUserPoolDomain = (domainName) => {'
339 | - ' let params = { Domain: domainName, UserPoolId: userPoolId };'
340 | - ' return identity.deleteUserPoolDomain(params).promise();'
341 | - ' };'
342 | - ' if (event.RequestType == ''Delete'') {'
343 | - ' deleteUserPoolDomain(inputDomainName)'
344 | - ' .then(() => {response.send(event, context, response.SUCCESS, {})})'
345 | - ' .catch((err) => { console.log(err); response.send(event, context, response.FAILED, {err}) });'
346 | - ' }'
347 | - ' if (event.RequestType == ''Update'' || event.RequestType == ''Create'') {'
348 | - ' let checkDomainAvailability = (domainName) => {'
349 | - ' let params = { Domain: domainName };'
350 | - ' return identity.describeUserPoolDomain(params).promise().then((res) => {'
351 | - ' if (res.DomainDescription && res.DomainDescription.UserPool) {'
352 | - ' return false;'
353 | - ' }'
354 | - ' return true;'
355 | - ' }).catch((err) => { return false; });'
356 | - ' };'
357 | - ' let createUserPoolDomain = (domainName) => {'
358 | - ' let params = { Domain: domainName, UserPoolId: userPoolId };'
359 | - ' return identity.createUserPoolDomain(params).promise();'
360 | - ' };'
361 | - ' identity.describeUserPool({UserPoolId: userPoolId }).promise().then((result) => {'
362 | - ' if (inputDomainName) {'
363 | - ' if (result.UserPool.Domain === inputDomainName) {'
364 | - ' return;'
365 | - ' } else {'
366 | - ' if (!result.UserPool.Domain) {'
367 | - ' return checkDomainAvailability(inputDomainName).then((isDomainAvailable) => {'
368 | - ' if (isDomainAvailable) {'
369 | - ' return createUserPoolDomain(inputDomainName);'
370 | - ' } else {'
371 | - ' throw new Error(''Domain not available'');'
372 | - ' }'
373 | - ' });'
374 | - ' } else {'
375 | - ' return checkDomainAvailability(inputDomainName).then((isDomainAvailable) => {'
376 | - ' if (isDomainAvailable) {'
377 | - ' return deleteUserPoolDomain(result.UserPool.Domain).then(() => createUserPoolDomain(inputDomainName));'
378 | - ' } else {'
379 | - ' throw new Error(''Domain not available'');'
380 | - ' }'
381 | - ' });'
382 | - ' }'
383 | - ' }'
384 | - ' } else {'
385 | - ' if (result.UserPool.Domain) {'
386 | - ' return deleteUserPoolDomain(result.UserPool.Domain);'
387 | - ' }'
388 | - ' }'
389 | - ' }).then(() => {response.send(event, context, response.SUCCESS, {})}).catch((err) => {'
390 | - ' console.log(err); response.send(event, context, response.FAILED, {err});'
391 | - ' });'
392 | - '}}'
393 |
394 |
395 | Handler: index.handler
396 | Runtime: nodejs8.10
397 | Timeout: '300'
398 | Role: !GetAtt
399 | - UserPoolClientRole
400 | - Arn
401 | DependsOn: UserPoolClientRole
402 |
403 | HostedUICustomResourcePolicy:
404 | Type: 'AWS::IAM::Policy'
405 | Properties:
406 | PolicyName: !Join ['-',[!Ref UserPool, 'hostedUI']]
407 | Roles:
408 | - !If [ShouldNotCreateEnvResources, !Ref userpoolClientLambdaRole, !Join ['',[!Ref userpoolClientLambdaRole, '-', !Ref env]]]
409 | PolicyDocument:
410 | Version: '2012-10-17'
411 | Statement:
412 | - Effect: Allow
413 | Action:
414 | - 'cognito-idp:CreateUserPoolDomain'
415 | - 'cognito-idp:DescribeUserPool'
416 | - 'cognito-idp:DeleteUserPoolDomain'
417 | Resource: !GetAtt UserPool.Arn
418 | - Effect: Allow
419 | Action:
420 | - 'cognito-idp:DescribeUserPoolDomain'
421 | Resource: '*'
422 | DependsOn: HostedUICustomResource
423 | HostedUICustomResourceLogPolicy:
424 | Type: 'AWS::IAM::Policy'
425 | Properties:
426 | PolicyName: !Join ['-',[!Ref UserPool, 'hostedUILogPolicy']]
427 | Roles:
428 | - !If [ShouldNotCreateEnvResources, !Ref userpoolClientLambdaRole, !Join ['',[!Ref userpoolClientLambdaRole, '-', !Ref env]]]
429 | PolicyDocument:
430 | Version: 2012-10-17
431 | Statement:
432 | - Effect: Allow
433 | Action:
434 | - 'logs:CreateLogGroup'
435 | - 'logs:CreateLogStream'
436 | - 'logs:PutLogEvents'
437 | Resource: !Sub
438 | - arn:aws:logs:${region}:${account}:log-group:/aws/lambda/${lambda}:log-stream:*
439 | - { region: !Ref "AWS::Region", account: !Ref "AWS::AccountId", lambda: !Ref HostedUICustomResource}
440 | DependsOn: HostedUICustomResourcePolicy
441 | HostedUICustomResourceInputs:
442 | Type: 'Custom::LambdaCallout'
443 | Properties:
444 | ServiceToken: !GetAtt HostedUICustomResource.Arn
445 | userPoolId: !Ref UserPool
446 | hostedUIDomainName: !If [ShouldNotCreateEnvResources, !Ref hostedUIDomainName, !Join ['-',[!Ref hostedUIDomainName, !Ref env]]]
447 | DependsOn: HostedUICustomResourceLogPolicy
448 |
449 |
450 |
451 | HostedUIProvidersCustomResource:
452 | Type: 'AWS::Lambda::Function'
453 | Properties:
454 | Code:
455 | ZipFile: !Join
456 | - |+
457 | - - 'const response = require(''cfn-response'');'
458 | - 'const aws = require(''aws-sdk'');'
459 | - 'const identity = new aws.CognitoIdentityServiceProvider();'
460 | - 'exports.handler = (event, context, callback) => {'
461 | - 'try{'
462 | - ' const userPoolId = event.ResourceProperties.userPoolId;'
463 | - ' let hostedUIProviderMeta = JSON.parse(event.ResourceProperties.hostedUIProviderMeta);'
464 | - ' let hostedUIProviderCreds = JSON.parse(event.ResourceProperties.hostedUIProviderCreds);'
465 | - ' if (event.RequestType == ''Delete'') {'
466 | - ' response.send(event, context, response.SUCCESS, {});'
467 | - ' }'
468 | - ' if (event.RequestType == ''Update'' || event.RequestType == ''Create'') {'
469 | - ' let getRequestParams = (providerName) => {'
470 | - ' let providerMetaIndex = hostedUIProviderMeta.findIndex((provider) => provider.ProviderName === providerName);'
471 | - ' let providerMeta = hostedUIProviderMeta[providerMetaIndex];'
472 | - ' let providerCredsIndex = hostedUIProviderCreds.findIndex((provider) => provider.ProviderName === providerName);'
473 | - ' let providerCreds = hostedUIProviderCreds[providerCredsIndex];'
474 | - ' let requestParams = {'
475 | - ' ProviderDetails: {'
476 | - ' ''client_id'': providerCreds.client_id,'
477 | - ' ''client_secret'': providerCreds.client_secret,'
478 | - ' ''authorize_scopes'': providerMeta.authorize_scopes'
479 | - ' },'
480 | - ' ProviderName: providerMeta.ProviderName,'
481 | - ' UserPoolId: userPoolId,'
482 | - ' AttributeMapping: providerMeta.AttributeMapping'
483 | - ' };'
484 | - ' return requestParams;'
485 | - ' };'
486 | - ' let createIdentityProvider = (providerName) => {'
487 | - ' let requestParams = getRequestParams(providerName);'
488 | - ' requestParams.ProviderType = requestParams.ProviderName;'
489 | - ' return identity.createIdentityProvider(requestParams).promise();'
490 | - ' };'
491 | - ' let updateIdentityProvider = (providerName) => {'
492 | - ' let requestParams = getRequestParams(providerName);'
493 | - ' return identity.updateIdentityProvider(requestParams).promise();'
494 | - ' };'
495 | - ' let deleteIdentityProvider = (providerName) => {'
496 | - ' let params = {ProviderName: providerName, UserPoolId: userPoolId};'
497 | - ' return identity.deleteIdentityProvider(params).promise();'
498 | - ' };'
499 | - ' let providerPromises = [];'
500 | - ' identity.listIdentityProviders({UserPoolId: userPoolId, MaxResults: 60}).promise()'
501 | - ' .then((result) => {'
502 | - ' let providerList = result.Providers.map(provider => provider.ProviderName);'
503 | - ' let providerListInParameters = hostedUIProviderMeta.map(provider => provider.ProviderName);'
504 | - ' hostedUIProviderMeta.forEach((providerMetadata) => {'
505 | - ' if(providerList.indexOf(providerMetadata.ProviderName) > -1) {'
506 | - ' providerPromises.push(updateIdentityProvider(providerMetadata.ProviderName));'
507 | - ' } else {'
508 | - ' providerPromises.push(createIdentityProvider(providerMetadata.ProviderName));'
509 | - ' }'
510 | - ' });'
511 | - ' providerList.forEach((provider) => {'
512 | - ' if(providerListInParameters.indexOf(provider) < 0) {'
513 | - ' providerPromises.push(deleteIdentityProvider(provider));'
514 | - ' }'
515 | - ' });'
516 | - ' return Promise.all(providerPromises);'
517 | - ' }).then(() => {response.send(event, context, response.SUCCESS, {})}).catch((err) => {'
518 | - ' console.log(err.stack); response.send(event, context, response.FAILED, {err})'
519 | - ' });'
520 | - ' } '
521 | - ' } catch(err) { console.log(err.stack); response.send(event, context, response.FAILED, {err});};'
522 | - '} '
523 |
524 | Handler: index.handler
525 | Runtime: nodejs8.10
526 | Timeout: '300'
527 | Role: !GetAtt
528 | - UserPoolClientRole
529 | - Arn
530 | DependsOn: UserPoolClientRole
531 |
532 | HostedUIProvidersCustomResourcePolicy:
533 | Type: 'AWS::IAM::Policy'
534 | Properties:
535 | PolicyName: !Join ['-',[!Ref UserPool, 'hostedUIProvider']]
536 | Roles:
537 | - !If [ShouldNotCreateEnvResources, !Ref userpoolClientLambdaRole, !Join ['',[!Ref userpoolClientLambdaRole, '-', !Ref env]]]
538 | PolicyDocument:
539 | Version: '2012-10-17'
540 | Statement:
541 | - Effect: Allow
542 | Action:
543 | - 'cognito-idp:CreateIdentityProvider'
544 | - 'cognito-idp:UpdateIdentityProvider'
545 | - 'cognito-idp:ListIdentityProviders'
546 | - 'cognito-idp:DeleteIdentityProvider'
547 | Resource: !GetAtt UserPool.Arn
548 | DependsOn: HostedUIProvidersCustomResource
549 |
550 | HostedUIProvidersCustomResourceLogPolicy:
551 | Type: 'AWS::IAM::Policy'
552 | Properties:
553 | PolicyName: !Join ['-',[!Ref UserPool, 'hostedUIProviderLogPolicy']]
554 | Roles:
555 | - !If [ShouldNotCreateEnvResources, !Ref userpoolClientLambdaRole, !Join ['',[!Ref userpoolClientLambdaRole, '-', !Ref env]]]
556 | PolicyDocument:
557 | Version: 2012-10-17
558 | Statement:
559 | - Effect: Allow
560 | Action:
561 | - 'logs:CreateLogGroup'
562 | - 'logs:CreateLogStream'
563 | - 'logs:PutLogEvents'
564 | Resource: !Sub
565 | - arn:aws:logs:${region}:${account}:log-group:/aws/lambda/${lambda}:log-stream:*
566 | - { region: !Ref "AWS::Region", account: !Ref "AWS::AccountId", lambda: !Ref HostedUIProvidersCustomResource}
567 | DependsOn: HostedUIProvidersCustomResourcePolicy
568 |
569 | HostedUIProvidersCustomResourceInputs:
570 | Type: 'Custom::LambdaCallout'
571 | Properties:
572 | ServiceToken: !GetAtt HostedUIProvidersCustomResource.Arn
573 | userPoolId: !Ref UserPool
574 | hostedUIProviderMeta: !Ref hostedUIProviderMeta
575 | hostedUIProviderCreds: !Ref hostedUIProviderCreds
576 | DependsOn: HostedUIProvidersCustomResourceLogPolicy
577 |
578 |
579 | OAuthCustomResource:
580 | Type: 'AWS::Lambda::Function'
581 | Properties:
582 | Code:
583 | ZipFile: !Join
584 | - |+
585 | - - 'const response = require(''cfn-response'');'
586 | - 'const aws = require(''aws-sdk'');'
587 | - 'const identity = new aws.CognitoIdentityServiceProvider();'
588 | - 'exports.handler = (event, context, callback) => {'
589 | - 'try{'
590 | - ' const userPoolId = event.ResourceProperties.userPoolId;'
591 | - ' let webClientId = event.ResourceProperties.webClientId;'
592 | - ' let nativeClientId = event.ResourceProperties.nativeClientId;'
593 | - ' let hostedUIProviderMeta = JSON.parse(event.ResourceProperties.hostedUIProviderMeta);'
594 | - ' let oAuthMetadata = JSON.parse(event.ResourceProperties.oAuthMetadata);'
595 | - ' let providerList = hostedUIProviderMeta.map(provider => provider.ProviderName);'
596 | - ' providerList.push(''COGNITO'');'
597 | - ' if (event.RequestType == ''Delete'') {'
598 | - ' response.send(event, context, response.SUCCESS, {});'
599 | - ' }'
600 | - ' if (event.RequestType == ''Update'' || event.RequestType == ''Create'') {'
601 | - ' let params = {'
602 | - ' UserPoolId: userPoolId,'
603 | - ' AllowedOAuthFlows: oAuthMetadata.AllowedOAuthFlows,'
604 | - ' AllowedOAuthFlowsUserPoolClient: true,'
605 | - ' AllowedOAuthScopes: oAuthMetadata.AllowedOAuthScopes,'
606 | - ' CallbackURLs: oAuthMetadata.CallbackURLs,'
607 | - ' LogoutURLs: oAuthMetadata.LogoutURLs,'
608 | - ' SupportedIdentityProviders: providerList'
609 | - ' };'
610 | - ' let updateUserPoolClientPromises = [];'
611 | - ' params.ClientId = webClientId;'
612 | - ' updateUserPoolClientPromises.push(identity.updateUserPoolClient(params).promise());'
613 | - ' params.ClientId = nativeClientId;'
614 | - ' updateUserPoolClientPromises.push(identity.updateUserPoolClient(params).promise());'
615 | - ' Promise.all(updateUserPoolClientPromises)'
616 | - ' .then(() => {response.send(event, context, response.SUCCESS, {})}).catch((err) => {'
617 | - ' console.log(err.stack); response.send(event, context, response.FAILED, {err});'
618 | - ' });'
619 | - ' }'
620 | - '} catch(err) { console.log(err.stack); response.send(event, context, response.FAILED, {err});};'
621 | - '}'
622 |
623 | Handler: index.handler
624 | Runtime: nodejs8.10
625 | Timeout: '300'
626 | Role: !GetAtt
627 | - UserPoolClientRole
628 | - Arn
629 | DependsOn: HostedUIProvidersCustomResourceInputs
630 |
631 | OAuthCustomResourcePolicy:
632 | Type: 'AWS::IAM::Policy'
633 | Properties:
634 | PolicyName: !Join ['-',[!Ref UserPool, 'OAuth']]
635 | Roles:
636 | - !If [ShouldNotCreateEnvResources, !Ref userpoolClientLambdaRole, !Join ['',[!Ref userpoolClientLambdaRole, '-', !Ref env]]]
637 | PolicyDocument:
638 | Version: '2012-10-17'
639 | Statement:
640 | - Effect: Allow
641 | Action:
642 | - 'cognito-idp:UpdateUserPoolClient'
643 | Resource: !GetAtt UserPool.Arn
644 | DependsOn: OAuthCustomResource
645 |
646 | OAuthCustomResourceLogPolicy:
647 | Type: 'AWS::IAM::Policy'
648 | Properties:
649 | PolicyName: !Join ['-',[!Ref UserPool, 'OAuthLogPolicy']]
650 | Roles:
651 | - !If [ShouldNotCreateEnvResources, !Ref userpoolClientLambdaRole, !Join ['',[!Ref userpoolClientLambdaRole, '-', !Ref env]]]
652 | PolicyDocument:
653 | Version: 2012-10-17
654 | Statement:
655 | - Effect: Allow
656 | Action:
657 | - 'logs:CreateLogGroup'
658 | - 'logs:CreateLogStream'
659 | - 'logs:PutLogEvents'
660 | Resource: !Sub
661 | - arn:aws:logs:${region}:${account}:log-group:/aws/lambda/${lambda}:log-stream:*
662 | - { region: !Ref "AWS::Region", account: !Ref "AWS::AccountId", lambda: !Ref OAuthCustomResource}
663 | DependsOn: OAuthCustomResourcePolicy
664 |
665 | OAuthCustomResourceInputs:
666 | Type: 'Custom::LambdaCallout'
667 | Properties:
668 | ServiceToken: !GetAtt OAuthCustomResource.Arn
669 | userPoolId: !Ref UserPool
670 | hostedUIProviderMeta: !Ref hostedUIProviderMeta
671 | oAuthMetadata: !Ref oAuthMetadata
672 | webClientId: !Ref 'UserPoolClientWeb'
673 | nativeClientId: !Ref 'UserPoolClient'
674 | DependsOn: OAuthCustomResourceLogPolicy
675 |
676 |
677 |
678 |
679 | # BEGIN IDENTITY POOL RESOURCES
680 |
681 |
682 | IdentityPool:
683 | # Always created
684 | Type: AWS::Cognito::IdentityPool
685 | Properties:
686 | IdentityPoolName: !If [ShouldNotCreateEnvResources, 'amplifyauthdemob1911f49_identitypool_b1911f49', !Join ['',['amplifyauthdemob1911f49_identitypool_b1911f49', '__', !Ref env]]]
687 |
688 | CognitoIdentityProviders:
689 | - ClientId: !Ref UserPoolClient
690 | ProviderName: !Sub
691 | - cognito-idp.${region}.amazonaws.com/${client}
692 | - { region: !Ref "AWS::Region", client: !Ref UserPool}
693 | - ClientId: !Ref UserPoolClientWeb
694 | ProviderName: !Sub
695 | - cognito-idp.${region}.amazonaws.com/${client}
696 | - { region: !Ref "AWS::Region", client: !Ref UserPool}
697 |
698 | AllowUnauthenticatedIdentities: !Ref allowUnauthenticatedIdentities
699 |
700 |
701 | DependsOn: UserPoolClientInputs
702 |
703 |
704 | IdentityPoolRoleMap:
705 | # Created to map Auth and Unauth roles to the identity pool
706 | # Depends on Identity Pool for ID ref
707 | Type: AWS::Cognito::IdentityPoolRoleAttachment
708 | Properties:
709 | IdentityPoolId: !Ref IdentityPool
710 | Roles:
711 | unauthenticated: !Ref unauthRoleArn
712 | authenticated: !Ref authRoleArn
713 | DependsOn: IdentityPool
714 |
715 |
716 | Outputs :
717 |
718 | IdentityPoolId:
719 | Value: !Ref 'IdentityPool'
720 | Description: Id for the identity pool
721 | IdentityPoolName:
722 | Value: !GetAtt IdentityPool.Name
723 |
724 |
725 | HostedUIDomain:
726 | Value: !If [ShouldNotCreateEnvResources, !Ref hostedUIDomainName, !Join ['-',[!Ref hostedUIDomainName, !Ref env]]]
727 |
728 |
729 | OAuthMetadata:
730 | Value: !Ref oAuthMetadata
731 |
732 |
733 | UserPoolId:
734 | Value: !Ref 'UserPool'
735 | Description: Id for the user pool
736 | UserPoolName:
737 | Value: !Ref userPoolName
738 | AppClientIDWeb:
739 | Value: !Ref 'UserPoolClientWeb'
740 | Description: The user pool app client id for web
741 | AppClientID:
742 | Value: !Ref 'UserPoolClient'
743 | Description: The user pool app client id
744 | AppClientSecret:
745 | Value: !GetAtt UserPoolClientInputs.appSecret
746 |
747 |
748 |
749 |
750 |
751 |
752 |
--------------------------------------------------------------------------------