├── .gitignore ├── README.md ├── amplify ├── #current-cloud-backend │ ├── amplify-meta.json │ ├── auth │ │ └── tailwindauth0a2d4345 │ │ │ ├── parameters.json │ │ │ └── tailwindauth0a2d4345-cloudformation-template.yml │ ├── backend-config.json │ └── tags.json ├── .config │ ├── local-aws-info.json │ ├── local-env-info.json │ └── project-config.json ├── README.md ├── backend │ ├── amplify-meta.json │ ├── auth │ │ └── tailwindauth0a2d4345 │ │ │ ├── parameters.json │ │ │ └── tailwindauth0a2d4345-cloudformation-template.yml │ ├── awscloudformation │ │ └── nested-cloudformation-stack.yml │ ├── backend-config.json │ └── tags.json ├── cli.json └── team-provider-info.json ├── aws-exports.js ├── components ├── ConfirmSignUp.js ├── ForgotPassword.js ├── ForgotPasswordSubmit.js ├── Input.js ├── Profile.js ├── SignIn.js ├── SignUp.js └── SocialSignIn.js ├── configureAmplify.js ├── header.png ├── package.json ├── pages ├── _app.js ├── api │ └── hello.js ├── auth.js └── index.js ├── postcss.config.js ├── public ├── favicon.ico └── vercel.svg ├── src └── aws-exports.js ├── styles ├── Home.module.css └── globals.css ├── tailwind.config.js └── yarn.lock /.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 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | 27 | # local env files 28 | .env.local 29 | .env.development.local 30 | .env.test.local 31 | .env.production.local 32 | 33 | # vercel 34 | .vercel 35 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Building an authentication flow with Next.js, TailwindCSS, and AWS Amplify 2 | 3 |  4 | 5 | ## To deploy this app: 6 | 7 | 1. Clone the project & install dependencies 8 | 9 | ```sh 10 | git clone git@github.com:dabit3/next.js-tailwind-authentication.git 11 | 12 | npm install 13 | 14 | # or 15 | 16 | yarn 17 | ``` 18 | 19 | 2. Create your Facebook and Google OAuth App IDs 20 | 21 | 3. Initialize the Amplify project' 22 | 23 | ```sh 24 | amplify init 25 | ``` 26 | 27 | 4. Deploy the back end services 28 | 29 | ```sh 30 | amplify push --y 31 | ``` 32 | 33 | 5. Run the app locally: 34 | 35 | ```sh 36 | npm run dev 37 | ``` -------------------------------------------------------------------------------- /amplify/#current-cloud-backend/amplify-meta.json: -------------------------------------------------------------------------------- 1 | { 2 | "providers": { 3 | "awscloudformation": { 4 | "AuthRoleName": "amplify-tailwindauth-dev-162937-authRole", 5 | "UnauthRoleArn": "arn:aws:iam::557458351015:role/amplify-tailwindauth-dev-162937-unauthRole", 6 | "AuthRoleArn": "arn:aws:iam::557458351015:role/amplify-tailwindauth-dev-162937-authRole", 7 | "Region": "us-east-1", 8 | "DeploymentBucketName": "amplify-tailwindauth-dev-162937-deployment", 9 | "UnauthRoleName": "amplify-tailwindauth-dev-162937-unauthRole", 10 | "StackName": "amplify-tailwindauth-dev-162937", 11 | "StackId": "arn:aws:cloudformation:us-east-1:557458351015:stack/amplify-tailwindauth-dev-162937/51446780-5d01-11eb-9ac3-0a6046b66d41", 12 | "AmplifyAppId": "d3l292lxfelsd0" 13 | } 14 | }, 15 | "auth": { 16 | "tailwindauth0a2d4345": { 17 | "service": "Cognito", 18 | "providerPlugin": "awscloudformation", 19 | "dependsOn": [], 20 | "customAuth": false, 21 | "providerMetadata": { 22 | "s3TemplateURL": "https://s3.amazonaws.com/amplify-tailwindauth-dev-162937-deployment/amplify-cfn-templates/auth/tailwindauth0a2d4345-cloudformation-template.yml", 23 | "logicalId": "authtailwindauth0a2d4345" 24 | }, 25 | "lastPushTimeStamp": "2021-01-27T01:22:44.936Z", 26 | "output": { 27 | "AppClientSecret": "3pqv4m1au5fm0l6kric1j4asu9u2rhvgush4ifutci9dgqtp3ck", 28 | "UserPoolId": "us-east-1_PIY96OxtS", 29 | "AppClientIDWeb": "3ndqpf0997g69sga9377uuhn71", 30 | "AppClientID": "2heai65uscpt7m7p70dpbec4c4", 31 | "IdentityPoolId": "us-east-1:327776ec-d1e4-4ad4-99c3-8890815b3090", 32 | "IdentityPoolName": "tailwindauth0a2d4345_identitypool_0a2d4345__dev", 33 | "UserPoolName": "tailwindauth0a2d4345_userpool_0a2d4345", 34 | "HostedUIDomain": "tailwindauth4cf825c5-4cf825c5-dev", 35 | "OAuthMetadata": "{\"AllowedOAuthFlows\":[\"code\"],\"AllowedOAuthScopes\":[\"phone\",\"email\",\"openid\",\"profile\",\"aws.cognito.signin.user.admin\"],\"CallbackURLs\":[\"http://localhost:3000/\"],\"LogoutURLs\":[\"http://localhost:3000/\"]}" 36 | }, 37 | "lastPushDirHash": "A1o7cz0rR/omtHAf7xmfbqI0dXI=" 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /amplify/#current-cloud-backend/auth/tailwindauth0a2d4345/parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "identityPoolName": "tailwindauth0a2d4345_identitypool_0a2d4345", 3 | "allowUnauthenticatedIdentities": false, 4 | "resourceNameTruncated": "tailwi0a2d4345", 5 | "userPoolName": "tailwindauth0a2d4345_userpool_0a2d4345", 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": "tailwi0a2d4345_userpoolclient_lambda_role", 32 | "userpoolClientSetAttributes": false, 33 | "sharedId": "0a2d4345", 34 | "resourceName": "tailwindauth0a2d4345", 35 | "authSelections": "identityPoolAndUserPool", 36 | "authRoleArn": { 37 | "Fn::GetAtt": [ 38 | "AuthRole", 39 | "Arn" 40 | ] 41 | }, 42 | "unauthRoleArn": { 43 | "Fn::GetAtt": [ 44 | "UnauthRole", 45 | "Arn" 46 | ] 47 | }, 48 | "useDefault": "defaultSocial", 49 | "usernameAttributes": [ 50 | "email" 51 | ], 52 | "userPoolGroupList": [], 53 | "serviceName": "Cognito", 54 | "usernameCaseSensitive": false, 55 | "dependsOn": [], 56 | "hostedUI": true, 57 | "hostedUIDomainName": "tailwindauth4cf825c5-4cf825c5", 58 | "authProvidersUserPool": [ 59 | "Facebook", 60 | "Google" 61 | ], 62 | "hostedUIProviderMeta": "[{\"ProviderName\":\"Facebook\",\"authorize_scopes\":\"email,public_profile\",\"AttributeMapping\":{\"email\":\"email\",\"username\":\"id\"}},{\"ProviderName\":\"Google\",\"authorize_scopes\":\"openid email profile\",\"AttributeMapping\":{\"email\":\"email\",\"username\":\"sub\"}}]", 63 | "oAuthMetadata": "{\"AllowedOAuthFlows\":[\"code\"],\"AllowedOAuthScopes\":[\"phone\",\"email\",\"openid\",\"profile\",\"aws.cognito.signin.user.admin\"],\"CallbackURLs\":[\"http://localhost:3000/\"],\"LogoutURLs\":[\"http://localhost:3000/\"]}" 64 | } -------------------------------------------------------------------------------- /amplify/#current-cloud-backend/auth/tailwindauth0a2d4345/tailwindauth0a2d4345-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 | 18 | 19 | allowUnauthenticatedIdentities: 20 | Type: String 21 | 22 | resourceNameTruncated: 23 | Type: String 24 | 25 | 26 | userPoolName: 27 | Type: String 28 | 29 | 30 | 31 | autoVerifiedAttributes: 32 | Type: CommaDelimitedList 33 | 34 | mfaConfiguration: 35 | Type: String 36 | 37 | 38 | 39 | mfaTypes: 40 | Type: CommaDelimitedList 41 | 42 | smsAuthenticationMessage: 43 | Type: String 44 | 45 | 46 | smsVerificationMessage: 47 | Type: String 48 | 49 | 50 | emailVerificationSubject: 51 | Type: String 52 | 53 | 54 | emailVerificationMessage: 55 | Type: String 56 | 57 | 58 | 59 | defaultPasswordPolicy: 60 | Type: String 61 | 62 | 63 | passwordPolicyMinLength: 64 | Type: Number 65 | 66 | 67 | passwordPolicyCharacters: 68 | Type: CommaDelimitedList 69 | 70 | 71 | requiredAttributes: 72 | Type: CommaDelimitedList 73 | 74 | 75 | userpoolClientGenerateSecret: 76 | Type: String 77 | 78 | 79 | userpoolClientRefreshTokenValidity: 80 | Type: Number 81 | 82 | 83 | userpoolClientWriteAttributes: 84 | Type: CommaDelimitedList 85 | 86 | 87 | userpoolClientReadAttributes: 88 | Type: CommaDelimitedList 89 | 90 | userpoolClientLambdaRole: 91 | Type: String 92 | 93 | 94 | 95 | userpoolClientSetAttributes: 96 | Type: String 97 | 98 | sharedId: 99 | Type: String 100 | 101 | 102 | resourceName: 103 | Type: String 104 | 105 | 106 | authSelections: 107 | Type: String 108 | 109 | 110 | 111 | 112 | useDefault: 113 | Type: String 114 | 115 | 116 | 117 | usernameAttributes: 118 | Type: CommaDelimitedList 119 | 120 | 121 | userPoolGroupList: 122 | Type: CommaDelimitedList 123 | 124 | serviceName: 125 | Type: String 126 | 127 | 128 | 129 | usernameCaseSensitive: 130 | Type: String 131 | 132 | 133 | dependsOn: 134 | Type: CommaDelimitedList 135 | 136 | 137 | hostedUI: 138 | Type: String 139 | 140 | hostedUIDomainName: 141 | Type: String 142 | 143 | 144 | 145 | authProvidersUserPool: 146 | Type: CommaDelimitedList 147 | 148 | hostedUIProviderMeta: 149 | Type: String 150 | 151 | 152 | hostedUIProviderCreds: 153 | Type: String 154 | 155 | 156 | oAuthMetadata: 157 | Type: String 158 | 159 | 160 | 161 | Conditions: 162 | ShouldNotCreateEnvResources: !Equals [ !Ref env, NONE ] 163 | 164 | Resources: 165 | 166 | 167 | # BEGIN SNS ROLE RESOURCE 168 | SNSRole: 169 | # Created to allow the UserPool SMS Config to publish via the Simple Notification Service during MFA Process 170 | Type: AWS::IAM::Role 171 | Properties: 172 | RoleName: !If [ShouldNotCreateEnvResources, 'tailwi0a2d4345_sns-role', !Join ['',[ 'sns', '0a2d4345', !Select [3, !Split ['-', !Ref 'AWS::StackName']], '-', !Ref env]]] 173 | AssumeRolePolicyDocument: 174 | Version: "2012-10-17" 175 | Statement: 176 | - Sid: "" 177 | Effect: "Allow" 178 | Principal: 179 | Service: "cognito-idp.amazonaws.com" 180 | Action: 181 | - "sts:AssumeRole" 182 | Condition: 183 | StringEquals: 184 | sts:ExternalId: tailwi0a2d4345_role_external_id 185 | Policies: 186 | - 187 | PolicyName: tailwi0a2d4345-sns-policy 188 | PolicyDocument: 189 | Version: "2012-10-17" 190 | Statement: 191 | - 192 | Effect: "Allow" 193 | Action: 194 | - "sns:Publish" 195 | Resource: "*" 196 | # BEGIN USER POOL RESOURCES 197 | UserPool: 198 | # Created upon user selection 199 | # Depends on SNS Role for Arn if MFA is enabled 200 | Type: AWS::Cognito::UserPool 201 | UpdateReplacePolicy: Retain 202 | Properties: 203 | UserPoolName: !If [ShouldNotCreateEnvResources, !Ref userPoolName, !Join ['',[!Ref userPoolName, '-', !Ref env]]] 204 | 205 | 206 | UsernameConfiguration: 207 | CaseSensitive: false 208 | 209 | Schema: 210 | 211 | - 212 | Name: email 213 | Required: true 214 | Mutable: true 215 | 216 | 217 | 218 | 219 | AutoVerifiedAttributes: !Ref autoVerifiedAttributes 220 | 221 | 222 | EmailVerificationMessage: !Ref emailVerificationMessage 223 | EmailVerificationSubject: !Ref emailVerificationSubject 224 | 225 | Policies: 226 | PasswordPolicy: 227 | MinimumLength: !Ref passwordPolicyMinLength 228 | RequireLowercase: false 229 | RequireNumbers: false 230 | RequireSymbols: false 231 | RequireUppercase: false 232 | 233 | UsernameAttributes: !Ref usernameAttributes 234 | 235 | MfaConfiguration: !Ref mfaConfiguration 236 | SmsVerificationMessage: !Ref smsVerificationMessage 237 | SmsConfiguration: 238 | SnsCallerArn: !GetAtt SNSRole.Arn 239 | ExternalId: tailwi0a2d4345_role_external_id 240 | 241 | 242 | UserPoolClientWeb: 243 | # Created provide application access to user pool 244 | # Depends on UserPool for ID reference 245 | Type: "AWS::Cognito::UserPoolClient" 246 | Properties: 247 | ClientName: tailwi0a2d4345_app_clientWeb 248 | 249 | RefreshTokenValidity: !Ref userpoolClientRefreshTokenValidity 250 | UserPoolId: !Ref UserPool 251 | DependsOn: UserPool 252 | UserPoolClient: 253 | # Created provide application access to user pool 254 | # Depends on UserPool for ID reference 255 | Type: "AWS::Cognito::UserPoolClient" 256 | Properties: 257 | ClientName: tailwi0a2d4345_app_client 258 | 259 | GenerateSecret: !Ref userpoolClientGenerateSecret 260 | RefreshTokenValidity: !Ref userpoolClientRefreshTokenValidity 261 | UserPoolId: !Ref UserPool 262 | DependsOn: UserPool 263 | # BEGIN USER POOL LAMBDA RESOURCES 264 | UserPoolClientRole: 265 | # Created to execute Lambda which gets userpool app client config values 266 | Type: 'AWS::IAM::Role' 267 | Properties: 268 | RoleName: !If [ShouldNotCreateEnvResources, !Ref userpoolClientLambdaRole, !Join ['',['upClientLambdaRole', '0a2d4345', !Select [3, !Split ['-', !Ref 'AWS::StackName']], '-', !Ref env]]] 269 | AssumeRolePolicyDocument: 270 | Version: '2012-10-17' 271 | Statement: 272 | - Effect: Allow 273 | Principal: 274 | Service: 275 | - lambda.amazonaws.com 276 | Action: 277 | - 'sts:AssumeRole' 278 | DependsOn: UserPoolClient 279 | UserPoolClientLambda: 280 | # Lambda which gets userpool app client config values 281 | # Depends on UserPool for id 282 | # Depends on UserPoolClientRole for role ARN 283 | Type: 'AWS::Lambda::Function' 284 | Properties: 285 | Code: 286 | ZipFile: !Join 287 | - |+ 288 | - - 'const response = require(''cfn-response'');' 289 | - 'const aws = require(''aws-sdk'');' 290 | - 'const identity = new aws.CognitoIdentityServiceProvider();' 291 | - 'exports.handler = (event, context, callback) => {' 292 | - ' if (event.RequestType == ''Delete'') { ' 293 | - ' response.send(event, context, response.SUCCESS, {})' 294 | - ' }' 295 | - ' if (event.RequestType == ''Update'' || event.RequestType == ''Create'') {' 296 | - ' const params = {' 297 | - ' ClientId: event.ResourceProperties.clientId,' 298 | - ' UserPoolId: event.ResourceProperties.userpoolId' 299 | - ' };' 300 | - ' identity.describeUserPoolClient(params).promise()' 301 | - ' .then((res) => {' 302 | - ' response.send(event, context, response.SUCCESS, {''appSecret'': res.UserPoolClient.ClientSecret});' 303 | - ' })' 304 | - ' .catch((err) => {' 305 | - ' response.send(event, context, response.FAILED, {err});' 306 | - ' });' 307 | - ' }' 308 | - '};' 309 | Handler: index.handler 310 | Runtime: nodejs10.x 311 | Timeout: '300' 312 | Role: !GetAtt 313 | - UserPoolClientRole 314 | - Arn 315 | DependsOn: UserPoolClientRole 316 | UserPoolClientLambdaPolicy: 317 | # Sets userpool policy for the role that executes the Userpool Client Lambda 318 | # Depends on UserPool for Arn 319 | # Marked as depending on UserPoolClientRole for easier to understand CFN sequencing 320 | Type: 'AWS::IAM::Policy' 321 | Properties: 322 | PolicyName: tailwi0a2d4345_userpoolclient_lambda_iam_policy 323 | Roles: 324 | - !Ref UserPoolClientRole 325 | PolicyDocument: 326 | Version: '2012-10-17' 327 | Statement: 328 | - Effect: Allow 329 | Action: 330 | - 'cognito-idp:DescribeUserPoolClient' 331 | Resource: !GetAtt UserPool.Arn 332 | DependsOn: UserPoolClientLambda 333 | UserPoolClientLogPolicy: 334 | # Sets log policy for the role that executes the Userpool Client Lambda 335 | # Depends on UserPool for Arn 336 | # Marked as depending on UserPoolClientLambdaPolicy for easier to understand CFN sequencing 337 | Type: 'AWS::IAM::Policy' 338 | Properties: 339 | PolicyName: tailwi0a2d4345_userpoolclient_lambda_log_policy 340 | Roles: 341 | - !Ref UserPoolClientRole 342 | PolicyDocument: 343 | Version: 2012-10-17 344 | Statement: 345 | - Effect: Allow 346 | Action: 347 | - 'logs:CreateLogGroup' 348 | - 'logs:CreateLogStream' 349 | - 'logs:PutLogEvents' 350 | Resource: !Sub 351 | - arn:aws:logs:${region}:${account}:log-group:/aws/lambda/${lambda}:log-stream:* 352 | - { region: !Ref "AWS::Region", account: !Ref "AWS::AccountId", lambda: !Ref UserPoolClientLambda} 353 | DependsOn: UserPoolClientLambdaPolicy 354 | UserPoolClientInputs: 355 | # Values passed to Userpool client Lambda 356 | # Depends on UserPool for Id 357 | # Depends on UserPoolClient for Id 358 | # Marked as depending on UserPoolClientLambdaPolicy for easier to understand CFN sequencing 359 | Type: 'Custom::LambdaCallout' 360 | Properties: 361 | ServiceToken: !GetAtt UserPoolClientLambda.Arn 362 | clientId: !Ref UserPoolClient 363 | userpoolId: !Ref UserPool 364 | DependsOn: UserPoolClientLogPolicy 365 | 366 | HostedUICustomResource: 367 | Type: 'AWS::Lambda::Function' 368 | Properties: 369 | Code: 370 | ZipFile: !Join 371 | - |+ 372 | - - 'const response = require(''cfn-response'');' 373 | - 'const aws = require(''aws-sdk'');' 374 | - 'const identity = new aws.CognitoIdentityServiceProvider();' 375 | - 'exports.handler = (event, context, callback) => {' 376 | - ' const userPoolId = event.ResourceProperties.userPoolId;' 377 | - ' const inputDomainName = event.ResourceProperties.hostedUIDomainName;' 378 | - ' let deleteUserPoolDomain = (domainName) => {' 379 | - ' let params = { Domain: domainName, UserPoolId: userPoolId };' 380 | - ' return identity.deleteUserPoolDomain(params).promise();' 381 | - ' };' 382 | - ' if (event.RequestType == ''Delete'') {' 383 | - ' deleteUserPoolDomain(inputDomainName)' 384 | - ' .then(() => {response.send(event, context, response.SUCCESS, {})})' 385 | - ' .catch((err) => { console.log(err); response.send(event, context, response.FAILED, {err}) });' 386 | - ' }' 387 | - ' if (event.RequestType == ''Update'' || event.RequestType == ''Create'') {' 388 | - ' let checkDomainAvailability = (domainName) => {' 389 | - ' let params = { Domain: domainName };' 390 | - ' return identity.describeUserPoolDomain(params).promise().then((res) => {' 391 | - ' if (res.DomainDescription && res.DomainDescription.UserPool) {' 392 | - ' return false;' 393 | - ' }' 394 | - ' return true;' 395 | - ' }).catch((err) => { return false; });' 396 | - ' };' 397 | - ' let createUserPoolDomain = (domainName) => {' 398 | - ' let params = { Domain: domainName, UserPoolId: userPoolId };' 399 | - ' return identity.createUserPoolDomain(params).promise();' 400 | - ' };' 401 | - ' identity.describeUserPool({UserPoolId: userPoolId }).promise().then((result) => {' 402 | - ' if (inputDomainName) {' 403 | - ' if (result.UserPool.Domain === inputDomainName) {' 404 | - ' return;' 405 | - ' } else {' 406 | - ' if (!result.UserPool.Domain) {' 407 | - ' return checkDomainAvailability(inputDomainName).then((isDomainAvailable) => {' 408 | - ' if (isDomainAvailable) {' 409 | - ' return createUserPoolDomain(inputDomainName);' 410 | - ' } else {' 411 | - ' throw new Error(''Domain not available'');' 412 | - ' }' 413 | - ' });' 414 | - ' } else {' 415 | - ' return checkDomainAvailability(inputDomainName).then((isDomainAvailable) => {' 416 | - ' if (isDomainAvailable) {' 417 | - ' return deleteUserPoolDomain(result.UserPool.Domain).then(() => createUserPoolDomain(inputDomainName));' 418 | - ' } else {' 419 | - ' throw new Error(''Domain not available'');' 420 | - ' }' 421 | - ' });' 422 | - ' }' 423 | - ' }' 424 | - ' } else {' 425 | - ' if (result.UserPool.Domain) {' 426 | - ' return deleteUserPoolDomain(result.UserPool.Domain);' 427 | - ' }' 428 | - ' }' 429 | - ' }).then(() => {response.send(event, context, response.SUCCESS, {})}).catch((err) => {' 430 | - ' console.log(err); response.send(event, context, response.FAILED, {err});' 431 | - ' });' 432 | - '}}' 433 | 434 | 435 | Handler: index.handler 436 | Runtime: nodejs10.x 437 | Timeout: '300' 438 | Role: !GetAtt 439 | - UserPoolClientRole 440 | - Arn 441 | DependsOn: UserPoolClientRole 442 | 443 | HostedUICustomResourcePolicy: 444 | Type: 'AWS::IAM::Policy' 445 | Properties: 446 | PolicyName: !Join ['-',[!Ref UserPool, 'hostedUI']] 447 | Roles: 448 | - !Ref UserPoolClientRole 449 | PolicyDocument: 450 | Version: '2012-10-17' 451 | Statement: 452 | - Effect: Allow 453 | Action: 454 | - 'cognito-idp:CreateUserPoolDomain' 455 | - 'cognito-idp:DescribeUserPool' 456 | - 'cognito-idp:DeleteUserPoolDomain' 457 | Resource: !GetAtt UserPool.Arn 458 | - Effect: Allow 459 | Action: 460 | - 'cognito-idp:DescribeUserPoolDomain' 461 | Resource: '*' 462 | DependsOn: HostedUICustomResource 463 | HostedUICustomResourceLogPolicy: 464 | Type: 'AWS::IAM::Policy' 465 | Properties: 466 | PolicyName: !Join ['-',[!Ref UserPool, 'hostedUILogPolicy']] 467 | Roles: 468 | - !Ref UserPoolClientRole 469 | PolicyDocument: 470 | Version: 2012-10-17 471 | Statement: 472 | - Effect: Allow 473 | Action: 474 | - 'logs:CreateLogGroup' 475 | - 'logs:CreateLogStream' 476 | - 'logs:PutLogEvents' 477 | Resource: !Sub 478 | - arn:aws:logs:${region}:${account}:log-group:/aws/lambda/${lambda}:log-stream:* 479 | - { region: !Ref "AWS::Region", account: !Ref "AWS::AccountId", lambda: !Ref HostedUICustomResource} 480 | DependsOn: HostedUICustomResourcePolicy 481 | HostedUICustomResourceInputs: 482 | Type: 'Custom::LambdaCallout' 483 | Properties: 484 | ServiceToken: !GetAtt HostedUICustomResource.Arn 485 | userPoolId: !Ref UserPool 486 | hostedUIDomainName: !If [ShouldNotCreateEnvResources, !Ref hostedUIDomainName, !Join ['-',[!Ref hostedUIDomainName, !Ref env]]] 487 | DependsOn: HostedUICustomResourceLogPolicy 488 | 489 | 490 | 491 | HostedUIProvidersCustomResource: 492 | Type: 'AWS::Lambda::Function' 493 | Properties: 494 | Code: 495 | ZipFile: !Join 496 | - |+ 497 | - - 'const response = require(''cfn-response'');' 498 | - 'const aws = require(''aws-sdk'');' 499 | - 'const identity = new aws.CognitoIdentityServiceProvider();' 500 | - 'exports.handler = (event, context, callback) => {' 501 | - 'try{' 502 | - ' const userPoolId = event.ResourceProperties.userPoolId;' 503 | - ' let hostedUIProviderMeta = JSON.parse(event.ResourceProperties.hostedUIProviderMeta);' 504 | - ' let hostedUIProviderCreds = JSON.parse(event.ResourceProperties.hostedUIProviderCreds);' 505 | - ' if(hostedUIProviderCreds.length === 0) {' 506 | - ' response.send(event, context, response.SUCCESS, {});' 507 | - ' }' 508 | - ' if (event.RequestType == ''Delete'') {' 509 | - ' response.send(event, context, response.SUCCESS, {});' 510 | - ' }' 511 | - ' if (event.RequestType == ''Update'' || event.RequestType == ''Create'') {' 512 | - ' let getRequestParams = (providerName) => {' 513 | - ' let providerMetaIndex = hostedUIProviderMeta.findIndex((provider) => provider.ProviderName === providerName);' 514 | - ' let providerMeta = hostedUIProviderMeta[providerMetaIndex];' 515 | - ' let providerCredsIndex = hostedUIProviderCreds.findIndex((provider) => provider.ProviderName === providerName);' 516 | - ' let providerCreds = hostedUIProviderCreds[providerCredsIndex];' 517 | - ' let requestParams = {' 518 | - ' ProviderDetails: {' 519 | - ' ''client_id'': providerCreds.client_id,' 520 | - ' ''client_secret'': providerCreds.client_secret,' 521 | - ' ''authorize_scopes'': providerMeta.authorize_scopes' 522 | - ' },' 523 | - ' ProviderName: providerMeta.ProviderName,' 524 | - ' UserPoolId: userPoolId,' 525 | - ' AttributeMapping: providerMeta.AttributeMapping' 526 | - ' };' 527 | - ' return requestParams;' 528 | - ' };' 529 | - ' let createIdentityProvider = (providerName) => {' 530 | - ' let requestParams = getRequestParams(providerName);' 531 | - ' requestParams.ProviderType = requestParams.ProviderName;' 532 | - ' return identity.createIdentityProvider(requestParams).promise();' 533 | - ' };' 534 | - ' let updateIdentityProvider = (providerName) => {' 535 | - ' let requestParams = getRequestParams(providerName);' 536 | - ' return identity.updateIdentityProvider(requestParams).promise();' 537 | - ' };' 538 | - ' let deleteIdentityProvider = (providerName) => {' 539 | - ' let params = {ProviderName: providerName, UserPoolId: userPoolId};' 540 | - ' return identity.deleteIdentityProvider(params).promise();' 541 | - ' };' 542 | - ' let providerPromises = [];' 543 | - ' identity.listIdentityProviders({UserPoolId: userPoolId, MaxResults: 60}).promise()' 544 | - ' .then((result) => {' 545 | - ' let providerList = result.Providers.map(provider => provider.ProviderName);' 546 | - ' let providerListInParameters = hostedUIProviderMeta.map(provider => provider.ProviderName);' 547 | - ' hostedUIProviderMeta.forEach((providerMetadata) => {' 548 | - ' if(providerList.indexOf(providerMetadata.ProviderName) > -1) {' 549 | - ' providerPromises.push(updateIdentityProvider(providerMetadata.ProviderName));' 550 | - ' } else {' 551 | - ' providerPromises.push(createIdentityProvider(providerMetadata.ProviderName));' 552 | - ' }' 553 | - ' });' 554 | - ' providerList.forEach((provider) => {' 555 | - ' if(providerListInParameters.indexOf(provider) < 0) {' 556 | - ' providerPromises.push(deleteIdentityProvider(provider));' 557 | - ' }' 558 | - ' });' 559 | - ' return Promise.all(providerPromises);' 560 | - ' }).then(() => {response.send(event, context, response.SUCCESS, {})}).catch((err) => {' 561 | - ' console.log(err.stack); response.send(event, context, response.FAILED, {err})' 562 | - ' });' 563 | - ' } ' 564 | - ' } catch(err) { console.log(err.stack); response.send(event, context, response.FAILED, {err});};' 565 | - '} ' 566 | 567 | Handler: index.handler 568 | Runtime: nodejs10.x 569 | Timeout: '300' 570 | Role: !GetAtt 571 | - UserPoolClientRole 572 | - Arn 573 | DependsOn: UserPoolClientRole 574 | 575 | HostedUIProvidersCustomResourcePolicy: 576 | Type: 'AWS::IAM::Policy' 577 | Properties: 578 | PolicyName: !Join ['-',[!Ref UserPool, 'hostedUIProvider']] 579 | Roles: 580 | - !Ref UserPoolClientRole 581 | PolicyDocument: 582 | Version: '2012-10-17' 583 | Statement: 584 | - Effect: Allow 585 | Action: 586 | - 'cognito-idp:CreateIdentityProvider' 587 | - 'cognito-idp:UpdateIdentityProvider' 588 | - 'cognito-idp:ListIdentityProviders' 589 | - 'cognito-idp:DeleteIdentityProvider' 590 | Resource: !GetAtt UserPool.Arn 591 | DependsOn: HostedUIProvidersCustomResource 592 | 593 | HostedUIProvidersCustomResourceLogPolicy: 594 | Type: 'AWS::IAM::Policy' 595 | Properties: 596 | PolicyName: !Join ['-',[!Ref UserPool, 'hostedUIProviderLogPolicy']] 597 | Roles: 598 | - !Ref UserPoolClientRole 599 | PolicyDocument: 600 | Version: 2012-10-17 601 | Statement: 602 | - Effect: Allow 603 | Action: 604 | - 'logs:CreateLogGroup' 605 | - 'logs:CreateLogStream' 606 | - 'logs:PutLogEvents' 607 | Resource: !Sub 608 | - arn:aws:logs:${region}:${account}:log-group:/aws/lambda/${lambda}:log-stream:* 609 | - { region: !Ref "AWS::Region", account: !Ref "AWS::AccountId", lambda: !Ref HostedUIProvidersCustomResource} 610 | DependsOn: HostedUIProvidersCustomResourcePolicy 611 | 612 | HostedUIProvidersCustomResourceInputs: 613 | Type: 'Custom::LambdaCallout' 614 | Properties: 615 | ServiceToken: !GetAtt HostedUIProvidersCustomResource.Arn 616 | userPoolId: !Ref UserPool 617 | hostedUIProviderMeta: !Ref hostedUIProviderMeta 618 | hostedUIProviderCreds: !Ref hostedUIProviderCreds 619 | DependsOn: HostedUIProvidersCustomResourceLogPolicy 620 | 621 | 622 | OAuthCustomResource: 623 | Type: 'AWS::Lambda::Function' 624 | Properties: 625 | Code: 626 | ZipFile: !Join 627 | - |+ 628 | - - 'const response = require(''cfn-response'');' 629 | - 'const aws = require(''aws-sdk'');' 630 | - 'const identity = new aws.CognitoIdentityServiceProvider();' 631 | - 'exports.handler = (event, context, callback) => {' 632 | - 'try{' 633 | - ' const userPoolId = event.ResourceProperties.userPoolId;' 634 | - ' let webClientId = event.ResourceProperties.webClientId;' 635 | - ' let nativeClientId = event.ResourceProperties.nativeClientId;' 636 | - ' let hostedUIProviderMeta = JSON.parse(event.ResourceProperties.hostedUIProviderMeta);' 637 | - ' let oAuthMetadata = JSON.parse(event.ResourceProperties.oAuthMetadata);' 638 | - ' let providerList = hostedUIProviderMeta.map(provider => provider.ProviderName);' 639 | - ' providerList.push(''COGNITO'');' 640 | - ' if (event.RequestType == ''Delete'') {' 641 | - ' response.send(event, context, response.SUCCESS, {});' 642 | - ' }' 643 | - ' if (event.RequestType == ''Update'' || event.RequestType == ''Create'') {' 644 | - ' let params = {' 645 | - ' UserPoolId: userPoolId,' 646 | - ' AllowedOAuthFlows: oAuthMetadata.AllowedOAuthFlows,' 647 | - ' AllowedOAuthFlowsUserPoolClient: true,' 648 | - ' AllowedOAuthScopes: oAuthMetadata.AllowedOAuthScopes,' 649 | - ' CallbackURLs: oAuthMetadata.CallbackURLs,' 650 | - ' LogoutURLs: oAuthMetadata.LogoutURLs,' 651 | - ' SupportedIdentityProviders: providerList' 652 | - ' };' 653 | - ' let updateUserPoolClientPromises = [];' 654 | - ' params.ClientId = webClientId;' 655 | - ' updateUserPoolClientPromises.push(identity.updateUserPoolClient(params).promise());' 656 | - ' params.ClientId = nativeClientId;' 657 | - ' updateUserPoolClientPromises.push(identity.updateUserPoolClient(params).promise());' 658 | - ' Promise.all(updateUserPoolClientPromises)' 659 | - ' .then(() => {response.send(event, context, response.SUCCESS, {})}).catch((err) => {' 660 | - ' console.log(err.stack); response.send(event, context, response.FAILED, {err});' 661 | - ' });' 662 | - ' }' 663 | - '} catch(err) { console.log(err.stack); response.send(event, context, response.FAILED, {err});};' 664 | - '}' 665 | 666 | Handler: index.handler 667 | Runtime: nodejs10.x 668 | Timeout: '300' 669 | Role: !GetAtt 670 | - UserPoolClientRole 671 | - Arn 672 | DependsOn: HostedUIProvidersCustomResourceInputs 673 | 674 | OAuthCustomResourcePolicy: 675 | Type: 'AWS::IAM::Policy' 676 | Properties: 677 | PolicyName: !Join ['-',[!Ref UserPool, 'OAuth']] 678 | Roles: 679 | - !Ref UserPoolClientRole 680 | PolicyDocument: 681 | Version: '2012-10-17' 682 | Statement: 683 | - Effect: Allow 684 | Action: 685 | - 'cognito-idp:UpdateUserPoolClient' 686 | Resource: !GetAtt UserPool.Arn 687 | DependsOn: OAuthCustomResource 688 | 689 | OAuthCustomResourceLogPolicy: 690 | Type: 'AWS::IAM::Policy' 691 | Properties: 692 | PolicyName: !Join ['-',[!Ref UserPool, 'OAuthLogPolicy']] 693 | Roles: 694 | - !Ref UserPoolClientRole 695 | PolicyDocument: 696 | Version: 2012-10-17 697 | Statement: 698 | - Effect: Allow 699 | Action: 700 | - 'logs:CreateLogGroup' 701 | - 'logs:CreateLogStream' 702 | - 'logs:PutLogEvents' 703 | Resource: !Sub 704 | - arn:aws:logs:${region}:${account}:log-group:/aws/lambda/${lambda}:log-stream:* 705 | - { region: !Ref "AWS::Region", account: !Ref "AWS::AccountId", lambda: !Ref OAuthCustomResource} 706 | DependsOn: OAuthCustomResourcePolicy 707 | 708 | OAuthCustomResourceInputs: 709 | Type: 'Custom::LambdaCallout' 710 | Properties: 711 | ServiceToken: !GetAtt OAuthCustomResource.Arn 712 | userPoolId: !Ref UserPool 713 | hostedUIProviderMeta: !Ref hostedUIProviderMeta 714 | oAuthMetadata: !Ref oAuthMetadata 715 | webClientId: !Ref 'UserPoolClientWeb' 716 | nativeClientId: !Ref 'UserPoolClient' 717 | DependsOn: OAuthCustomResourceLogPolicy 718 | 719 | 720 | 721 | 722 | # BEGIN IDENTITY POOL RESOURCES 723 | 724 | 725 | IdentityPool: 726 | # Always created 727 | Type: AWS::Cognito::IdentityPool 728 | Properties: 729 | IdentityPoolName: !If [ShouldNotCreateEnvResources, 'tailwindauth0a2d4345_identitypool_0a2d4345', !Join ['',['tailwindauth0a2d4345_identitypool_0a2d4345', '__', !Ref env]]] 730 | 731 | CognitoIdentityProviders: 732 | - ClientId: !Ref UserPoolClient 733 | ProviderName: !Sub 734 | - cognito-idp.${region}.amazonaws.com/${client} 735 | - { region: !Ref "AWS::Region", client: !Ref UserPool} 736 | - ClientId: !Ref UserPoolClientWeb 737 | ProviderName: !Sub 738 | - cognito-idp.${region}.amazonaws.com/${client} 739 | - { region: !Ref "AWS::Region", client: !Ref UserPool} 740 | 741 | AllowUnauthenticatedIdentities: !Ref allowUnauthenticatedIdentities 742 | 743 | 744 | DependsOn: UserPoolClientInputs 745 | 746 | 747 | IdentityPoolRoleMap: 748 | # Created to map Auth and Unauth roles to the identity pool 749 | # Depends on Identity Pool for ID ref 750 | Type: AWS::Cognito::IdentityPoolRoleAttachment 751 | Properties: 752 | IdentityPoolId: !Ref IdentityPool 753 | Roles: 754 | unauthenticated: !Ref unauthRoleArn 755 | authenticated: !Ref authRoleArn 756 | DependsOn: IdentityPool 757 | 758 | 759 | Outputs : 760 | 761 | IdentityPoolId: 762 | Value: !Ref 'IdentityPool' 763 | Description: Id for the identity pool 764 | IdentityPoolName: 765 | Value: !GetAtt IdentityPool.Name 766 | 767 | 768 | HostedUIDomain: 769 | Value: !If [ShouldNotCreateEnvResources, !Ref hostedUIDomainName, !Join ['-',[!Ref hostedUIDomainName, !Ref env]]] 770 | 771 | 772 | OAuthMetadata: 773 | Value: !Ref oAuthMetadata 774 | 775 | 776 | UserPoolId: 777 | Value: !Ref 'UserPool' 778 | Description: Id for the user pool 779 | UserPoolName: 780 | Value: !Ref userPoolName 781 | AppClientIDWeb: 782 | Value: !Ref 'UserPoolClientWeb' 783 | Description: The user pool app client id for web 784 | AppClientID: 785 | Value: !Ref 'UserPoolClient' 786 | Description: The user pool app client id 787 | AppClientSecret: 788 | Value: !GetAtt UserPoolClientInputs.appSecret 789 | 790 | 791 | 792 | 793 | 794 | 795 | 796 | -------------------------------------------------------------------------------- /amplify/#current-cloud-backend/backend-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "auth": { 3 | "tailwindauth0a2d4345": { 4 | "service": "Cognito", 5 | "providerPlugin": "awscloudformation", 6 | "dependsOn": [], 7 | "customAuth": false 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /amplify/#current-cloud-backend/tags.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "Key": "user:Stack", 4 | "Value": "{project-env}" 5 | }, 6 | { 7 | "Key": "user:Application", 8 | "Value": "{project-name}" 9 | } 10 | ] -------------------------------------------------------------------------------- /amplify/.config/local-aws-info.json: -------------------------------------------------------------------------------- 1 | { 2 | "dev": { 3 | "configLevel": "project", 4 | "useProfile": true, 5 | "profileName": "default" 6 | } 7 | } -------------------------------------------------------------------------------- /amplify/.config/local-env-info.json: -------------------------------------------------------------------------------- 1 | { 2 | "projectPath": "/Users/dabit/opensource/next-tailwind-auth", 3 | "defaultEditor": "vscode", 4 | "envName": "dev" 5 | } -------------------------------------------------------------------------------- /amplify/.config/project-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "projectName": "tailwindauth", 3 | "version": "3.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 | } -------------------------------------------------------------------------------- /amplify/README.md: -------------------------------------------------------------------------------- 1 | # Getting Started with Amplify CLI 2 | This directory was generated by [Amplify CLI](https://docs.amplify.aws/cli). 3 | 4 | Helpful resources: 5 | - Amplify documentation: https://docs.amplify.aws 6 | - Amplify CLI documentation: https://docs.amplify.aws/cli 7 | - More details on this folder & generated files: https://docs.amplify.aws/cli/reference/files 8 | - Join Amplify's community: https://amplify.aws/community/ 9 | -------------------------------------------------------------------------------- /amplify/backend/amplify-meta.json: -------------------------------------------------------------------------------- 1 | { 2 | "providers": { 3 | "awscloudformation": { 4 | "AuthRoleName": "amplify-tailwindauth-dev-162937-authRole", 5 | "UnauthRoleArn": "arn:aws:iam::557458351015:role/amplify-tailwindauth-dev-162937-unauthRole", 6 | "AuthRoleArn": "arn:aws:iam::557458351015:role/amplify-tailwindauth-dev-162937-authRole", 7 | "Region": "us-east-1", 8 | "DeploymentBucketName": "amplify-tailwindauth-dev-162937-deployment", 9 | "UnauthRoleName": "amplify-tailwindauth-dev-162937-unauthRole", 10 | "StackName": "amplify-tailwindauth-dev-162937", 11 | "StackId": "arn:aws:cloudformation:us-east-1:557458351015:stack/amplify-tailwindauth-dev-162937/51446780-5d01-11eb-9ac3-0a6046b66d41", 12 | "AmplifyAppId": "d3l292lxfelsd0" 13 | } 14 | }, 15 | "auth": { 16 | "tailwindauth0a2d4345": { 17 | "service": "Cognito", 18 | "providerPlugin": "awscloudformation", 19 | "dependsOn": [], 20 | "customAuth": false, 21 | "providerMetadata": { 22 | "s3TemplateURL": "https://s3.amazonaws.com/amplify-tailwindauth-dev-162937-deployment/amplify-cfn-templates/auth/tailwindauth0a2d4345-cloudformation-template.yml", 23 | "logicalId": "authtailwindauth0a2d4345" 24 | }, 25 | "lastPushTimeStamp": "2021-01-27T15:50:01.307Z", 26 | "output": { 27 | "AppClientSecret": "3pqv4m1au5fm0l6kric1j4asu9u2rhvgush4ifutci9dgqtp3ck", 28 | "UserPoolId": "us-east-1_PIY96OxtS", 29 | "AppClientIDWeb": "3ndqpf0997g69sga9377uuhn71", 30 | "AppClientID": "2heai65uscpt7m7p70dpbec4c4", 31 | "IdentityPoolId": "us-east-1:327776ec-d1e4-4ad4-99c3-8890815b3090", 32 | "IdentityPoolName": "tailwindauth0a2d4345_identitypool_0a2d4345__dev", 33 | "UserPoolName": "tailwindauth0a2d4345_userpool_0a2d4345", 34 | "HostedUIDomain": "tailwindauth4cf825c5-4cf825c5-dev", 35 | "OAuthMetadata": "{\"AllowedOAuthFlows\":[\"code\"],\"AllowedOAuthScopes\":[\"phone\",\"email\",\"openid\",\"profile\",\"aws.cognito.signin.user.admin\"],\"CallbackURLs\":[\"http://localhost:3000/\"],\"LogoutURLs\":[\"http://localhost:3000/\"]}" 36 | }, 37 | "lastPushDirHash": "Wv70WKzYBFEc/Q0je0r4lyr+krY=" 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /amplify/backend/auth/tailwindauth0a2d4345/parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "identityPoolName": "tailwindauth0a2d4345_identitypool_0a2d4345", 3 | "allowUnauthenticatedIdentities": false, 4 | "resourceNameTruncated": "tailwi0a2d4345", 5 | "userPoolName": "tailwindauth0a2d4345_userpool_0a2d4345", 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": "tailwi0a2d4345_userpoolclient_lambda_role", 32 | "userpoolClientSetAttributes": false, 33 | "sharedId": "0a2d4345", 34 | "resourceName": "tailwindauth0a2d4345", 35 | "authSelections": "identityPoolAndUserPool", 36 | "authRoleArn": { 37 | "Fn::GetAtt": [ 38 | "AuthRole", 39 | "Arn" 40 | ] 41 | }, 42 | "unauthRoleArn": { 43 | "Fn::GetAtt": [ 44 | "UnauthRole", 45 | "Arn" 46 | ] 47 | }, 48 | "useDefault": "defaultSocial", 49 | "usernameAttributes": [ 50 | "email" 51 | ], 52 | "userPoolGroupList": [], 53 | "serviceName": "Cognito", 54 | "usernameCaseSensitive": false, 55 | "dependsOn": [], 56 | "hostedUI": true, 57 | "hostedUIDomainName": "tailwindauth4cf825c5-4cf825c5", 58 | "authProvidersUserPool": [ 59 | "Facebook", 60 | "Google" 61 | ], 62 | "hostedUIProviderMeta": "[{\"ProviderName\":\"Facebook\",\"authorize_scopes\":\"email,public_profile\",\"AttributeMapping\":{\"email\":\"email\",\"username\":\"id\"}},{\"ProviderName\":\"Google\",\"authorize_scopes\":\"openid email profile\",\"AttributeMapping\":{\"email\":\"email\",\"username\":\"sub\"}}]", 63 | "oAuthMetadata": "{\"AllowedOAuthFlows\":[\"code\"],\"AllowedOAuthScopes\":[\"phone\",\"email\",\"openid\",\"profile\",\"aws.cognito.signin.user.admin\"],\"CallbackURLs\":[\"http://localhost:3000/\"],\"LogoutURLs\":[\"http://localhost:3000/\"]}" 64 | } -------------------------------------------------------------------------------- /amplify/backend/auth/tailwindauth0a2d4345/tailwindauth0a2d4345-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 | 18 | 19 | allowUnauthenticatedIdentities: 20 | Type: String 21 | 22 | resourceNameTruncated: 23 | Type: String 24 | 25 | 26 | userPoolName: 27 | Type: String 28 | 29 | 30 | 31 | autoVerifiedAttributes: 32 | Type: CommaDelimitedList 33 | 34 | mfaConfiguration: 35 | Type: String 36 | 37 | 38 | 39 | mfaTypes: 40 | Type: CommaDelimitedList 41 | 42 | smsAuthenticationMessage: 43 | Type: String 44 | 45 | 46 | smsVerificationMessage: 47 | Type: String 48 | 49 | 50 | emailVerificationSubject: 51 | Type: String 52 | 53 | 54 | emailVerificationMessage: 55 | Type: String 56 | 57 | 58 | 59 | defaultPasswordPolicy: 60 | Type: String 61 | 62 | 63 | passwordPolicyMinLength: 64 | Type: Number 65 | 66 | 67 | passwordPolicyCharacters: 68 | Type: CommaDelimitedList 69 | 70 | 71 | requiredAttributes: 72 | Type: CommaDelimitedList 73 | 74 | 75 | userpoolClientGenerateSecret: 76 | Type: String 77 | 78 | 79 | userpoolClientRefreshTokenValidity: 80 | Type: Number 81 | 82 | 83 | userpoolClientWriteAttributes: 84 | Type: CommaDelimitedList 85 | 86 | 87 | userpoolClientReadAttributes: 88 | Type: CommaDelimitedList 89 | 90 | userpoolClientLambdaRole: 91 | Type: String 92 | 93 | 94 | 95 | userpoolClientSetAttributes: 96 | Type: String 97 | 98 | sharedId: 99 | Type: String 100 | 101 | 102 | resourceName: 103 | Type: String 104 | 105 | 106 | authSelections: 107 | Type: String 108 | 109 | 110 | 111 | 112 | useDefault: 113 | Type: String 114 | 115 | 116 | 117 | usernameAttributes: 118 | Type: CommaDelimitedList 119 | 120 | 121 | userPoolGroupList: 122 | Type: CommaDelimitedList 123 | 124 | serviceName: 125 | Type: String 126 | 127 | 128 | 129 | usernameCaseSensitive: 130 | Type: String 131 | 132 | 133 | dependsOn: 134 | Type: CommaDelimitedList 135 | 136 | 137 | hostedUI: 138 | Type: String 139 | 140 | hostedUIDomainName: 141 | Type: String 142 | 143 | 144 | 145 | authProvidersUserPool: 146 | Type: CommaDelimitedList 147 | 148 | hostedUIProviderMeta: 149 | Type: String 150 | 151 | 152 | hostedUIProviderCreds: 153 | Type: String 154 | 155 | 156 | oAuthMetadata: 157 | Type: String 158 | 159 | 160 | 161 | Conditions: 162 | ShouldNotCreateEnvResources: !Equals [ !Ref env, NONE ] 163 | 164 | Resources: 165 | 166 | 167 | # BEGIN SNS ROLE RESOURCE 168 | SNSRole: 169 | # Created to allow the UserPool SMS Config to publish via the Simple Notification Service during MFA Process 170 | Type: AWS::IAM::Role 171 | Properties: 172 | RoleName: !If [ShouldNotCreateEnvResources, 'tailwi0a2d4345_sns-role', !Join ['',[ 'sns', '0a2d4345', !Select [3, !Split ['-', !Ref 'AWS::StackName']], '-', !Ref env]]] 173 | AssumeRolePolicyDocument: 174 | Version: "2012-10-17" 175 | Statement: 176 | - Sid: "" 177 | Effect: "Allow" 178 | Principal: 179 | Service: "cognito-idp.amazonaws.com" 180 | Action: 181 | - "sts:AssumeRole" 182 | Condition: 183 | StringEquals: 184 | sts:ExternalId: tailwi0a2d4345_role_external_id 185 | Policies: 186 | - 187 | PolicyName: tailwi0a2d4345-sns-policy 188 | PolicyDocument: 189 | Version: "2012-10-17" 190 | Statement: 191 | - 192 | Effect: "Allow" 193 | Action: 194 | - "sns:Publish" 195 | Resource: "*" 196 | # BEGIN USER POOL RESOURCES 197 | UserPool: 198 | # Created upon user selection 199 | # Depends on SNS Role for Arn if MFA is enabled 200 | Type: AWS::Cognito::UserPool 201 | UpdateReplacePolicy: Retain 202 | Properties: 203 | UserPoolName: !If [ShouldNotCreateEnvResources, !Ref userPoolName, !Join ['',[!Ref userPoolName, '-', !Ref env]]] 204 | 205 | 206 | UsernameConfiguration: 207 | CaseSensitive: false 208 | 209 | Schema: 210 | 211 | - 212 | Name: email 213 | Required: true 214 | Mutable: true 215 | 216 | 217 | 218 | 219 | AutoVerifiedAttributes: !Ref autoVerifiedAttributes 220 | 221 | 222 | EmailVerificationMessage: !Ref emailVerificationMessage 223 | EmailVerificationSubject: !Ref emailVerificationSubject 224 | 225 | Policies: 226 | PasswordPolicy: 227 | MinimumLength: !Ref passwordPolicyMinLength 228 | RequireLowercase: false 229 | RequireNumbers: false 230 | RequireSymbols: false 231 | RequireUppercase: false 232 | 233 | UsernameAttributes: !Ref usernameAttributes 234 | 235 | MfaConfiguration: !Ref mfaConfiguration 236 | SmsVerificationMessage: !Ref smsVerificationMessage 237 | SmsConfiguration: 238 | SnsCallerArn: !GetAtt SNSRole.Arn 239 | ExternalId: tailwi0a2d4345_role_external_id 240 | 241 | 242 | UserPoolClientWeb: 243 | # Created provide application access to user pool 244 | # Depends on UserPool for ID reference 245 | Type: "AWS::Cognito::UserPoolClient" 246 | Properties: 247 | ClientName: tailwi0a2d4345_app_clientWeb 248 | 249 | RefreshTokenValidity: !Ref userpoolClientRefreshTokenValidity 250 | UserPoolId: !Ref UserPool 251 | DependsOn: UserPool 252 | UserPoolClient: 253 | # Created provide application access to user pool 254 | # Depends on UserPool for ID reference 255 | Type: "AWS::Cognito::UserPoolClient" 256 | Properties: 257 | ClientName: tailwi0a2d4345_app_client 258 | 259 | GenerateSecret: !Ref userpoolClientGenerateSecret 260 | RefreshTokenValidity: !Ref userpoolClientRefreshTokenValidity 261 | UserPoolId: !Ref UserPool 262 | DependsOn: UserPool 263 | # BEGIN USER POOL LAMBDA RESOURCES 264 | UserPoolClientRole: 265 | # Created to execute Lambda which gets userpool app client config values 266 | Type: 'AWS::IAM::Role' 267 | Properties: 268 | RoleName: !If [ShouldNotCreateEnvResources, !Ref userpoolClientLambdaRole, !Join ['',['upClientLambdaRole', '0a2d4345', !Select [3, !Split ['-', !Ref 'AWS::StackName']], '-', !Ref env]]] 269 | AssumeRolePolicyDocument: 270 | Version: '2012-10-17' 271 | Statement: 272 | - Effect: Allow 273 | Principal: 274 | Service: 275 | - lambda.amazonaws.com 276 | Action: 277 | - 'sts:AssumeRole' 278 | DependsOn: UserPoolClient 279 | UserPoolClientLambda: 280 | # Lambda which gets userpool app client config values 281 | # Depends on UserPool for id 282 | # Depends on UserPoolClientRole for role ARN 283 | Type: 'AWS::Lambda::Function' 284 | Properties: 285 | Code: 286 | ZipFile: !Join 287 | - |+ 288 | - - 'const response = require(''cfn-response'');' 289 | - 'const aws = require(''aws-sdk'');' 290 | - 'const identity = new aws.CognitoIdentityServiceProvider();' 291 | - 'exports.handler = (event, context, callback) => {' 292 | - ' if (event.RequestType == ''Delete'') { ' 293 | - ' response.send(event, context, response.SUCCESS, {})' 294 | - ' }' 295 | - ' if (event.RequestType == ''Update'' || event.RequestType == ''Create'') {' 296 | - ' const params = {' 297 | - ' ClientId: event.ResourceProperties.clientId,' 298 | - ' UserPoolId: event.ResourceProperties.userpoolId' 299 | - ' };' 300 | - ' identity.describeUserPoolClient(params).promise()' 301 | - ' .then((res) => {' 302 | - ' response.send(event, context, response.SUCCESS, {''appSecret'': res.UserPoolClient.ClientSecret});' 303 | - ' })' 304 | - ' .catch((err) => {' 305 | - ' response.send(event, context, response.FAILED, {err});' 306 | - ' });' 307 | - ' }' 308 | - '};' 309 | Handler: index.handler 310 | Runtime: nodejs10.x 311 | Timeout: '300' 312 | Role: !GetAtt 313 | - UserPoolClientRole 314 | - Arn 315 | DependsOn: UserPoolClientRole 316 | UserPoolClientLambdaPolicy: 317 | # Sets userpool policy for the role that executes the Userpool Client Lambda 318 | # Depends on UserPool for Arn 319 | # Marked as depending on UserPoolClientRole for easier to understand CFN sequencing 320 | Type: 'AWS::IAM::Policy' 321 | Properties: 322 | PolicyName: tailwi0a2d4345_userpoolclient_lambda_iam_policy 323 | Roles: 324 | - !Ref UserPoolClientRole 325 | PolicyDocument: 326 | Version: '2012-10-17' 327 | Statement: 328 | - Effect: Allow 329 | Action: 330 | - 'cognito-idp:DescribeUserPoolClient' 331 | Resource: !GetAtt UserPool.Arn 332 | DependsOn: UserPoolClientLambda 333 | UserPoolClientLogPolicy: 334 | # Sets log policy for the role that executes the Userpool Client Lambda 335 | # Depends on UserPool for Arn 336 | # Marked as depending on UserPoolClientLambdaPolicy for easier to understand CFN sequencing 337 | Type: 'AWS::IAM::Policy' 338 | Properties: 339 | PolicyName: tailwi0a2d4345_userpoolclient_lambda_log_policy 340 | Roles: 341 | - !Ref UserPoolClientRole 342 | PolicyDocument: 343 | Version: 2012-10-17 344 | Statement: 345 | - Effect: Allow 346 | Action: 347 | - 'logs:CreateLogGroup' 348 | - 'logs:CreateLogStream' 349 | - 'logs:PutLogEvents' 350 | Resource: !Sub 351 | - arn:aws:logs:${region}:${account}:log-group:/aws/lambda/${lambda}:log-stream:* 352 | - { region: !Ref "AWS::Region", account: !Ref "AWS::AccountId", lambda: !Ref UserPoolClientLambda} 353 | DependsOn: UserPoolClientLambdaPolicy 354 | UserPoolClientInputs: 355 | # Values passed to Userpool client Lambda 356 | # Depends on UserPool for Id 357 | # Depends on UserPoolClient for Id 358 | # Marked as depending on UserPoolClientLambdaPolicy for easier to understand CFN sequencing 359 | Type: 'Custom::LambdaCallout' 360 | Properties: 361 | ServiceToken: !GetAtt UserPoolClientLambda.Arn 362 | clientId: !Ref UserPoolClient 363 | userpoolId: !Ref UserPool 364 | DependsOn: UserPoolClientLogPolicy 365 | 366 | HostedUICustomResource: 367 | Type: 'AWS::Lambda::Function' 368 | Properties: 369 | Code: 370 | ZipFile: !Join 371 | - |+ 372 | - - 'const response = require(''cfn-response'');' 373 | - 'const aws = require(''aws-sdk'');' 374 | - 'const identity = new aws.CognitoIdentityServiceProvider();' 375 | - 'exports.handler = (event, context, callback) => {' 376 | - ' const userPoolId = event.ResourceProperties.userPoolId;' 377 | - ' const inputDomainName = event.ResourceProperties.hostedUIDomainName;' 378 | - ' let deleteUserPoolDomain = (domainName) => {' 379 | - ' let params = { Domain: domainName, UserPoolId: userPoolId };' 380 | - ' return identity.deleteUserPoolDomain(params).promise();' 381 | - ' };' 382 | - ' if (event.RequestType == ''Delete'') {' 383 | - ' deleteUserPoolDomain(inputDomainName)' 384 | - ' .then(() => {response.send(event, context, response.SUCCESS, {})})' 385 | - ' .catch((err) => { console.log(err); response.send(event, context, response.FAILED, {err}) });' 386 | - ' }' 387 | - ' if (event.RequestType == ''Update'' || event.RequestType == ''Create'') {' 388 | - ' let checkDomainAvailability = (domainName) => {' 389 | - ' let params = { Domain: domainName };' 390 | - ' return identity.describeUserPoolDomain(params).promise().then((res) => {' 391 | - ' if (res.DomainDescription && res.DomainDescription.UserPool) {' 392 | - ' return false;' 393 | - ' }' 394 | - ' return true;' 395 | - ' }).catch((err) => { return false; });' 396 | - ' };' 397 | - ' let createUserPoolDomain = (domainName) => {' 398 | - ' let params = { Domain: domainName, UserPoolId: userPoolId };' 399 | - ' return identity.createUserPoolDomain(params).promise();' 400 | - ' };' 401 | - ' identity.describeUserPool({UserPoolId: userPoolId }).promise().then((result) => {' 402 | - ' if (inputDomainName) {' 403 | - ' if (result.UserPool.Domain === inputDomainName) {' 404 | - ' return;' 405 | - ' } else {' 406 | - ' if (!result.UserPool.Domain) {' 407 | - ' return checkDomainAvailability(inputDomainName).then((isDomainAvailable) => {' 408 | - ' if (isDomainAvailable) {' 409 | - ' return createUserPoolDomain(inputDomainName);' 410 | - ' } else {' 411 | - ' throw new Error(''Domain not available'');' 412 | - ' }' 413 | - ' });' 414 | - ' } else {' 415 | - ' return checkDomainAvailability(inputDomainName).then((isDomainAvailable) => {' 416 | - ' if (isDomainAvailable) {' 417 | - ' return deleteUserPoolDomain(result.UserPool.Domain).then(() => createUserPoolDomain(inputDomainName));' 418 | - ' } else {' 419 | - ' throw new Error(''Domain not available'');' 420 | - ' }' 421 | - ' });' 422 | - ' }' 423 | - ' }' 424 | - ' } else {' 425 | - ' if (result.UserPool.Domain) {' 426 | - ' return deleteUserPoolDomain(result.UserPool.Domain);' 427 | - ' }' 428 | - ' }' 429 | - ' }).then(() => {response.send(event, context, response.SUCCESS, {})}).catch((err) => {' 430 | - ' console.log(err); response.send(event, context, response.FAILED, {err});' 431 | - ' });' 432 | - '}}' 433 | 434 | 435 | Handler: index.handler 436 | Runtime: nodejs10.x 437 | Timeout: '300' 438 | Role: !GetAtt 439 | - UserPoolClientRole 440 | - Arn 441 | DependsOn: UserPoolClientRole 442 | 443 | HostedUICustomResourcePolicy: 444 | Type: 'AWS::IAM::Policy' 445 | Properties: 446 | PolicyName: !Join ['-',[!Ref UserPool, 'hostedUI']] 447 | Roles: 448 | - !Ref UserPoolClientRole 449 | PolicyDocument: 450 | Version: '2012-10-17' 451 | Statement: 452 | - Effect: Allow 453 | Action: 454 | - 'cognito-idp:CreateUserPoolDomain' 455 | - 'cognito-idp:DescribeUserPool' 456 | - 'cognito-idp:DeleteUserPoolDomain' 457 | Resource: !GetAtt UserPool.Arn 458 | - Effect: Allow 459 | Action: 460 | - 'cognito-idp:DescribeUserPoolDomain' 461 | Resource: '*' 462 | DependsOn: HostedUICustomResource 463 | HostedUICustomResourceLogPolicy: 464 | Type: 'AWS::IAM::Policy' 465 | Properties: 466 | PolicyName: !Join ['-',[!Ref UserPool, 'hostedUILogPolicy']] 467 | Roles: 468 | - !Ref UserPoolClientRole 469 | PolicyDocument: 470 | Version: 2012-10-17 471 | Statement: 472 | - Effect: Allow 473 | Action: 474 | - 'logs:CreateLogGroup' 475 | - 'logs:CreateLogStream' 476 | - 'logs:PutLogEvents' 477 | Resource: !Sub 478 | - arn:aws:logs:${region}:${account}:log-group:/aws/lambda/${lambda}:log-stream:* 479 | - { region: !Ref "AWS::Region", account: !Ref "AWS::AccountId", lambda: !Ref HostedUICustomResource} 480 | DependsOn: HostedUICustomResourcePolicy 481 | HostedUICustomResourceInputs: 482 | Type: 'Custom::LambdaCallout' 483 | Properties: 484 | ServiceToken: !GetAtt HostedUICustomResource.Arn 485 | userPoolId: !Ref UserPool 486 | hostedUIDomainName: !If [ShouldNotCreateEnvResources, !Ref hostedUIDomainName, !Join ['-',[!Ref hostedUIDomainName, !Ref env]]] 487 | DependsOn: HostedUICustomResourceLogPolicy 488 | 489 | 490 | 491 | HostedUIProvidersCustomResource: 492 | Type: 'AWS::Lambda::Function' 493 | Properties: 494 | Code: 495 | ZipFile: !Join 496 | - |+ 497 | - - 'const response = require(''cfn-response'');' 498 | - 'const aws = require(''aws-sdk'');' 499 | - 'const identity = new aws.CognitoIdentityServiceProvider();' 500 | - 'exports.handler = (event, context, callback) => {' 501 | - 'try{' 502 | - ' const userPoolId = event.ResourceProperties.userPoolId;' 503 | - ' let hostedUIProviderMeta = JSON.parse(event.ResourceProperties.hostedUIProviderMeta);' 504 | - ' let hostedUIProviderCreds = JSON.parse(event.ResourceProperties.hostedUIProviderCreds);' 505 | - ' if(hostedUIProviderCreds.length === 0) {' 506 | - ' response.send(event, context, response.SUCCESS, {});' 507 | - ' }' 508 | - ' if (event.RequestType == ''Delete'') {' 509 | - ' response.send(event, context, response.SUCCESS, {});' 510 | - ' }' 511 | - ' if (event.RequestType == ''Update'' || event.RequestType == ''Create'') {' 512 | - ' let getRequestParams = (providerName) => {' 513 | - ' let providerMetaIndex = hostedUIProviderMeta.findIndex((provider) => provider.ProviderName === providerName);' 514 | - ' let providerMeta = hostedUIProviderMeta[providerMetaIndex];' 515 | - ' let providerCredsIndex = hostedUIProviderCreds.findIndex((provider) => provider.ProviderName === providerName);' 516 | - ' let providerCreds = hostedUIProviderCreds[providerCredsIndex];' 517 | - ' let requestParams = {' 518 | - ' ProviderDetails: {' 519 | - ' ''client_id'': providerCreds.client_id,' 520 | - ' ''client_secret'': providerCreds.client_secret,' 521 | - ' ''authorize_scopes'': providerMeta.authorize_scopes' 522 | - ' },' 523 | - ' ProviderName: providerMeta.ProviderName,' 524 | - ' UserPoolId: userPoolId,' 525 | - ' AttributeMapping: providerMeta.AttributeMapping' 526 | - ' };' 527 | - ' return requestParams;' 528 | - ' };' 529 | - ' let createIdentityProvider = (providerName) => {' 530 | - ' let requestParams = getRequestParams(providerName);' 531 | - ' requestParams.ProviderType = requestParams.ProviderName;' 532 | - ' return identity.createIdentityProvider(requestParams).promise();' 533 | - ' };' 534 | - ' let updateIdentityProvider = (providerName) => {' 535 | - ' let requestParams = getRequestParams(providerName);' 536 | - ' return identity.updateIdentityProvider(requestParams).promise();' 537 | - ' };' 538 | - ' let deleteIdentityProvider = (providerName) => {' 539 | - ' let params = {ProviderName: providerName, UserPoolId: userPoolId};' 540 | - ' return identity.deleteIdentityProvider(params).promise();' 541 | - ' };' 542 | - ' let providerPromises = [];' 543 | - ' identity.listIdentityProviders({UserPoolId: userPoolId, MaxResults: 60}).promise()' 544 | - ' .then((result) => {' 545 | - ' let providerList = result.Providers.map(provider => provider.ProviderName);' 546 | - ' let providerListInParameters = hostedUIProviderMeta.map(provider => provider.ProviderName);' 547 | - ' hostedUIProviderMeta.forEach((providerMetadata) => {' 548 | - ' if(providerList.indexOf(providerMetadata.ProviderName) > -1) {' 549 | - ' providerPromises.push(updateIdentityProvider(providerMetadata.ProviderName));' 550 | - ' } else {' 551 | - ' providerPromises.push(createIdentityProvider(providerMetadata.ProviderName));' 552 | - ' }' 553 | - ' });' 554 | - ' providerList.forEach((provider) => {' 555 | - ' if(providerListInParameters.indexOf(provider) < 0) {' 556 | - ' providerPromises.push(deleteIdentityProvider(provider));' 557 | - ' }' 558 | - ' });' 559 | - ' return Promise.all(providerPromises);' 560 | - ' }).then(() => {response.send(event, context, response.SUCCESS, {})}).catch((err) => {' 561 | - ' console.log(err.stack); response.send(event, context, response.FAILED, {err})' 562 | - ' });' 563 | - ' } ' 564 | - ' } catch(err) { console.log(err.stack); response.send(event, context, response.FAILED, {err});};' 565 | - '} ' 566 | 567 | Handler: index.handler 568 | Runtime: nodejs10.x 569 | Timeout: '300' 570 | Role: !GetAtt 571 | - UserPoolClientRole 572 | - Arn 573 | DependsOn: UserPoolClientRole 574 | 575 | HostedUIProvidersCustomResourcePolicy: 576 | Type: 'AWS::IAM::Policy' 577 | Properties: 578 | PolicyName: !Join ['-',[!Ref UserPool, 'hostedUIProvider']] 579 | Roles: 580 | - !Ref UserPoolClientRole 581 | PolicyDocument: 582 | Version: '2012-10-17' 583 | Statement: 584 | - Effect: Allow 585 | Action: 586 | - 'cognito-idp:CreateIdentityProvider' 587 | - 'cognito-idp:UpdateIdentityProvider' 588 | - 'cognito-idp:ListIdentityProviders' 589 | - 'cognito-idp:DeleteIdentityProvider' 590 | Resource: !GetAtt UserPool.Arn 591 | DependsOn: HostedUIProvidersCustomResource 592 | 593 | HostedUIProvidersCustomResourceLogPolicy: 594 | Type: 'AWS::IAM::Policy' 595 | Properties: 596 | PolicyName: !Join ['-',[!Ref UserPool, 'hostedUIProviderLogPolicy']] 597 | Roles: 598 | - !Ref UserPoolClientRole 599 | PolicyDocument: 600 | Version: 2012-10-17 601 | Statement: 602 | - Effect: Allow 603 | Action: 604 | - 'logs:CreateLogGroup' 605 | - 'logs:CreateLogStream' 606 | - 'logs:PutLogEvents' 607 | Resource: !Sub 608 | - arn:aws:logs:${region}:${account}:log-group:/aws/lambda/${lambda}:log-stream:* 609 | - { region: !Ref "AWS::Region", account: !Ref "AWS::AccountId", lambda: !Ref HostedUIProvidersCustomResource} 610 | DependsOn: HostedUIProvidersCustomResourcePolicy 611 | 612 | HostedUIProvidersCustomResourceInputs: 613 | Type: 'Custom::LambdaCallout' 614 | Properties: 615 | ServiceToken: !GetAtt HostedUIProvidersCustomResource.Arn 616 | userPoolId: !Ref UserPool 617 | hostedUIProviderMeta: !Ref hostedUIProviderMeta 618 | hostedUIProviderCreds: !Ref hostedUIProviderCreds 619 | DependsOn: HostedUIProvidersCustomResourceLogPolicy 620 | 621 | 622 | OAuthCustomResource: 623 | Type: 'AWS::Lambda::Function' 624 | Properties: 625 | Code: 626 | ZipFile: !Join 627 | - |+ 628 | - - 'const response = require(''cfn-response'');' 629 | - 'const aws = require(''aws-sdk'');' 630 | - 'const identity = new aws.CognitoIdentityServiceProvider();' 631 | - 'exports.handler = (event, context, callback) => {' 632 | - 'try{' 633 | - ' const userPoolId = event.ResourceProperties.userPoolId;' 634 | - ' let webClientId = event.ResourceProperties.webClientId;' 635 | - ' let nativeClientId = event.ResourceProperties.nativeClientId;' 636 | - ' let hostedUIProviderMeta = JSON.parse(event.ResourceProperties.hostedUIProviderMeta);' 637 | - ' let oAuthMetadata = JSON.parse(event.ResourceProperties.oAuthMetadata);' 638 | - ' let providerList = hostedUIProviderMeta.map(provider => provider.ProviderName);' 639 | - ' providerList.push(''COGNITO'');' 640 | - ' if (event.RequestType == ''Delete'') {' 641 | - ' response.send(event, context, response.SUCCESS, {});' 642 | - ' }' 643 | - ' if (event.RequestType == ''Update'' || event.RequestType == ''Create'') {' 644 | - ' let params = {' 645 | - ' UserPoolId: userPoolId,' 646 | - ' AllowedOAuthFlows: oAuthMetadata.AllowedOAuthFlows,' 647 | - ' AllowedOAuthFlowsUserPoolClient: true,' 648 | - ' AllowedOAuthScopes: oAuthMetadata.AllowedOAuthScopes,' 649 | - ' CallbackURLs: oAuthMetadata.CallbackURLs,' 650 | - ' LogoutURLs: oAuthMetadata.LogoutURLs,' 651 | - ' SupportedIdentityProviders: providerList' 652 | - ' };' 653 | - ' let updateUserPoolClientPromises = [];' 654 | - ' params.ClientId = webClientId;' 655 | - ' updateUserPoolClientPromises.push(identity.updateUserPoolClient(params).promise());' 656 | - ' params.ClientId = nativeClientId;' 657 | - ' updateUserPoolClientPromises.push(identity.updateUserPoolClient(params).promise());' 658 | - ' Promise.all(updateUserPoolClientPromises)' 659 | - ' .then(() => {response.send(event, context, response.SUCCESS, {})}).catch((err) => {' 660 | - ' console.log(err.stack); response.send(event, context, response.FAILED, {err});' 661 | - ' });' 662 | - ' }' 663 | - '} catch(err) { console.log(err.stack); response.send(event, context, response.FAILED, {err});};' 664 | - '}' 665 | 666 | Handler: index.handler 667 | Runtime: nodejs10.x 668 | Timeout: '300' 669 | Role: !GetAtt 670 | - UserPoolClientRole 671 | - Arn 672 | DependsOn: HostedUIProvidersCustomResourceInputs 673 | 674 | OAuthCustomResourcePolicy: 675 | Type: 'AWS::IAM::Policy' 676 | Properties: 677 | PolicyName: !Join ['-',[!Ref UserPool, 'OAuth']] 678 | Roles: 679 | - !Ref UserPoolClientRole 680 | PolicyDocument: 681 | Version: '2012-10-17' 682 | Statement: 683 | - Effect: Allow 684 | Action: 685 | - 'cognito-idp:UpdateUserPoolClient' 686 | Resource: !GetAtt UserPool.Arn 687 | DependsOn: OAuthCustomResource 688 | 689 | OAuthCustomResourceLogPolicy: 690 | Type: 'AWS::IAM::Policy' 691 | Properties: 692 | PolicyName: !Join ['-',[!Ref UserPool, 'OAuthLogPolicy']] 693 | Roles: 694 | - !Ref UserPoolClientRole 695 | PolicyDocument: 696 | Version: 2012-10-17 697 | Statement: 698 | - Effect: Allow 699 | Action: 700 | - 'logs:CreateLogGroup' 701 | - 'logs:CreateLogStream' 702 | - 'logs:PutLogEvents' 703 | Resource: !Sub 704 | - arn:aws:logs:${region}:${account}:log-group:/aws/lambda/${lambda}:log-stream:* 705 | - { region: !Ref "AWS::Region", account: !Ref "AWS::AccountId", lambda: !Ref OAuthCustomResource} 706 | DependsOn: OAuthCustomResourcePolicy 707 | 708 | OAuthCustomResourceInputs: 709 | Type: 'Custom::LambdaCallout' 710 | Properties: 711 | ServiceToken: !GetAtt OAuthCustomResource.Arn 712 | userPoolId: !Ref UserPool 713 | hostedUIProviderMeta: !Ref hostedUIProviderMeta 714 | oAuthMetadata: !Ref oAuthMetadata 715 | webClientId: !Ref 'UserPoolClientWeb' 716 | nativeClientId: !Ref 'UserPoolClient' 717 | DependsOn: OAuthCustomResourceLogPolicy 718 | 719 | 720 | 721 | 722 | # BEGIN IDENTITY POOL RESOURCES 723 | 724 | 725 | IdentityPool: 726 | # Always created 727 | Type: AWS::Cognito::IdentityPool 728 | Properties: 729 | IdentityPoolName: !If [ShouldNotCreateEnvResources, 'tailwindauth0a2d4345_identitypool_0a2d4345', !Join ['',['tailwindauth0a2d4345_identitypool_0a2d4345', '__', !Ref env]]] 730 | 731 | CognitoIdentityProviders: 732 | - ClientId: !Ref UserPoolClient 733 | ProviderName: !Sub 734 | - cognito-idp.${region}.amazonaws.com/${client} 735 | - { region: !Ref "AWS::Region", client: !Ref UserPool} 736 | - ClientId: !Ref UserPoolClientWeb 737 | ProviderName: !Sub 738 | - cognito-idp.${region}.amazonaws.com/${client} 739 | - { region: !Ref "AWS::Region", client: !Ref UserPool} 740 | 741 | AllowUnauthenticatedIdentities: !Ref allowUnauthenticatedIdentities 742 | 743 | 744 | DependsOn: UserPoolClientInputs 745 | 746 | 747 | IdentityPoolRoleMap: 748 | # Created to map Auth and Unauth roles to the identity pool 749 | # Depends on Identity Pool for ID ref 750 | Type: AWS::Cognito::IdentityPoolRoleAttachment 751 | Properties: 752 | IdentityPoolId: !Ref IdentityPool 753 | Roles: 754 | unauthenticated: !Ref unauthRoleArn 755 | authenticated: !Ref authRoleArn 756 | DependsOn: IdentityPool 757 | 758 | 759 | Outputs : 760 | 761 | IdentityPoolId: 762 | Value: !Ref 'IdentityPool' 763 | Description: Id for the identity pool 764 | IdentityPoolName: 765 | Value: !GetAtt IdentityPool.Name 766 | 767 | 768 | HostedUIDomain: 769 | Value: !If [ShouldNotCreateEnvResources, !Ref hostedUIDomainName, !Join ['-',[!Ref hostedUIDomainName, !Ref env]]] 770 | 771 | 772 | OAuthMetadata: 773 | Value: !Ref oAuthMetadata 774 | 775 | 776 | UserPoolId: 777 | Value: !Ref 'UserPool' 778 | Description: Id for the user pool 779 | UserPoolName: 780 | Value: !Ref userPoolName 781 | AppClientIDWeb: 782 | Value: !Ref 'UserPoolClientWeb' 783 | Description: The user pool app client id for web 784 | AppClientID: 785 | Value: !Ref 'UserPoolClient' 786 | Description: The user pool app client id 787 | AppClientSecret: 788 | Value: !GetAtt UserPoolClientInputs.appSecret 789 | 790 | 791 | 792 | 793 | 794 | 795 | 796 | -------------------------------------------------------------------------------- /amplify/backend/awscloudformation/nested-cloudformation-stack.yml: -------------------------------------------------------------------------------- 1 | { 2 | "AWSTemplateFormatVersion": "2010-09-09", 3 | "Description": "Root Stack for AWS Amplify CLI", 4 | "Parameters": { 5 | "DeploymentBucketName": { 6 | "Description": "Name of the common deployment bucket provided by the parent stack", 7 | "Type": "String", 8 | "Default": "DeploymentBucket" 9 | }, 10 | "AuthRoleName": { 11 | "Type": "String", 12 | "Default": "AuthRoleName" 13 | }, 14 | "UnauthRoleName": { 15 | "Type": "String", 16 | "Default": "UnauthRoleName" 17 | } 18 | }, 19 | "Resources": { 20 | "DeploymentBucket": { 21 | "Type": "AWS::S3::Bucket", 22 | "DeletionPolicy": "Retain", 23 | "Properties": { 24 | "BucketName": { 25 | "Ref": "DeploymentBucketName" 26 | } 27 | } 28 | }, 29 | "AuthRole": { 30 | "Type": "AWS::IAM::Role", 31 | "Properties": { 32 | "RoleName": { 33 | "Ref": "AuthRoleName" 34 | }, 35 | "AssumeRolePolicyDocument": { 36 | "Version": "2012-10-17", 37 | "Statement": [ 38 | { 39 | "Sid": "", 40 | "Effect": "Deny", 41 | "Principal": { 42 | "Federated": "cognito-identity.amazonaws.com" 43 | }, 44 | "Action": "sts:AssumeRoleWithWebIdentity" 45 | } 46 | ] 47 | } 48 | } 49 | }, 50 | "UnauthRole": { 51 | "Type": "AWS::IAM::Role", 52 | "Properties": { 53 | "RoleName": { 54 | "Ref": "UnauthRoleName" 55 | }, 56 | "AssumeRolePolicyDocument": { 57 | "Version": "2012-10-17", 58 | "Statement": [ 59 | { 60 | "Sid": "", 61 | "Effect": "Deny", 62 | "Principal": { 63 | "Federated": "cognito-identity.amazonaws.com" 64 | }, 65 | "Action": "sts:AssumeRoleWithWebIdentity" 66 | } 67 | ] 68 | } 69 | } 70 | }, 71 | "authtailwindauth0a2d4345": { 72 | "Type": "AWS::CloudFormation::Stack", 73 | "Properties": { 74 | "TemplateURL": "https://s3.amazonaws.com/amplify-tailwindauth-dev-162937-deployment/amplify-cfn-templates/auth/tailwindauth0a2d4345-cloudformation-template.yml", 75 | "Parameters": { 76 | "identityPoolName": "tailwindauth0a2d4345_identitypool_0a2d4345", 77 | "allowUnauthenticatedIdentities": false, 78 | "resourceNameTruncated": "tailwi0a2d4345", 79 | "userPoolName": "tailwindauth0a2d4345_userpool_0a2d4345", 80 | "autoVerifiedAttributes": "email", 81 | "mfaConfiguration": "OFF", 82 | "mfaTypes": "SMS Text Message", 83 | "smsAuthenticationMessage": "Your authentication code is {####}", 84 | "smsVerificationMessage": "Your verification code is {####}", 85 | "emailVerificationSubject": "Your verification code", 86 | "emailVerificationMessage": "Your verification code is {####}", 87 | "defaultPasswordPolicy": false, 88 | "passwordPolicyMinLength": 8, 89 | "passwordPolicyCharacters": "", 90 | "requiredAttributes": "email", 91 | "userpoolClientGenerateSecret": true, 92 | "userpoolClientRefreshTokenValidity": 30, 93 | "userpoolClientWriteAttributes": "email", 94 | "userpoolClientReadAttributes": "email", 95 | "userpoolClientLambdaRole": "tailwi0a2d4345_userpoolclient_lambda_role", 96 | "userpoolClientSetAttributes": false, 97 | "sharedId": "0a2d4345", 98 | "resourceName": "tailwindauth0a2d4345", 99 | "authSelections": "identityPoolAndUserPool", 100 | "authRoleArn": { 101 | "Fn::GetAtt": [ 102 | "AuthRole", 103 | "Arn" 104 | ] 105 | }, 106 | "unauthRoleArn": { 107 | "Fn::GetAtt": [ 108 | "UnauthRole", 109 | "Arn" 110 | ] 111 | }, 112 | "useDefault": "defaultSocial", 113 | "usernameAttributes": "email", 114 | "userPoolGroupList": "", 115 | "serviceName": "Cognito", 116 | "usernameCaseSensitive": false, 117 | "dependsOn": "", 118 | "hostedUI": true, 119 | "hostedUIDomainName": "tailwindauth4cf825c5-4cf825c5", 120 | "authProvidersUserPool": "Facebook,Google", 121 | "hostedUIProviderMeta": "[{\"ProviderName\":\"Facebook\",\"authorize_scopes\":\"email,public_profile\",\"AttributeMapping\":{\"email\":\"email\",\"username\":\"id\"}},{\"ProviderName\":\"Google\",\"authorize_scopes\":\"openid email profile\",\"AttributeMapping\":{\"email\":\"email\",\"username\":\"sub\"}}]", 122 | "oAuthMetadata": "{\"AllowedOAuthFlows\":[\"code\"],\"AllowedOAuthScopes\":[\"phone\",\"email\",\"openid\",\"profile\",\"aws.cognito.signin.user.admin\"],\"CallbackURLs\":[\"http://localhost:3000/profile/\"],\"LogoutURLs\":[\"http://localhost:3000/profile/\"]}", 123 | "hostedUIProviderCreds": "[]", 124 | "env": "dev" 125 | } 126 | } 127 | }, 128 | "UpdateRolesWithIDPFunction": { 129 | "DependsOn": [ 130 | "AuthRole", 131 | "UnauthRole", 132 | "authtailwindauth0a2d4345" 133 | ], 134 | "Type": "AWS::Lambda::Function", 135 | "Properties": { 136 | "Code": { 137 | "ZipFile": { 138 | "Fn::Join": [ 139 | "\n", 140 | [ 141 | "const response = require('cfn-response');", 142 | "const aws = require('aws-sdk');", 143 | "let responseData = {};", 144 | "exports.handler = function(event, context) {", 145 | " try {", 146 | " let authRoleName = event.ResourceProperties.authRoleName;", 147 | " let unauthRoleName = event.ResourceProperties.unauthRoleName;", 148 | " let idpId = event.ResourceProperties.idpId;", 149 | " let promises = [];", 150 | " let authParamsJson = { 'Version': '2012-10-17','Statement': [{'Effect': 'Allow','Principal': {'Federated': 'cognito-identity.amazonaws.com'},'Action': 'sts:AssumeRoleWithWebIdentity','Condition': {'StringEquals': {'cognito-identity.amazonaws.com:aud': idpId},'ForAnyValue:StringLike': {'cognito-identity.amazonaws.com:amr': 'authenticated'}}}]};", 151 | " let unauthParamsJson = { 'Version': '2012-10-17','Statement': [{'Effect': 'Allow','Principal': {'Federated': 'cognito-identity.amazonaws.com'},'Action': 'sts:AssumeRoleWithWebIdentity','Condition': {'StringEquals': {'cognito-identity.amazonaws.com:aud': idpId},'ForAnyValue:StringLike': {'cognito-identity.amazonaws.com:amr': 'unauthenticated'}}}]};", 152 | " if (event.RequestType == 'Delete') {", 153 | " delete authParamsJson.Statement[0].Condition;", 154 | " delete unauthParamsJson.Statement[0].Condition;", 155 | " let authParams = { PolicyDocument: JSON.stringify(authParamsJson),RoleName: authRoleName};", 156 | " let unauthParams = {PolicyDocument: JSON.stringify(unauthParamsJson),RoleName: unauthRoleName};", 157 | " const iam = new aws.IAM({ apiVersion: '2010-05-08', region: event.ResourceProperties.region});", 158 | " promises.push(iam.updateAssumeRolePolicy(authParams).promise());", 159 | " promises.push(iam.updateAssumeRolePolicy(unauthParams).promise());", 160 | " Promise.all(promises)", 161 | " .then((res) => {", 162 | " console.log(\"delete response data\" + JSON.stringify(res));", 163 | " response.send(event, context, response.SUCCESS, {});", 164 | " });", 165 | " }", 166 | " if (event.RequestType == 'Update' || event.RequestType == 'Create') {", 167 | " const iam = new aws.IAM({ apiVersion: '2010-05-08', region: event.ResourceProperties.region});", 168 | " let authParams = { PolicyDocument: JSON.stringify(authParamsJson),RoleName: authRoleName};", 169 | " let unauthParams = {PolicyDocument: JSON.stringify(unauthParamsJson),RoleName: unauthRoleName};", 170 | " promises.push(iam.updateAssumeRolePolicy(authParams).promise());", 171 | " promises.push(iam.updateAssumeRolePolicy(unauthParams).promise());", 172 | " Promise.all(promises)", 173 | " .then((res) => {", 174 | " console.log(\"createORupdate\" + res);", 175 | " console.log(\"response data\" + JSON.stringify(res));", 176 | " response.send(event, context, response.SUCCESS, {});", 177 | " });", 178 | " }", 179 | " } catch(err) {", 180 | " console.log(err.stack);", 181 | " responseData = {Error: err};", 182 | " response.send(event, context, response.FAILED, responseData);", 183 | " throw err;", 184 | " }", 185 | "};" 186 | ] 187 | ] 188 | } 189 | }, 190 | "Handler": "index.handler", 191 | "Runtime": "nodejs10.x", 192 | "Timeout": "300", 193 | "Role": { 194 | "Fn::GetAtt": [ 195 | "UpdateRolesWithIDPFunctionRole", 196 | "Arn" 197 | ] 198 | } 199 | } 200 | }, 201 | "UpdateRolesWithIDPFunctionOutputs": { 202 | "Type": "Custom::LambdaCallout", 203 | "Properties": { 204 | "ServiceToken": { 205 | "Fn::GetAtt": [ 206 | "UpdateRolesWithIDPFunction", 207 | "Arn" 208 | ] 209 | }, 210 | "region": { 211 | "Ref": "AWS::Region" 212 | }, 213 | "idpId": { 214 | "Fn::GetAtt": [ 215 | "authtailwindauth0a2d4345", 216 | "Outputs.IdentityPoolId" 217 | ] 218 | }, 219 | "authRoleName": { 220 | "Ref": "AuthRoleName" 221 | }, 222 | "unauthRoleName": { 223 | "Ref": "UnauthRoleName" 224 | } 225 | } 226 | }, 227 | "UpdateRolesWithIDPFunctionRole": { 228 | "Type": "AWS::IAM::Role", 229 | "Properties": { 230 | "RoleName": { 231 | "Fn::Join": [ 232 | "", 233 | [ 234 | { 235 | "Ref": "AuthRoleName" 236 | }, 237 | "-idp" 238 | ] 239 | ] 240 | }, 241 | "AssumeRolePolicyDocument": { 242 | "Version": "2012-10-17", 243 | "Statement": [ 244 | { 245 | "Effect": "Allow", 246 | "Principal": { 247 | "Service": [ 248 | "lambda.amazonaws.com" 249 | ] 250 | }, 251 | "Action": [ 252 | "sts:AssumeRole" 253 | ] 254 | } 255 | ] 256 | }, 257 | "Policies": [ 258 | { 259 | "PolicyName": "UpdateRolesWithIDPFunctionPolicy", 260 | "PolicyDocument": { 261 | "Version": "2012-10-17", 262 | "Statement": [ 263 | { 264 | "Effect": "Allow", 265 | "Action": [ 266 | "logs:CreateLogGroup", 267 | "logs:CreateLogStream", 268 | "logs:PutLogEvents" 269 | ], 270 | "Resource": "arn:aws:logs:*:*:*" 271 | }, 272 | { 273 | "Effect": "Allow", 274 | "Action": "iam:UpdateAssumeRolePolicy", 275 | "Resource": { 276 | "Fn::GetAtt": [ 277 | "AuthRole", 278 | "Arn" 279 | ] 280 | } 281 | }, 282 | { 283 | "Effect": "Allow", 284 | "Action": "iam:UpdateAssumeRolePolicy", 285 | "Resource": { 286 | "Fn::GetAtt": [ 287 | "UnauthRole", 288 | "Arn" 289 | ] 290 | } 291 | } 292 | ] 293 | } 294 | } 295 | ] 296 | } 297 | } 298 | }, 299 | "Outputs": { 300 | "Region": { 301 | "Description": "CloudFormation provider root stack Region", 302 | "Value": { 303 | "Ref": "AWS::Region" 304 | }, 305 | "Export": { 306 | "Name": { 307 | "Fn::Sub": "${AWS::StackName}-Region" 308 | } 309 | } 310 | }, 311 | "StackName": { 312 | "Description": "CloudFormation provider root stack ID", 313 | "Value": { 314 | "Ref": "AWS::StackName" 315 | }, 316 | "Export": { 317 | "Name": { 318 | "Fn::Sub": "${AWS::StackName}-StackName" 319 | } 320 | } 321 | }, 322 | "StackId": { 323 | "Description": "CloudFormation provider root stack name", 324 | "Value": { 325 | "Ref": "AWS::StackId" 326 | }, 327 | "Export": { 328 | "Name": { 329 | "Fn::Sub": "${AWS::StackName}-StackId" 330 | } 331 | } 332 | }, 333 | "DeploymentBucketName": { 334 | "Description": "CloudFormation provider root stack deployment bucket name", 335 | "Value": { 336 | "Ref": "DeploymentBucketName" 337 | }, 338 | "Export": { 339 | "Name": { 340 | "Fn::Sub": "${AWS::StackName}-DeploymentBucketName" 341 | } 342 | } 343 | }, 344 | "AuthRoleArn": { 345 | "Value": { 346 | "Fn::GetAtt": [ 347 | "AuthRole", 348 | "Arn" 349 | ] 350 | } 351 | }, 352 | "UnauthRoleArn": { 353 | "Value": { 354 | "Fn::GetAtt": [ 355 | "UnauthRole", 356 | "Arn" 357 | ] 358 | } 359 | }, 360 | "AuthRoleName": { 361 | "Value": { 362 | "Ref": "AuthRole" 363 | } 364 | }, 365 | "UnauthRoleName": { 366 | "Value": { 367 | "Ref": "UnauthRole" 368 | } 369 | } 370 | } 371 | } -------------------------------------------------------------------------------- /amplify/backend/backend-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "auth": { 3 | "tailwindauth0a2d4345": { 4 | "service": "Cognito", 5 | "providerPlugin": "awscloudformation", 6 | "dependsOn": [], 7 | "customAuth": false 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /amplify/backend/tags.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "Key": "user:Stack", 4 | "Value": "{project-env}" 5 | }, 6 | { 7 | "Key": "user:Application", 8 | "Value": "{project-name}" 9 | } 10 | ] -------------------------------------------------------------------------------- /amplify/cli.json: -------------------------------------------------------------------------------- 1 | { 2 | "features": { 3 | "graphqltransformer": { 4 | "addmissingownerfields": true, 5 | "validatetypenamereservedwords": true, 6 | "useexperimentalpipelinedtransformer": false, 7 | "enableiterativegsiupdates": false 8 | }, 9 | "frontend-ios": { 10 | "enablexcodeintegration": true 11 | }, 12 | "auth": { 13 | "enablecaseinsensitivity": true 14 | }, 15 | "codegen": { 16 | "useappsyncmodelgenplugin": true 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /amplify/team-provider-info.json: -------------------------------------------------------------------------------- 1 | { 2 | "dev": { 3 | "awscloudformation": { 4 | "AuthRoleName": "amplify-tailwindauth-dev-162937-authRole", 5 | "UnauthRoleArn": "arn:aws:iam::557458351015:role/amplify-tailwindauth-dev-162937-unauthRole", 6 | "AuthRoleArn": "arn:aws:iam::557458351015:role/amplify-tailwindauth-dev-162937-authRole", 7 | "Region": "us-east-1", 8 | "DeploymentBucketName": "amplify-tailwindauth-dev-162937-deployment", 9 | "UnauthRoleName": "amplify-tailwindauth-dev-162937-unauthRole", 10 | "StackName": "amplify-tailwindauth-dev-162937", 11 | "StackId": "arn:aws:cloudformation:us-east-1:557458351015:stack/amplify-tailwindauth-dev-162937/51446780-5d01-11eb-9ac3-0a6046b66d41", 12 | "AmplifyAppId": "d3l292lxfelsd0" 13 | }, 14 | "categories": { 15 | "auth": { 16 | "tailwindauth0a2d4345": {} 17 | } 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /aws-exports.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | // WARNING: DO NOT EDIT. This file is automatically generated by AWS Amplify. It will be overwritten. 3 | 4 | const awsmobile = { 5 | "aws_project_region": "us-east-1", 6 | "aws_cognito_identity_pool_id": "us-east-1:327776ec-d1e4-4ad4-99c3-8890815b3090", 7 | "aws_cognito_region": "us-east-1", 8 | "aws_user_pools_id": "us-east-1_PIY96OxtS", 9 | "aws_user_pools_web_client_id": "3ndqpf0997g69sga9377uuhn71", 10 | "oauth": { 11 | "domain": "tailwindauth4cf825c5-4cf825c5-dev.auth.us-east-1.amazoncognito.com", 12 | "scope": [ 13 | "phone", 14 | "email", 15 | "openid", 16 | "profile", 17 | "aws.cognito.signin.user.admin" 18 | ], 19 | "redirectSignIn": "http://localhost:3000/", 20 | "redirectSignOut": "http://localhost:3000/", 21 | "responseType": "code" 22 | }, 23 | "federationTarget": "COGNITO_USER_POOLS" 24 | }; 25 | 26 | 27 | export default awsmobile; 28 | -------------------------------------------------------------------------------- /components/ConfirmSignUp.js: -------------------------------------------------------------------------------- 1 | import Input from './Input' 2 | 3 | function ConfirmSignUp({ setUiState, onChange, confirmSignUp }) { 4 | return ( 5 | <> 6 |
Confirm Sign Up
7 |Reset password
7 |Reset password
7 |Welcome, {user.email}
17 | 21 | > 22 | ) 23 | } 24 | 25 | export default Profile -------------------------------------------------------------------------------- /components/SignIn.js: -------------------------------------------------------------------------------- 1 | import Input from './Input' 2 | import SocialSignIn from './SocialSignIn' 3 | 4 | function SignIn({ 5 | setUiState, onChange, signIn 6 | }) { 7 | return ( 8 | <> 9 |Sign in to your account
10 |29 | Don't have an account? 30 | setUiState('signUp')} 32 | role="button" 33 | className="cursor-pointer text-pink-600"> Sign Up. 34 |
35 | > 36 | ) 37 | } 38 | 39 | export default SignIn -------------------------------------------------------------------------------- /components/SignUp.js: -------------------------------------------------------------------------------- 1 | import Input from './Input' 2 | 3 | function SignUp({ 4 | setUiState, signUp, onChange 5 | }) { 6 | return ( 7 | <> 8 |Sign up for an account
9 |15 | Password 16 | Forgot your password? 19 |
20 | 21 |28 | Already have an account? 29 | setUiState('signIn')} 32 | > Sign In. 33 |
34 | > 35 | ) 36 | } 37 | 38 | export default SignUp -------------------------------------------------------------------------------- /components/SocialSignIn.js: -------------------------------------------------------------------------------- 1 | import { FaGoogle, FaFacebook } from 'react-icons/fa'; 2 | import { Auth } from 'aws-amplify' 3 | 4 | function SocialSignIn() { 5 | return ( 6 |amplify
69 |Loading ...
73 | } 74 | { 75 | uiState === 'signedIn' && ( 76 |A utility-first CSS framework packed with classes like flex
, pt-4
, text-center
and rotate-90
that can be composed to build any design, directly in your markup.