diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index c41c480705b..3d807f47fcf 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,177 +1,177 @@ * @aws-amplify/documentation-team #Other -/src/pages/gen1/[platform]/build-a-backend/existing-resources/ @josefaidt @hdworld11 @renebrandel @dbanksdesign -/src/pages/gen1/[platform]/build-a-backend/functions/ @josefaidt -/src/pages/gen1/[platform]/how-amplify-works/ @aspittel -/src/pages/gen1/[platform]/sdk/api/ @hdworld11 -/src/pages/gen1/[platform]/sdk/info @hdworld11 -/src/pages/gen1/[platform]/sdk/configuration/ @hdworld11 -/src/pages/[platform]/how-amplify-works/ @aspittel -/src/pages/[platform]/build-a-backend/functions/ @josefaidt -/src/pages/[platform]/build-a-backend/functions/ @josefaidt -/src/pages/[platform]/build-a-backend/add-aws-services/custom-resources/ @josefaidt @hdworld11 @renebrandel @dbanksdesign -/src/pages/[platform]/build-a-backend/add-aws-services/delete-backup-resources/ @josefaidt @hdworld11 @renebrandel @dbanksdesign -/src/pages/[platform]/build-a-backend/add-aws-services/environment-variables-and-secrets/ @swaminator @josefaidt -/src/pages/[platform]/build-a-backend/q-developer/ @arundna +/src/pages/gen1/\[platform\]/build-a-backend/existing-resources/ @josefaidt @hdworld11 @dbanksdesign +/src/pages/gen1/\[platform\]/build-a-backend/functions/ @josefaidt +/src/pages/gen1/\[platform\]/how-amplify-works/ @aws-amplify/amplify-pms +/src/pages/gen1/\[platform\]/sdk/api/ @hdworld11 +/src/pages/gen1/\[platform\]/sdk/info @hdworld11 +/src/pages/gen1/\[platform\]/sdk/configuration/ @hdworld11 +/src/pages/\[platform\]/how-amplify-works/ @aws-amplify/amplify-pms +/src/pages/\[platform\]/build-a-backend/functions/ @josefaidt +/src/pages/\[platform\]/build-a-backend/functions/ @josefaidt +/src/pages/\[platform\]/build-a-backend/add-aws-services/custom-resources/ @josefaidt @hdworld11 @dbanksdesign +/src/pages/\[platform\]/build-a-backend/add-aws-services/delete-backup-resources/ @josefaidt @hdworld11 @dbanksdesign +/src/pages/\[platform\]/build-a-backend/add-aws-services/environment-variables-and-secrets/ @swaminator @josefaidt +/src/pages/\[platform\]/build-a-backend/q-developer/ @arundna #CLI /src/fragments/cli/ @josefaidt -/src/pages/gen1/[platform]/tools/cli/ @josefaidt -/src/pages/gen1/[platform]/tools/cli-legacy/ @josefaidt -/src/pages/[platform]/reference/cli-commands/ @josefaidt +/src/pages/gen1/\[platform\]/tools/cli/ @josefaidt +/src/pages/gen1/\[platform\]/tools/cli-legacy/ @josefaidt +/src/pages/\[platform\]/reference/cli-commands/ @josefaidt #Studio -/src/pages/gen1/[platform]/tools/console/ @dbanksdesign +/src/pages/gen1/\[platform\]/tools/console/ @dbanksdesign #Analytics /src/fragments/**/analytics/ @hdworld11 -/src/pages/gen1/[platform]/build-a-backend/more-features/analytics/ @hdworld11 -/src/pages/gen1/[platform]/prev/build-a-backend/more-features/analytics/ @hdworld11 -/src/pages/gen1/[platform]/sdk/analytics/ @hdworld11 -/src/pages/[platform]/build-a-backend/add-aws-services/analytics/ @hdworld11 -/src/pages/gen1/[platform]/build-a-backend/existing-resources/cli @hdworld11 +/src/pages/gen1/\[platform\]/build-a-backend/more-features/analytics/ @hdworld11 +/src/pages/gen1/\[platform\]/prev/build-a-backend/more-features/analytics/ @hdworld11 +/src/pages/gen1/\[platform\]/sdk/analytics/ @hdworld11 +/src/pages/\[platform\]/build-a-backend/add-aws-services/analytics/ @hdworld11 +/src/pages/gen1/\[platform\]/build-a-backend/existing-resources/cli @hdworld11 #Auth /src/fragments/**/auth/ @josefaidt -/src/pages/gen1/[platform]/build-a-backend/auth/ @josefaidt -/src/pages/gen1/[platform]/prev/build-a-backend/auth/ @josefaidt -/src/pages/gen1/[platform]/sdk/auth/ @josefaidt -/src/pages/gen1/[platform]/start/getting-started/auth/ @josefaidt -/src/pages/[platform]/build-a-backend/auth/ @josefaidt +/src/pages/gen1/\[platform\]/build-a-backend/auth/ @josefaidt +/src/pages/gen1/\[platform\]/prev/build-a-backend/auth/ @josefaidt +/src/pages/gen1/\[platform\]/sdk/auth/ @josefaidt +/src/pages/gen1/\[platform\]/start/getting-started/auth/ @josefaidt +/src/pages/\[platform\]/build-a-backend/auth/ @josefaidt #Client Configuration -/src/fragments/**/client-configuration @renebrandel @josefaidt @hdworld11 -/src/fragments/**/configuration @renebrandel @josefaidt @hdworld11 +/src/fragments/**/client-configuration @josefaidt @hdworld11 +/src/fragments/**/configuration @josefaidt @hdworld11 #Common -/src/fragments/common @renebrandel @hdworld11 @josefaidt @dbanksdesign -/src/fragments/**/common @renebrandel @hdworld11 @josefaidt @dbanksdesign +/src/fragments/common @hdworld11 @josefaidt @dbanksdesign +/src/fragments/**/common @hdworld11 @josefaidt @dbanksdesign #Data -/src/fragments/**/datastore @renebrandel -/src/pages/gen1/[platform]/build-a-backend/more-features/datastore @renebrandel -/src/pages/gen1/[platform]/prev/build-a-backend/more-features/datastore/ @renebrandel -/src/pages/[platform]/build-a-backend/data/ @renebrandel +/src/fragments/**/datastore @josefaidt +/src/pages/gen1/\[platform\]/build-a-backend/more-features/datastore @josefaidt +/src/pages/gen1/\[platform\]/prev/build-a-backend/more-features/datastore/ @josefaidt +/src/pages/\[platform\]/build-a-backend/data/ @josefaidt #Debugging /src/fragments/**/debugging @josefaidt -/src/pages/gen1/[platform]/build-a-backend/debugging/ @josefaidt -/src/pages/gen1/[platform]/prev/build-a-backend/debugging/ @josefaidt +/src/pages/gen1/\[platform\]/build-a-backend/debugging/ @josefaidt +/src/pages/gen1/\[platform\]/prev/build-a-backend/debugging/ @josefaidt #Geo /src/fragments/**/geo @hdworld11 -/src/pages/gen1/[platform]/build-a-backend/more-features/geo/ @hdworld11 -/src/pages/gen1/[platform]/prev/build-a-backend/more-features/geo/ @hdworld11 -/src/pages/[platform]/build-a-backend/add-aws-services/geo/ @hdworld11 +/src/pages/gen1/\[platform\]/build-a-backend/more-features/geo/ @hdworld11 +/src/pages/gen1/\[platform\]/prev/build-a-backend/more-features/geo/ @hdworld11 +/src/pages/\[platform\]/build-a-backend/add-aws-services/geo/ @hdworld11 #Getting Started -/src/fragments/start @aspittel -/src/fragments/gen2/quickstart/ @aspittel -/src/fragments/**/start/ @aspittel -/src/fragments/**/project-setup @aspittel -/src/pages/gen1/[platform]/prev/start/ @aspittel -/src/pages/gen1/[platform]/start/ @aspittel -/src/pages/[platform]/start/ @aspittel +/src/fragments/start @aws-amplify/amplify-pms +/src/fragments/gen2/quickstart/ @aws-amplify/amplify-pms +/src/fragments/**/start/ @aws-amplify/amplify-pms +/src/fragments/**/project-setup @aws-amplify/amplify-pms +/src/pages/gen1/\[platform\]/prev/start/ @aws-amplify/amplify-pms +/src/pages/gen1/\[platform\]/start/ @aws-amplify/amplify-pms +/src/pages/\[platform\]/start/ @aws-amplify/amplify-pms #GraphQL API -/src/fragments/**/api-graphql @renebrandel -/src/fragments/**/graphqlapi @renebrandel -/src/fragments/sdk/api/**/graphql.mdx @renebrandel -/src/pages/gen1/[platform]/build-a-backend/functions/graphql-from-lambda/ @renebrandel -/src/pages/gen1/[platform]/build-a-backend/graphqlapi/ @renebrandel -/src/pages/gen1/[platform]/prev/build-a-backend/graphqlapi/ @renebrandel -/src/pages/gen1/[platform]/sdk/api/graphql/ @renebrandel +/src/fragments/**/api-graphql @josefaidt +/src/fragments/**/graphqlapi @josefaidt +/src/fragments/sdk/api/**/graphql.mdx @josefaidt +/src/pages/gen1/\[platform\]/build-a-backend/functions/graphql-from-lambda/ @josefaidt +/src/pages/gen1/\[platform\]/build-a-backend/graphqlapi/ @josefaidt +/src/pages/gen1/\[platform\]/prev/build-a-backend/graphqlapi/ @josefaidt +/src/pages/gen1/\[platform\]/sdk/api/graphql/ @josefaidt #In-App Messaging /src/fragments/**/in-app-messaging @hdworld11 -/src/pages/gen1/[platform]/build-a-backend/more-features/in-app-messaging/ @hdworld11 -/src/pages/gen1/[platform]/prev/build-a-backend/more-features/in-app-messaging/ @hdworld11 -/src/pages/[platform]/build-a-backend/add-aws-services/in-app-messaging/ @hdworld11 +/src/pages/gen1/\[platform\]/build-a-backend/more-features/in-app-messaging/ @hdworld11 +/src/pages/gen1/\[platform\]/prev/build-a-backend/more-features/in-app-messaging/ @hdworld11 +/src/pages/\[platform\]/build-a-backend/add-aws-services/in-app-messaging/ @hdworld11 #Info -/src/fragments/**/info @renebrandel @hdworld11 @josefaidt @dbanksdesign +/src/fragments/**/info @hdworld11 @josefaidt @dbanksdesign #Interactions /src/fragments/**/interactions @josefaidt -/src/pages/gen1/[platform]/build-a-backend/more-features/interactions/ @josefaidt -/src/pages/gen1/[platform]/prev/build-a-backend/more-features/interactions/ @josefaidt -/src/pages/[platform]/build-a-backend/add-aws-services/interactions/ @josefaidt +/src/pages/gen1/\[platform\]/build-a-backend/more-features/interactions/ @josefaidt +/src/pages/gen1/\[platform\]/prev/build-a-backend/more-features/interactions/ @josefaidt +/src/pages/\[platform\]/build-a-backend/add-aws-services/interactions/ @josefaidt #Logging /src/fragments/**/logging @hdworld11 -/src/pages/gen1/[platform]/build-a-backend/more-features/logging/ @hdworld11 -/src/pages/[platform]/build-a-backend/add-aws-services/logging/ @hdworld11 +/src/pages/gen1/\[platform\]/build-a-backend/more-features/logging/ @hdworld11 +/src/pages/\[platform\]/build-a-backend/add-aws-services/logging/ @hdworld11 #Predictions /src/fragments/**/predictions @hdworld11 @dbanksdesign -/src/pages/gen1/[platform]/build-a-backend/more-features/predictions/ @hdworld11 @dbanksdesign -/src/pages/gen1/[platform]/prev/build-a-backend/more-features/predictions/ @hdworld11 @dbanksdesign -/src/pages/[platform]/build-a-backend/add-aws-services/predictions/ @hdworld11 @dbanksdesign +/src/pages/gen1/\[platform\]/build-a-backend/more-features/predictions/ @hdworld11 @dbanksdesign +/src/pages/gen1/\[platform\]/prev/build-a-backend/more-features/predictions/ @hdworld11 @dbanksdesign +/src/pages/\[platform\]/build-a-backend/add-aws-services/predictions/ @hdworld11 @dbanksdesign #PubSub -/src/fragments/**/pubsub @renebrandel -/src/pages/gen1/[platform]/build-a-backend/more-features/pubsub/ @renebrandel -/src/pages/gen1/[platform]/prev/build-a-backend/more-features/pubsub/ @renebrandel -/src/pages/gen1/[platform]/sdk/pubsub/ @renebrandel -/src/pages/[platform]/build-a-backend/add-aws-services/pubsub/ @renebrandel +/src/fragments/**/pubsub @josefaidt +/src/pages/gen1/\[platform\]/build-a-backend/more-features/pubsub/ @josefaidt +/src/pages/gen1/\[platform\]/prev/build-a-backend/more-features/pubsub/ @josefaidt +/src/pages/gen1/\[platform\]/sdk/pubsub/ @josefaidt +/src/pages/\[platform\]/build-a-backend/add-aws-services/pubsub/ @josefaidt #Push Notifications /src/fragments/**/push-notifications @hdworld11 @dbanksdesign -/src/pages/gen1/[platform]/build-a-backend/push-notifications/ @hdworld11 @dbanksdesign -/src/pages/gen1/[platform]/prev/build-a-backend/push-notifications/ @hdworld11 @dbanksdesign -/src/pages/gen1/[platform]/sdk/push-notifications/ @hdworld11 @dbanksdesign +/src/pages/gen1/\[platform\]/build-a-backend/push-notifications/ @hdworld11 @dbanksdesign +/src/pages/gen1/\[platform\]/prev/build-a-backend/push-notifications/ @hdworld11 @dbanksdesign +/src/pages/gen1/\[platform\]/sdk/push-notifications/ @hdworld11 @dbanksdesign #Rest API /src/fragments/**/api-rest @josefaidt /src/fragments/**/restapi @josefaidt /src/fragments/sdk/api/**/rest.mdx @josefaidt -/src/pages/gen1/[platform]/build-a-backend/restapi/ @josefaidt -/src/pages/gen1/[platform]/prev/build-a-backend/restapi/ @josefaidt -/src/pages/gen1/[platform]/sdk/api/rest/ @josefaidt -/src/pages/[platform]/build-a-backend/add-aws-services/rest-api/ @josefaidt +/src/pages/gen1/\[platform\]/build-a-backend/restapi/ @josefaidt +/src/pages/gen1/\[platform\]/prev/build-a-backend/restapi/ @josefaidt +/src/pages/gen1/\[platform\]/sdk/api/rest/ @josefaidt +/src/pages/\[platform\]/build-a-backend/add-aws-services/rest-api/ @josefaidt #SSR -/src/fragments/**/ssr @renebrandel @josefaidt @dbanksdesign -/src/pages/gen1/[platform]/build-a-backend/server-side-rendering/ @renebrandel @josefaidt @dbanksdesign -/src/pages/gen1/[platform]/prev/build-a-backend/server-side-rendering/ @renebrandel @josefaidt @dbanksdesign -/src/pages/[platform]/build-a-backend/server-side-rendering/ @renebrandel @josefaidt @dbanksdesign +/src/fragments/**/ssr @josefaidt @dbanksdesign +/src/pages/gen1/\[platform\]/build-a-backend/server-side-rendering/ @josefaidt @dbanksdesign +/src/pages/gen1/\[platform\]/prev/build-a-backend/server-side-rendering/ @josefaidt @dbanksdesign +/src/pages/\[platform\]/build-a-backend/server-side-rendering/ @josefaidt @dbanksdesign #Storage /src/fragments/**/storage @hdworld11 -/src/pages/gen1/[platform]/build-a-backend/storage/ @hdworld11 -/src/pages/gen1/[platform]/prev/build-a-backend/storage/ @hdworld11 -/src/pages/gen1/[platform]/sdk/storage/ @hdworld11 -/src/pages/[platform]/build-a-backend/storage/ @hdworld11 +/src/pages/gen1/\[platform\]/build-a-backend/storage/ @hdworld11 +/src/pages/gen1/\[platform\]/prev/build-a-backend/storage/ @hdworld11 +/src/pages/gen1/\[platform\]/sdk/storage/ @hdworld11 +/src/pages/\[platform\]/build-a-backend/storage/ @hdworld11 #Troubleshooting /src/fragments/**/troubleshooting @josefaidt -/src/pages/gen1/[platform]/build-a-backend/troubleshooting/ @josefaidt -/src/pages/gen1/[platform]/prev/build-a-backend/troubleshooting/ @josefaidt -/src/pages/[platform]/build-a-backend/troubleshooting/ @josefaidt +/src/pages/gen1/\[platform\]/build-a-backend/troubleshooting/ @josefaidt +/src/pages/gen1/\[platform\]/prev/build-a-backend/troubleshooting/ @josefaidt +/src/pages/\[platform\]/build-a-backend/troubleshooting/ @josefaidt #UI /src/fragments/ui/auth/react/ @dbanksdesign -/src/pages/gen1/[platform]/build-ui/ @dbanksdesign -/src/pages/gen1/[platform]/prev/build-ui/ @dbanksdesign -/src/pages/[platform]/build-ui/ @dbanksdesign +/src/pages/gen1/\[platform\]/build-ui/ @dbanksdesign +/src/pages/gen1/\[platform\]/prev/build-ui/ @dbanksdesign +/src/pages/\[platform\]/build-ui/ @dbanksdesign #Utilities /src/fragments/**/utilities @josefaidt -/src/pages/gen1/[platform]/build-a-backend/utilities/ @josefaidt -/src/pages/gen1/[platform]/prev/build-a-backend/utilities/ @josefaidt +/src/pages/gen1/\[platform\]/build-a-backend/utilities/ @josefaidt +/src/pages/gen1/\[platform\]/prev/build-a-backend/utilities/ @josefaidt #Deploy and Host -/src/pages/gen1/[platform]/deploy-and-host/ @mauerbac -/src/pages/gen1/[platform]/prev/deploy-and-host/ @mauerbac -/src/pages/[platform]/deploy-and-host/ @mauerbac +/src/pages/gen1/\[platform\]/deploy-and-host/ @mauerbac +/src/pages/gen1/\[platform\]/prev/deploy-and-host/ @mauerbac +/src/pages/\[platform\]/deploy-and-host/ @mauerbac #Docs Engineering /src/components @aws-amplify/documentation-team /src/constants @aws-amplify/documentation-team /src/data @aws-amplify/documentation-team /src/directory @aws-amplify/documentation-team -/src/directory/directory.mjs @aspittel @swaminator @renebrandel +/src/directory/directory.mjs @aws-amplify/amplify-pms /src/pages/contribute/ @aws-amplify/documentation-team /src/pages/_app.tsx @aws-amplify/documentation-team /src/pages/_document.tsx @aws-amplify/documentation-team diff --git a/.github/workflows/accessibility_scan.yml b/.github/workflows/accessibility_scan.yml index 933fd2f136f..793b0471cf6 100644 --- a/.github/workflows/accessibility_scan.yml +++ b/.github/workflows/accessibility_scan.yml @@ -13,7 +13,7 @@ jobs: - name: Checkout branch uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 - name: Setup Node.js 20 - uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2 + uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0 with: node-version: 20.x - name: Install dependencies diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 83a8bd247c8..c118fac30d5 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -13,7 +13,7 @@ jobs: - name: Checkout Repo uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 - name: Setup Node.js 20.x - uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2 + uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0 with: node-version: 20.x - name: Install Dependencies diff --git a/.github/workflows/check_bundle_size.yml b/.github/workflows/check_bundle_size.yml index 745ee002efa..7a7accfadbe 100644 --- a/.github/workflows/check_bundle_size.yml +++ b/.github/workflows/check_bundle_size.yml @@ -14,7 +14,7 @@ jobs: with: ref: main - name: Setup Node.js 20 - uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2 + uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0 with: node-version: 20.x - name: Install dependencies @@ -38,7 +38,7 @@ jobs: with: ref: ${{ github.head_ref }} - name: Setup Node.js 20 - uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2 + uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0 with: node-version: 20.x - name: Install dependencies diff --git a/.github/workflows/check_for_broken_links.yml b/.github/workflows/check_for_broken_links.yml index 181c6a1458b..45aa18f9cde 100644 --- a/.github/workflows/check_for_broken_links.yml +++ b/.github/workflows/check_for_broken_links.yml @@ -13,7 +13,7 @@ jobs: - name: Checkout repository uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 - name: Setup Node.js 20 - uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2 + uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0 with: node-version: 20.x - name: Install Dependencies @@ -32,7 +32,7 @@ jobs: role-to-assume: arn:aws:iam::464149486631:role/github_action_read_slack_webhook_url aws-region: us-west-2 - name: Read secrets from AWS Secrets Manager into environment variables - uses: aws-actions/aws-secretsmanager-get-secrets@98c2d6bf1dd67c2575fa2bb14294aa64103d426c # v2.0.5 + uses: aws-actions/aws-secretsmanager-get-secrets@1d6311ab61b4856de027ff508aac818ddc1e141b # v2.0.7 with: secret-ids: | SLACK_WEBHOOK_URL diff --git a/.github/workflows/check_for_console_errors.yml b/.github/workflows/check_for_console_errors.yml index 3615ac34632..d103ab66a73 100644 --- a/.github/workflows/check_for_console_errors.yml +++ b/.github/workflows/check_for_console_errors.yml @@ -14,7 +14,7 @@ jobs: - name: Checkout repository uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 - name: Setup Node.js 20.x - uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2 + uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0 with: node-version: 20.x - name: Install Dependencies diff --git a/.github/workflows/check_for_deleted_assets.yml b/.github/workflows/check_for_deleted_assets.yml index 860a48bcd15..d6c7f5beca8 100644 --- a/.github/workflows/check_for_deleted_assets.yml +++ b/.github/workflows/check_for_deleted_assets.yml @@ -32,7 +32,7 @@ jobs: echo ${{ env.PR_NUMBER }} >> $artifactName echo ${{ steps.set-deleted-files-count.outputs.result }} >> $artifactName - name: Upload the deleted assets file to artifacts - uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 + uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 with: name: ${{ env.ARTIFACT_NAME }} path: '${{ env.ARTIFACT_NAME }}.txt' diff --git a/.github/workflows/check_for_redirects.yml b/.github/workflows/check_for_redirects.yml index 5f157560e99..d4b244c5f41 100644 --- a/.github/workflows/check_for_redirects.yml +++ b/.github/workflows/check_for_redirects.yml @@ -32,7 +32,7 @@ jobs: echo ${{ env.PR_NUMBER }} >> $artifactName echo ${{ steps.set-deleted-files-count.outputs.result }} >> $artifactName - name: Upload the redirects file to artifacts - uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 + uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 with: name: ${{ env.ARTIFACT_NAME }} path: '${{ env.ARTIFACT_NAME }}.txt' diff --git a/.github/workflows/check_pr_for_broken_links.yml b/.github/workflows/check_pr_for_broken_links.yml index 24a9f7e6f38..766801b41da 100644 --- a/.github/workflows/check_pr_for_broken_links.yml +++ b/.github/workflows/check_pr_for_broken_links.yml @@ -12,7 +12,7 @@ jobs: - name: Checkout repository uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 - name: Setup Node.js 20 - uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2 + uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0 with: node-version: 20.x - name: Install Dependencies diff --git a/.github/workflows/spellcheck.yml b/.github/workflows/spellcheck.yml index 088fdeb0045..e8ce1664edb 100644 --- a/.github/workflows/spellcheck.yml +++ b/.github/workflows/spellcheck.yml @@ -11,7 +11,7 @@ jobs: - name: Checkout repository uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 - name: Setup Node.js 20 - uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2 + uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0 with: node-version: 20.x - name: Install Dependencies diff --git a/.github/workflows/update_references.yml b/.github/workflows/update_references.yml index fb5b43655b2..190bf19fd16 100644 --- a/.github/workflows/update_references.yml +++ b/.github/workflows/update_references.yml @@ -18,7 +18,7 @@ jobs: uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 - name: Setup Node.js 20 - uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2 + uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0 with: node-version: 20.x diff --git a/.github/workflows/validate_redirects.yml b/.github/workflows/validate_redirects.yml index e37598b26c2..8affcb4b074 100644 --- a/.github/workflows/validate_redirects.yml +++ b/.github/workflows/validate_redirects.yml @@ -14,7 +14,7 @@ jobs: - name: Checkout repository uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 - name: Setup Node.js 20.x - uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2 + uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0 with: node-version: 20.x - name: Install Dependencies diff --git a/cspell.json b/cspell.json index e4ee6df3832..80ac1464f23 100644 --- a/cspell.json +++ b/cspell.json @@ -851,6 +851,7 @@ "metadata", "mfaDescription", "mfaTypes", + "enabledMfas", "MiB", "middleware", "Millis", diff --git a/src/components/Layout/Layout.tsx b/src/components/Layout/Layout.tsx index 86aa98bbc11..4638d637994 100644 --- a/src/components/Layout/Layout.tsx +++ b/src/components/Layout/Layout.tsx @@ -149,8 +149,15 @@ export const Layout = ({ pageHeadings.forEach((node) => { const { innerText, id, localName } = node as HTMLElement; - if (innerText && id && (localName == 'h2' || localName == 'h3')) { + if (innerText && id && localName == 'h2') { headings.push({ + linkText: innerText, + hash: id, + level: localName, + subheadings: [] + }); + } else if (innerText && id && localName == 'h3') { + headings[headings.length - 1].subheadings.push({ linkText: innerText, hash: id, level: localName diff --git a/src/components/TableOfContents/TableOfContents.tsx b/src/components/TableOfContents/TableOfContents.tsx index 041c0a1e724..c415a5575da 100644 --- a/src/components/TableOfContents/TableOfContents.tsx +++ b/src/components/TableOfContents/TableOfContents.tsx @@ -4,6 +4,7 @@ export interface HeadingInterface { linkText: string; hash: string; level: string; + subheadings: Array; } interface TableOfContents { headers?: HeadingInterface[]; @@ -21,20 +22,57 @@ export const TableOfContents = ({ headers }) => { )} {headers.map(({ linkText, hash, level }, index) => { - return ( - - - {linkText} - - - ); + + {linkText} + + + ); + } else { + return ( + + + {linkText} + + + {headers[index].subheadings?.map( + ({ linkText, hash, level }, index) => { + return ( + + + {linkText} + + + ); + } + )} + + + ); + } })} diff --git a/src/constants/versions.ts b/src/constants/versions.ts index 9d46720b5a8..dacf5ba9a81 100644 --- a/src/constants/versions.ts +++ b/src/constants/versions.ts @@ -1,10 +1,10 @@ export const versions = { - ANDROID_VERSION: '2.19.1', + ANDROID_VERSION: '2.24.0', ANDROID_DEVPREVIEW: '1.36.5-dev-preview.0', ANDROID_V1_VERSION: '1.38.8', ANDROID_V1_GEO_VERSION: '1.0.1', ANDROID_V1_KOTLIN_VERSION: '0.22.8', ANDROID_SDK_VERSION: '2.76.0', - KOTLIN_SDK_VERSION: '1.2.8', - ANDROID_AUTHENTICATOR_VERSION: '1.2.0' + KOTLIN_SDK_VERSION: '1.3.31', + ANDROID_AUTHENTICATOR_VERSION: '1.4.0' }; diff --git a/src/directory/directory.mjs b/src/directory/directory.mjs index 157c7fd514d..49e53841015 100644 --- a/src/directory/directory.mjs +++ b/src/directory/directory.mjs @@ -122,6 +122,9 @@ export const directory = { }, { path: 'src/pages/[platform]/build-a-backend/auth/connect-your-frontend/delete-user-account/index.mdx' + }, + { + path: 'src/pages/[platform]/build-a-backend/auth/connect-your-frontend/multi-step-sign-in/index.mdx' } ] }, @@ -156,9 +159,6 @@ export const directory = { } ] }, - { - path: 'src/pages/[platform]/build-a-backend/auth/multi-step-sign-in/index.mdx' - }, { path: 'src/pages/[platform]/build-a-backend/auth/sign-in-with-web-ui/index.mdx' }, @@ -320,6 +320,9 @@ export const directory = { { path: 'src/pages/[platform]/build-a-backend/data/optimistic-ui/index.mdx' }, + { + path: 'src/pages/[platform]/build-a-backend/data/connect-event-api/index.mdx' + }, { path: 'src/pages/[platform]/build-a-backend/data/override-resources/index.mdx' }, @@ -706,7 +709,7 @@ export const directory = { path: 'src/pages/[platform]/build-a-backend/troubleshooting/library-not-configured/index.mdx' }, { - path: 'src/pages/[platform]/build-a-backend/troubleshooting/stack-cdktoolkit-already-exists/index.mdx' + path: 'src/pages/[platform]/build-a-backend/troubleshooting/cdktoolkit-stack/index.mdx' }, { path: 'src/pages/[platform]/build-a-backend/troubleshooting/cannot-find-module-amplify-env/index.mdx' diff --git a/src/fragments/lib-v1/analytics/js/personalize.mdx b/src/fragments/lib-v1/analytics/js/personalize.mdx index 300ad039769..3f5cccc55de 100644 --- a/src/fragments/lib-v1/analytics/js/personalize.mdx +++ b/src/fragments/lib-v1/analytics/js/personalize.mdx @@ -7,7 +7,7 @@ To record event data, you need the following: For more information, see [Record Events](https://docs.aws.amazon.com/personalize/latest/dg/recording-events.html). -### Installation and Configuration +## Installation and Configuration Register the *AmazonPersonalizeProvider* with the Analytics category: You need the tracking ID of your event tracker. For more information, see [Get a Tracking ID](https://docs.aws.amazon.com/personalize/latest/dg/recording-events.html#event-get-tracker). @@ -38,7 +38,7 @@ Analytics.configure({ } }); ``` -### Working with the API +## Working with the API You can use the `Identify` event type to track a user identity. This lets you connect a user to their actions and record traits about them. To identify a user, specify a unique identifier for the userId property. Consider the following user interactions when choosing when and how often to call record with the Identify eventType: diff --git a/src/fragments/lib-v1/auth/native_common/signin_next_steps/common.mdx b/src/fragments/lib-v1/auth/native_common/signin_next_steps/common.mdx index c3310606b28..eaeb26fbbd0 100644 --- a/src/fragments/lib-v1/auth/native_common/signin_next_steps/common.mdx +++ b/src/fragments/lib-v1/auth/native_common/signin_next_steps/common.mdx @@ -10,7 +10,7 @@ import flutter0 from '/src/fragments/lib-v1/auth/flutter/signin_next_steps/10_si -### Confirm signin with SMS MFA +## Confirm signin with SMS MFA import ios1 from '/src/fragments/lib-v1/auth/ios/signin_next_steps/20_confirm_sms_mfa.mdx'; @@ -19,7 +19,7 @@ import flutter1 from '/src/fragments/lib-v1/auth/flutter/signin_next_steps/20_co -### Confirm signin with TOTP MFA +## Confirm signin with TOTP MFA import flutter7 from '/src/fragments/lib-v1/auth/flutter/signin_next_steps/80_totp.mdx'; @@ -27,7 +27,7 @@ import flutter7 from '/src/fragments/lib-v1/auth/flutter/signin_next_steps/80_to -### Continue signin with MFA Selection +## Continue signin with MFA Selection import flutter8 from '/src/fragments/lib-v1/auth/flutter/signin_next_steps/90_mfa_selection.mdx'; @@ -35,14 +35,14 @@ import flutter8 from '/src/fragments/lib-v1/auth/flutter/signin_next_steps/90_mf -### Continue signin with TOTP Setup +## Continue signin with TOTP Setup import flutter9 from '/src/fragments/lib-v1/auth/flutter/signin_next_steps/100_totp_setup.mdx'; -### Confirm signin with custom challenge +## Confirm signin with custom challenge import ios2 from '/src/fragments/lib-v1/auth/ios/signin_next_steps/30_confirm_custom_challenge.mdx'; @@ -50,7 +50,7 @@ import flutter2 from '/src/fragments/lib-v1/auth/flutter/signin_next_steps/30_co -### Confirm signin with new password +## Confirm signin with new password import ios3 from '/src/fragments/lib-v1/auth/ios/signin_next_steps/40_confirm_new_password.mdx'; @@ -58,7 +58,7 @@ import flutter3 from '/src/fragments/lib-v1/auth/flutter/signin_next_steps/40_co -### Reset password +## Reset password import ios4 from '/src/fragments/lib-v1/auth/ios/signin_next_steps/50_reset_password.mdx'; @@ -66,7 +66,7 @@ import flutter4 from '/src/fragments/lib-v1/auth/flutter/signin_next_steps/50_re -### Confirm Signup +## Confirm Signup import ios5 from '/src/fragments/lib-v1/auth/ios/signin_next_steps/60_confirm_signup.mdx'; @@ -74,7 +74,7 @@ import flutter5 from '/src/fragments/lib-v1/auth/flutter/signin_next_steps/60_co -### Done +## Done import ios6 from '/src/fragments/lib-v1/auth/ios/signin_next_steps/70_done.mdx'; diff --git a/src/fragments/lib-v1/geo/android/escapehatch.mdx b/src/fragments/lib-v1/geo/android/escapehatch.mdx index eee50df3e9f..88b6772b41b 100644 --- a/src/fragments/lib-v1/geo/android/escapehatch.mdx +++ b/src/fragments/lib-v1/geo/android/escapehatch.mdx @@ -51,7 +51,7 @@ Log.i("MyAmplifyApp", response.entries.toString()) -### Documentation Resources +## Documentation Resources * [How to manage Amazon Location Service resources through console](https://docs.aws.amazon.com/location/latest/developerguide/welcome.html) diff --git a/src/fragments/lib-v1/geo/ios/escapehatch.mdx b/src/fragments/lib-v1/geo/ios/escapehatch.mdx index 9f710cf01ab..70be0439244 100644 --- a/src/fragments/lib-v1/geo/ios/escapehatch.mdx +++ b/src/fragments/lib-v1/geo/ios/escapehatch.mdx @@ -47,7 +47,7 @@ do { } ``` -### Documentation Resources +## Documentation Resources * [How to manage Amazon Location Service resources through console](https://docs.aws.amazon.com/location/latest/developerguide/welcome.html) diff --git a/src/fragments/lib-v1/graphqlapi/js/delta-sync.mdx b/src/fragments/lib-v1/graphqlapi/js/delta-sync.mdx index edd993e8320..83c192abb1a 100644 --- a/src/fragments/lib-v1/graphqlapi/js/delta-sync.mdx +++ b/src/fragments/lib-v1/graphqlapi/js/delta-sync.mdx @@ -33,17 +33,17 @@ subscription.unsubscribe(); - `query`: A `DocumentNode` for the base data (e.g. as returned by [`gql`](https://github.com/apollographql/graphql-tag#gql)) - `variables` [optional]: An object with the query variables, if any. - `baseRefreshIntervalInSeconds` [optional]: Number of seconds after which the base query will be run again. Default value: `86400` (24 hrs) - - `update` [optional]: A function to update the cache, see: [Apollo's `update` function](https://www.apollographql.com/docs/react/api/react-apollo.html#graphql-mutation-options-update) + - `update` [optional]: A function to update the cache, see: [Apollo's `update` function](https://www.apollographql.com/docs/react/data/mutations#the-update-function) **subscriptionQuery** - `query`: A `DocumentNode` for the subscription (e.g. as returned by [`gql`](https://github.com/apollographql/graphql-tag#gql)) - `variables` [optional]: An object with the query variables, if any. - - `update` [optional]: A function to update the cache, see: [Apollo's `update` function](https://www.apollographql.com/docs/react/api/react-apollo.html#graphql-mutation-options-update) + - `update` [optional]: A function to update the cache, see: [Apollo's `update` function](https://www.apollographql.com/docs/react/data/mutations#the-update-function) **deltaQuery** - `query`: A `DocumentNode` for the deltas (e.g. as returned by [`gql`](https://github.com/apollographql/graphql-tag#gql)) - `variables` [optional]: An object with the query variables, if any. - - `update` [optional]: A function to update the cache, see: [Apollo's `update` function](https://www.apollographql.com/docs/react/api/react-apollo.html#graphql-mutation-options-update) + - `update` [optional]: A function to update the cache, see: [Apollo's `update` function](https://www.apollographql.com/docs/react/data/mutations#the-update-function) ## The buildSync helper diff --git a/src/fragments/lib-v1/in-app-messaging/integrate-your-application/integrate-your-application.mdx b/src/fragments/lib-v1/in-app-messaging/integrate-your-application/integrate-your-application.mdx index f30fecd99ed..784c5d40468 100644 --- a/src/fragments/lib-v1/in-app-messaging/integrate-your-application/integrate-your-application.mdx +++ b/src/fragments/lib-v1/in-app-messaging/integrate-your-application/integrate-your-application.mdx @@ -16,7 +16,7 @@ import js1 from '/src/fragments/lib-v1/in-app-messaging/integrate-your-applicati -### Integrate In-App Messaging +## Integrate In-App Messaging Amplify UI provides a Higher-Order Component for ease of integrating the In-App Messaging UI with your application. Simply wrap your application root component in, for example, `App.js`. diff --git a/src/fragments/lib-v1/in-app-messaging/integrate-your-application/js/install-dependencies.mdx b/src/fragments/lib-v1/in-app-messaging/integrate-your-application/js/install-dependencies.mdx index a0f47aad688..26ed63d4294 100644 --- a/src/fragments/lib-v1/in-app-messaging/integrate-your-application/js/install-dependencies.mdx +++ b/src/fragments/lib-v1/in-app-messaging/integrate-your-application/js/install-dependencies.mdx @@ -1,6 +1,6 @@ {/* TODO What should be done with this page for non-react frameworks */} -### Install Amplify UI for React +## Install Amplify UI for React import js0 from '/src/fragments/lib-v1/in-app-messaging/integrate-your-application/ui-integration.mdx'; diff --git a/src/fragments/lib-v1/in-app-messaging/integrate-your-application/react-native/configure-amplify.mdx b/src/fragments/lib-v1/in-app-messaging/integrate-your-application/react-native/configure-amplify.mdx index 170b23dfe39..1d8e2333076 100644 --- a/src/fragments/lib-v1/in-app-messaging/integrate-your-application/react-native/configure-amplify.mdx +++ b/src/fragments/lib-v1/in-app-messaging/integrate-your-application/react-native/configure-amplify.mdx @@ -1,4 +1,4 @@ -### Configure Amplify +## Configure Amplify import rn1 from '/src/fragments/lib-v1/common/react-native/import_configuration.mdx'; diff --git a/src/fragments/lib-v1/in-app-messaging/integrate-your-application/react-native/install-dependencies.mdx b/src/fragments/lib-v1/in-app-messaging/integrate-your-application/react-native/install-dependencies.mdx index 0965237d597..7775307ceca 100644 --- a/src/fragments/lib-v1/in-app-messaging/integrate-your-application/react-native/install-dependencies.mdx +++ b/src/fragments/lib-v1/in-app-messaging/integrate-your-application/react-native/install-dependencies.mdx @@ -2,7 +2,7 @@ import reactnative0 from '/src/fragments/lib-v1/react-native-polyfills.mdx'; -### Install Amplify UI for React Native and its dependencies +## Install Amplify UI for React Native and its dependencies import reactnative1 from '/src/fragments/lib-v1/in-app-messaging/integrate-your-application/ui-integration.mdx'; diff --git a/src/fragments/lib-v1/push-notifications/common/receive-device-token.mdx b/src/fragments/lib-v1/push-notifications/common/receive-device-token.mdx index 88d87abc058..116ae4ca15a 100644 --- a/src/fragments/lib-v1/push-notifications/common/receive-device-token.mdx +++ b/src/fragments/lib-v1/push-notifications/common/receive-device-token.mdx @@ -1,6 +1,6 @@ Push notifications are delivered to your user's devices through a device token which uniquely identifies your app. Although Amplify will automatically register this token with Amazon Pinpoint, it can still be useful to have access to this token for your app's use cases (e.g. to send direct notifications to a specific device). -### onTokenReceived +## onTokenReceived Add `onTokenReceived` listeners to respond to a token being received by your app. diff --git a/src/fragments/lib-v1/react-native-polyfills.mdx b/src/fragments/lib-v1/react-native-polyfills.mdx index 4386092db05..f1e0906c3df 100644 --- a/src/fragments/lib-v1/react-native-polyfills.mdx +++ b/src/fragments/lib-v1/react-native-polyfills.mdx @@ -1,4 +1,4 @@ -### Install Amplify and its dependencies +## Install Amplify and its dependencies ```bash npm install aws-amplify@^5 amazon-cognito-identity-js @react-native-community/netinfo @react-native-async-storage/async-storage react-native-get-random-values react-native-url-polyfill diff --git a/src/fragments/lib-v1/storage/android/download.mdx b/src/fragments/lib-v1/storage/android/download.mdx index 26d512c00ba..926fd213d79 100644 --- a/src/fragments/lib-v1/storage/android/download.mdx +++ b/src/fragments/lib-v1/storage/android/download.mdx @@ -1,4 +1,4 @@ -### Download to file +## Download to file If you uploaded the data using the key `ExampleKey`, you can retrieve the data using `Amplify.Storage.downloadFile`. diff --git a/src/fragments/lib-v1/storage/ios/download.mdx b/src/fragments/lib-v1/storage/ios/download.mdx index 7c85b1d6658..e715bc7963a 100644 --- a/src/fragments/lib-v1/storage/ios/download.mdx +++ b/src/fragments/lib-v1/storage/ios/download.mdx @@ -1,6 +1,6 @@ There are three ways of getting data that was previously uploaded: -### Download data +## Download data You can download to in-memory buffer [Data](https://developer.apple.com/documentation/foundation/data) object with `Amplify.Storage.downloadData`: @@ -46,7 +46,7 @@ receiveValue: { data in -### Download to file +## Download to file You can download to a file [URL](https://developer.apple.com/documentation/foundation/url) with `Amplify.Storage.downloadFile`: diff --git a/src/fragments/lib-v1/storage/js/autotrack.mdx b/src/fragments/lib-v1/storage/js/autotrack.mdx index aecdfd931c7..b25c10a47ee 100644 --- a/src/fragments/lib-v1/storage/js/autotrack.mdx +++ b/src/fragments/lib-v1/storage/js/autotrack.mdx @@ -8,13 +8,13 @@ You can enable automatic tracking of Storage Events such as uploads and download the event, e.g. *Storage {'>'} Method {'>'} Put*. -### Track all the Storage events +## Track all the Storage events ```javascript Storage.configure({ track: true }); ``` -### Track a specific storage action +## Track a specific storage action ```javascript Storage.get('welcome.png', { track: true }); diff --git a/src/fragments/lib/analytics/js/personalize.mdx b/src/fragments/lib/analytics/js/personalize.mdx index 87aebc29bc3..247ad480e41 100644 --- a/src/fragments/lib/analytics/js/personalize.mdx +++ b/src/fragments/lib/analytics/js/personalize.mdx @@ -7,7 +7,7 @@ To record event data, you need the following: For more information, see [Record Events](https://docs.aws.amazon.com/personalize/latest/dg/recording-events.html). -### Installation and Configuration +## Installation and Configuration After creating the Amazon Personalize dataset group, you need to add the `personalize:PutEvents` permission to your Amplify IAM user roles. @@ -49,7 +49,7 @@ Amplify.configure({ } }); ``` -### Working with the API +## Working with the API You can use the `Identify` event type to track a user identity. This lets you connect a user to their actions and record traits about them. To identify a user, specify a unique identifier for the userId property. Consider the following user interactions when choosing when and how often to call record with the Identify eventType: diff --git a/src/fragments/lib/auth/android/signin_next_steps/80_current_user.mdx b/src/fragments/lib/auth/android/signin_next_steps/80_current_user.mdx index fdbef661b2d..607c30f52a8 100644 --- a/src/fragments/lib/auth/android/signin_next_steps/80_current_user.mdx +++ b/src/fragments/lib/auth/android/signin_next_steps/80_current_user.mdx @@ -1,4 +1,4 @@ -### Get Current User +## Get Current User This call fetches the current logged in user and should be used after a user has been successfully signed in. If the user is signed in, it will return the current userId and username. diff --git a/src/fragments/lib/auth/flutter/access_credentials/10_fetchAuthSession.mdx b/src/fragments/lib/auth/flutter/access_credentials/10_fetchAuthSession.mdx index 34434da6f25..710e6c668af 100644 --- a/src/fragments/lib/auth/flutter/access_credentials/10_fetchAuthSession.mdx +++ b/src/fragments/lib/auth/flutter/access_credentials/10_fetchAuthSession.mdx @@ -11,7 +11,7 @@ Future fetchAuthSession() async { } ``` -### Retrieving AWS credentials +## Retrieving AWS credentials Sometimes it can be helpful to retrieve the instance of the underlying plugin which has more specific typing. In the case of Cognito, calling `fetchAuthSession` diff --git a/src/fragments/lib/auth/native_common/signin_next_steps/common.mdx b/src/fragments/lib/auth/native_common/signin_next_steps/common.mdx index 8c615f36156..0f1ab188ea9 100644 --- a/src/fragments/lib/auth/native_common/signin_next_steps/common.mdx +++ b/src/fragments/lib/auth/native_common/signin_next_steps/common.mdx @@ -19,7 +19,7 @@ import flutter0 from '/src/fragments/lib/auth/flutter/signin_next_steps/10_signi -### Confirm signin with SMS MFA +## Confirm signin with SMS MFA import ios1 from '/src/fragments/lib/auth/ios/signin_next_steps/20_confirm_sms_mfa.mdx'; @@ -33,7 +33,7 @@ import flutter1 from '/src/fragments/lib/auth/flutter/signin_next_steps/20_confi -### Confirm signin with TOTP MFA +## Confirm signin with TOTP MFA If the next step is `CONFIRM_SIGN_IN_WITH_TOTP_CODE`, you should prompt the user to enter the TOTP code from their associated authenticator app during set up. The code is a six-digit number that changes every 30 seconds. The user must enter the code before the 30-second window expires. @@ -167,7 +167,7 @@ Future confirmTotpUser(String totpCode) async { -### Continue signin with MFA Selection +## Continue signin with MFA Selection If the next step is `CONTINUE_SIGN_IN_WITH_MFA_SELECTION`, the user must select the MFA method to use. Amplify Auth currently only supports SMS and TOTP as MFA methods. After the user selects an MFA method, your implementation must pass the selected MFA method to Amplify Auth using `confirmSignIn` API. @@ -288,7 +288,7 @@ Future _handleMfaSelection(MfaType selection) async { -### Continue signin with TOTP Setup +## Continue signin with TOTP Setup If the next step is `CONTINUE_SIGN_IN_WITH_TOTP_SETUP`, then the user must provide a TOTP code to complete the sign in process. The step returns an associated value of type `TOTPSetupDetails` which would be used for generating TOTP. `TOTPSetupDetails` provides a helper method called `getSetupURI` that can be used to generate a URI, which can be used by native password managers for TOTP association. For example. if the URI is used on Apple platforms, it will trigger the platform's native password manager to associate TOTP with the account. For more advanced use cases, `TOTPSetupDetails` also contains the `sharedSecret` that will be used to either generate a QR code or can be manually entered into an authenticator app. @@ -476,7 +476,7 @@ Future confirmTotpUser(String totpCode) async { -### Confirm signin with custom challenge +## Confirm signin with custom challenge import ios2 from '/src/fragments/lib/auth/ios/signin_next_steps/30_confirm_custom_challenge.mdx'; @@ -490,7 +490,7 @@ import flutter2 from '/src/fragments/lib/auth/flutter/signin_next_steps/30_confi -### Confirm signin with new password +## Confirm signin with new password import ios3 from '/src/fragments/lib/auth/ios/signin_next_steps/40_confirm_new_password.mdx'; @@ -504,7 +504,7 @@ import flutter3 from '/src/fragments/lib/auth/flutter/signin_next_steps/40_confi -### Reset password +## Reset password import ios4 from '/src/fragments/lib/auth/ios/signin_next_steps/50_reset_password.mdx'; @@ -518,7 +518,7 @@ import flutter4 from '/src/fragments/lib/auth/flutter/signin_next_steps/50_reset -### Confirm Signup +## Confirm Signup import ios5 from '/src/fragments/lib/auth/ios/signin_next_steps/60_confirm_signup.mdx'; @@ -536,7 +536,7 @@ import flutter5 from '/src/fragments/lib/auth/flutter/signin_next_steps/60_confi -### Done +## Done import ios6 from '/src/fragments/lib/auth/ios/signin_next_steps/70_done.mdx'; diff --git a/src/fragments/lib/geo/android/escapehatch.mdx b/src/fragments/lib/geo/android/escapehatch.mdx index 335a5605f43..564f203c85f 100644 --- a/src/fragments/lib/geo/android/escapehatch.mdx +++ b/src/fragments/lib/geo/android/escapehatch.mdx @@ -74,7 +74,7 @@ Log.i("MyAmplifyApp", response.entries.toString()) -### Documentation Resources +## Documentation Resources * [How to manage Amazon Location Service resources through console](https://docs.aws.amazon.com/location/latest/developerguide/welcome.html) diff --git a/src/fragments/lib/geo/ios/escapehatch.mdx b/src/fragments/lib/geo/ios/escapehatch.mdx index d0b54d22fe2..85113283ea5 100644 --- a/src/fragments/lib/geo/ios/escapehatch.mdx +++ b/src/fragments/lib/geo/ios/escapehatch.mdx @@ -29,7 +29,7 @@ do { } ``` -### Documentation Resources +## Documentation Resources - [How to manage Amazon Location Service resources through console](https://docs.aws.amazon.com/location/latest/developerguide/welcome.html) diff --git a/src/fragments/lib/graphqlapi/ios/upgrade-guide.mdx b/src/fragments/lib/graphqlapi/ios/upgrade-guide.mdx index 719971cdb00..1e3250514a2 100644 --- a/src/fragments/lib/graphqlapi/ios/upgrade-guide.mdx +++ b/src/fragments/lib/graphqlapi/ios/upgrade-guide.mdx @@ -66,10 +66,10 @@ do { } ``` -### Optimistic UI and cached data revalidation +## Optimistic UI and cached data revalidation If you've used the AWS AppSync SDK's caching capabilities for optimistic UI, then we recommend you to follow our [Optimistic UI](/gen1/[platform]/build-a-backend/graphqlapi/optimistic-ui/) guide. In this guide, you'll learn how to use AWS Amplify's API category in conjunction with SwiftUI to achieve optimistic UI and cached data invalidation use cases. -### Complex objects support +## Complex objects support If you were using complex objects in the AWS AppSync SDK for iOS (Maintenance mode), then we recommend you to follow our [Working with Files](/gen1/[platform]/build-a-backend/graphqlapi/working-with-files) guide. This guide details the recommended path to store file metadata in your GraphQL API records and use Amplify Storage to store blob data in Amazon S3. diff --git a/src/fragments/lib/graphqlapi/js/delta-sync.mdx b/src/fragments/lib/graphqlapi/js/delta-sync.mdx index edd993e8320..83c192abb1a 100644 --- a/src/fragments/lib/graphqlapi/js/delta-sync.mdx +++ b/src/fragments/lib/graphqlapi/js/delta-sync.mdx @@ -33,17 +33,17 @@ subscription.unsubscribe(); - `query`: A `DocumentNode` for the base data (e.g. as returned by [`gql`](https://github.com/apollographql/graphql-tag#gql)) - `variables` [optional]: An object with the query variables, if any. - `baseRefreshIntervalInSeconds` [optional]: Number of seconds after which the base query will be run again. Default value: `86400` (24 hrs) - - `update` [optional]: A function to update the cache, see: [Apollo's `update` function](https://www.apollographql.com/docs/react/api/react-apollo.html#graphql-mutation-options-update) + - `update` [optional]: A function to update the cache, see: [Apollo's `update` function](https://www.apollographql.com/docs/react/data/mutations#the-update-function) **subscriptionQuery** - `query`: A `DocumentNode` for the subscription (e.g. as returned by [`gql`](https://github.com/apollographql/graphql-tag#gql)) - `variables` [optional]: An object with the query variables, if any. - - `update` [optional]: A function to update the cache, see: [Apollo's `update` function](https://www.apollographql.com/docs/react/api/react-apollo.html#graphql-mutation-options-update) + - `update` [optional]: A function to update the cache, see: [Apollo's `update` function](https://www.apollographql.com/docs/react/data/mutations#the-update-function) **deltaQuery** - `query`: A `DocumentNode` for the deltas (e.g. as returned by [`gql`](https://github.com/apollographql/graphql-tag#gql)) - `variables` [optional]: An object with the query variables, if any. - - `update` [optional]: A function to update the cache, see: [Apollo's `update` function](https://www.apollographql.com/docs/react/api/react-apollo.html#graphql-mutation-options-update) + - `update` [optional]: A function to update the cache, see: [Apollo's `update` function](https://www.apollographql.com/docs/react/data/mutations#the-update-function) ## The buildSync helper diff --git a/src/fragments/lib/in-app-messaging/integrate-your-application/integrate-your-application.mdx b/src/fragments/lib/in-app-messaging/integrate-your-application/integrate-your-application.mdx index 7075de6f09e..3701f39833e 100644 --- a/src/fragments/lib/in-app-messaging/integrate-your-application/integrate-your-application.mdx +++ b/src/fragments/lib/in-app-messaging/integrate-your-application/integrate-your-application.mdx @@ -4,7 +4,7 @@ In your application directory, you should first install the necessary dependenci npm install aws-amplify ``` -### Initialize In-App Messaging +## Initialize In-App Messaging To finish setting up your application with Amplify, you need to configure it using the `configure` API. Next, to interact with In-App Messaging APIs, you need to first initialize In-App Messaging by calling the `initializeInAppMessaging` API directly imported from the `in-app-messaging` sub-path. This is required to be called as early as possible in the app lifecycle. @@ -29,7 +29,7 @@ import js0 from '/src/fragments/lib/in-app-messaging/integrate-your-application/ -### Integrate Amplify UI +## Integrate Amplify UI Amplify UI provides a Higher-Order Component for ease of integrating the In-App Messaging UI with your application. Simply wrap your application root component in, for example, `App.js`. diff --git a/src/fragments/lib/in-app-messaging/integrate-your-application/js/install-ui-dependencies.mdx b/src/fragments/lib/in-app-messaging/integrate-your-application/js/install-ui-dependencies.mdx index a8f06c5716c..80883dad9d5 100644 --- a/src/fragments/lib/in-app-messaging/integrate-your-application/js/install-ui-dependencies.mdx +++ b/src/fragments/lib/in-app-messaging/integrate-your-application/js/install-ui-dependencies.mdx @@ -1,6 +1,6 @@ {/* TODO What should be done with this page for non-react frameworks */} -### Install Amplify UI for React +## Install Amplify UI for React import js0 from '/src/fragments/lib/in-app-messaging/integrate-your-application/ui-integration.mdx'; diff --git a/src/fragments/lib/in-app-messaging/integrate-your-application/react-native/install-dependencies.mdx b/src/fragments/lib/in-app-messaging/integrate-your-application/react-native/install-dependencies.mdx index db8c2e07ef5..1aacbf80a69 100644 --- a/src/fragments/lib/in-app-messaging/integrate-your-application/react-native/install-dependencies.mdx +++ b/src/fragments/lib/in-app-messaging/integrate-your-application/react-native/install-dependencies.mdx @@ -1,4 +1,4 @@ -### Install the Amplify React Native Package and other dependencies +## Install the Amplify React Native Package and other dependencies Installing the `@aws-amplify/react-native` will bring in the necessary polyfills. import rnVersionCallout from '/src/fragments/common/react-native-version-deployment-target.mdx'; @@ -9,7 +9,7 @@ import rnVersionCallout from '/src/fragments/common/react-native-version-deploym npm install @aws-amplify/react-native @react-native-community/netinfo @react-native-async-storage/async-storage ``` -### Install Amplify UI for React Native and its dependencies +## Install Amplify UI for React Native and its dependencies import reactnative1 from '/src/fragments/lib/in-app-messaging/integrate-your-application/ui-integration.mdx'; diff --git a/src/fragments/lib/ios-prereq-category.mdx b/src/fragments/lib/ios-prereq-category.mdx index 6907a9ff7d5..ed5b07f6d6e 100644 --- a/src/fragments/lib/ios-prereq-category.mdx +++ b/src/fragments/lib/ios-prereq-category.mdx @@ -3,15 +3,13 @@ An application with Amplify libraries integrated and a minimum target of any of - **macOS 10.15**, using **Xcode 14.1** or later. - **tvOS 13.0**, using **Xcode 14.3** or later. - **watchOS 9.0**, using **Xcode 14.3** or later. -- **visionOS 1.0**, using **Xcode 15 beta 2** or later. (Preview support - see below for more details.) +- **visionOS 1.0**, using **Xcode 15** or later. (Preview support - see below for more details.) For a full example, please follow the [project setup walkthrough](/gen1/[platform]/start/project-setup/prerequisites/). -visionOS support is currently in **preview** and can be used by targeting the [`visionos-preview`](https://github.com/aws-amplify/amplify-swift/tree/visionos-preview) branch. -As new Xcode 15 beta versions are released, the branch will be updated with any necessary fixes on a best effort basis. - -For more information on how to use the `visionos-preview` branch, see [Platform Support](https://github.com/aws-amplify/amplify-swift/tree/visionos-preview#platform-support). +visionOS support is currently in **preview** and can be used by using the latest [Amplify Release](https://github.com/aws-amplify/amplify-swift/releases). +As new Xcode and visionOS versions are released, the support will be updated with any necessary fixes on a best effort basis. diff --git a/src/fragments/lib/logging/common/access_logs/access_logs.mdx b/src/fragments/lib/logging/common/access_logs/access_logs.mdx index cae5a69cecc..bcec9e381de 100644 --- a/src/fragments/lib/logging/common/access_logs/access_logs.mdx +++ b/src/fragments/lib/logging/common/access_logs/access_logs.mdx @@ -3,7 +3,7 @@ For an authenticated user, the log stream name is `. -### Track download progress +## Track download progress To track progress of the download, use the `downloadFile` API that includes a progress listener callback. @@ -264,7 +264,7 @@ download -### Generate a download URL +## Generate a download URL You can also retrieve a URL for the object in storage: diff --git a/src/fragments/sdk/api/android/graphql.mdx b/src/fragments/sdk/api/android/graphql.mdx index 1da60b2fb84..d2a4ab50ca8 100644 --- a/src/fragments/sdk/api/android/graphql.mdx +++ b/src/fragments/sdk/api/android/graphql.mdx @@ -8,7 +8,7 @@ You can integrate with AWS AppSync using the following steps: The Amplify CLI provides support for AppSync that make this process easy. Using the CLI, you can configure an AWS AppSync API, download required client side configuration files, and generate client side code within minutes by running a few simple commands on the command line. -### Configuration +## Configuration The AWS SDKs support configuration through a centralized file called `awsconfiguration.json` that defines your AWS regions and service endpoints. You obtain this file in one of two ways, depending on whether you are creating your AppSync API in the AppSync console or using the Amplify CLI. @@ -16,11 +16,11 @@ The AWS SDKs support configuration through a centralized file called `awsconfigu - If you are creating your API with the Amplify CLI (using `amplify add api`), the `awsconfiguration.json` file is automatically downloaded and updated each time you run `amplify push` to update your cloud resources. The file is placed in the `./app/src/main/res/raw` directory of your Android Studio project. -### Code Generation +## Code Generation To execute GraphQL operations in Android you need to run a code generation process, which requires both the GraphQL schema and the statements (for example, queries, mutations, or subscriptions) that your client defines. The Amplify CLI toolchain makes this easy for you by automatically pulling down your schema and generating default GraphQL queries, mutations, and subscriptions before kicking off the code generation process using Gradle. If your client requirements change, you can alter these GraphQL statements and kick off a Gradle build again to regenerate the types. -#### AppSync APIs Created in the Console +### AppSync APIs Created in the Console After installing the Amplify CLI open a terminal, go to your Android Studio project root, and then run the following: @@ -33,7 +33,7 @@ The `XXXXXX` is the unique AppSync API identifier that you can find in the conso **Note:** It is not necessary to run the command `amplify codegen` after adding an API, as code generation is done by the Gradle build process. However, if you subsequently update your API in the AppSync Console, you will need to re-run `amplify codegen` to update the local `schema.json` and `.graphql` with the modified schema. -#### AppSync APIs Created Using the CLI +### AppSync APIs Created Using the CLI Navigate in your terminal to an Android Studio project directory and run the following: @@ -83,7 +83,7 @@ amplify console api When prompted, select **GraphQL**. This will open the AWS AppSync console for you to run Queries, Mutations, or Subscriptions at the server and see the changes in your client app. -### Import SDK and Config +## Import SDK and Config To use AppSync in your Android studio project, modify the project's `build.gradle` by adding the Maven plugin repositories, and the AppSync Gradle plugin to `dependencies`. @@ -154,11 +154,11 @@ Finally, update your AndroidManifest.xml with updates to `` fo ``` -### Build your Project +## Build your Project Do not skip this step! Run `gradlew build`, or build your application via Android Studio. This will trigger the AppSync Gradle plugin that you added above to generate Java classes in your build folder based off of your schema files. These classes will be needed before proceeding to the steps below. -### Client Initialization +## Client Initialization Inside your application code, such as the `onCreate()` lifecycle method of your activity class, you can initialize the AppSync client using an instance of `AWSConfiguration()` in the `AWSAppSyncClient` builder like the following: @@ -180,7 +180,7 @@ protected void onCreate(Bundle savedInstanceState) { `AWSConfiguration()` reads configuration information in the `awsconfiguration.json` file. By default, the information in the `Default` section of the json file is used. -### Run a Query +## Run a Query Now that the client is configured, you can run a GraphQL query. The syntax of the callback is `GraphQLCall.Callback<{NAME}Query.Data>` where `{NAME}` comes from the GraphQL statements that `amplify codegen` created after you ran a Gradle build. You invoke this from an instance of the AppSync client with a similar syntax of `.query({NAME}Query.builder().build())`. For example, if you have a `ListTodos` query, your code will look like the following: @@ -206,7 +206,7 @@ private GraphQLCall.Callback todosCallback = new GraphQLCal Optionally, you can change the cache policy on `AppSyncResponseFetchers`, but we recommend leaving `CACHE_AND_NETWORK` because it pulls results from the local cache first before retrieving data over the network. This gives a snappy UX and offline support. -### Run a Mutation +## Run a Mutation To add data you need to run a GraphQL mutation. The syntax of the callback is `GraphQLCall.Callback<{NAME}Mutation.Data>` where `{NAME}` comes from the GraphQL statements that `amplify codegen` created after a Gradle build. However, most GraphQL schemas organize mutations with an `input` type for maintainability, which is what the Amplify CLI does as well. Therefore you'll pass this as a parameter called `input` created with a second builder. You invoke this from an instance of the AppSync client with a similar syntax of `.mutate({NAME}Mutation.builder().input({Name}Input).build())` like the following: @@ -234,7 +234,7 @@ private GraphQLCall.Callback mutationCallback = new Gra }; ``` -### Subscribe to Data +## Subscribe to Data Finally, it's time to set up a subscription to real-time data. The callback is just `AppSyncSubscriptionCall.Callback` and you invoke it with a client `.subscribe()` call and pass in a builder with syntax of `{NAME}Subscription.builder()` where `{NAME}` comes from the GraphQL statements that `amplify codegen` and Gradle build created. Note that the AppSync console and Amplify GraphQL transformer have a common nomenclature that puts the word `On` in front of a subscription as in the following example: @@ -267,7 +267,7 @@ private AppSyncSubscriptionCall.Callback subCallb Subscriptions can also take input types like mutations, in which case they will be subscribing to particular events based on the input. -### Background Tasks +## Background Tasks All GraphQL operations in the Android client are automatically run as asynchronous tasks and can be safely called from any thread. If you have a need to run GraphQL operations from a background thread you can do it with a `Runnable()` like the example below: @@ -318,7 +318,7 @@ try { } ``` -### Client Architecture +## Client Architecture The AppSync client supports offline scenarios with a programming model that provides a "write through cache". This allows you to both render data in the UI when offline as well as add/update through an "optimistic response". The below diagram shows how the AppSync client interfaces with the network GraphQL calls, it's offline mutation queue, the Apollo cache, and your application code. @@ -362,7 +362,7 @@ AWSAppSyncClient.builder() If you are performing a mutation, you can write an “optimistic response” anytime to this cache even if you are offline. You use the AppSync client to connect by passing in the query to update, reading the items off the cache. This normally returns a single item or list of items, depending on the GraphQL response type of the query to update. At this point you would add to the list, remove, or update it as appropriate and write back the response to the store persisting it to disk. When you reconnect to the network any responses from the service will overwrite the changes as the authoritative response. -#### Offline Mutations +### Offline Mutations As outlined in the architecture section, all query results are automatically persisted to disc with the AppSync client. For updating data through mutations when offline you will need to use an "optimistic response" by writing directly to the store. This is done by querying the store directly with `client.query().responseFetcher()` and passing in `AppSyncResponseFetchers.CACHE_ONLY` to pull the records for a specific query that you wish to update. @@ -449,11 +449,11 @@ private AWSAppSyncClient mAWSAppSyncClient = AWSAppSyncClient.builder() .build(); ``` -### Authorization Modes +## Authorization Modes For client authorization AppSync supports API Keys, Amazon IAM credentials (we recommend using Amazon Cognito Identity Pools for this option), Amazon Cognito User Pools, and 3rd party OIDC providers. This is inferred from the `awsconfiguration.json` when you call `.awsConfiguration()` on the `AWSAppSyncClient` builder. -#### API Key +### API Key API Key is the easiest way to setup and prototype your application with AppSync. It's also a good option if your application is completely public. If your application needs to interact with other AWS services besides AppSync, such as S3, you will need to use IAM credentials provided by Cognito Identity Pools, which also supports "Guest" access. See [the authentication section for more details](/gen1/[platform]/sdk/auth/getting-started/). For manual configuration, add the following snippet to your `awsconfiguration.json` file: @@ -479,7 +479,7 @@ private AWSAppSyncClient mAWSAppSyncClient = AWSAppSyncClient.builder() .build(); ``` -#### Cognito User Pools +### Cognito User Pools Amazon Cognito User Pools is the most common service to use with AppSync when adding user Sign-Up and Sign-In to your application. If your application needs to interact with other AWS services besides AppSync, such as S3, you will need to use IAM credentials with Cognito Identity Pools. The Amplify CLI can automatically configure this for you when running `amplify add auth` and can also automatically federate User Pools with Identity Pools. This allows you to have both User Pool credentials for AppSync and AWS credentials for S3. You can then use the `AWSMobileClient` for automatic credentials refresh [as outlined in the authentication section](/gen1/[platform]/sdk/auth/getting-started/). For manual configuration, add the following snippet to your `awsconfiguration.json` file: @@ -521,7 +521,7 @@ private AWSAppSyncClient mAWSAppSyncClient = AWSAppSyncClient.builder() }).build(); ``` -#### IAM +### IAM When using AWS IAM in a mobile application you should leverage Amazon Cognito Identity Pools. The Amplify CLI can automatically configure this for you when running `amplify add auth`. You can then use the `AWSMobileClient` for automatic credentials refresh [as outlined in the authentication section](/gen1/[platform]/sdk/auth/getting-started/) For manual configuration, add the following snippet to your `awsconfiguration.json` file: @@ -555,7 +555,7 @@ private AWSAppSyncClient mAWSAppSyncClient = AWSAppSyncClient.builder() .build(); ``` -#### OIDC +### OIDC If you are using a 3rd party OIDC provider you will need to configure it and manage the details of token refreshes yourself. Update the `awsconfiguration.json` file and code snippet as follows: @@ -592,7 +592,7 @@ private static String MyOIDCAuthProvider(){ } ``` -#### Multi-Auth +### Multi-Auth This section talks about the capability of AWS AppSync to configure multiple authorization modes for a single AWS AppSync endpoint and region. Follow the [AWS AppSync Multi-Auth](https://docs.aws.amazon.com/appsync/latest/devguide/security.html#using-additional-authorization-modes) to configure multiple authorization modes for your AWS AppSync endpoint. @@ -800,7 +800,7 @@ public class ClientFactory { } ``` -### Clear cache +## Clear cache Clears the data cached by the `AWSAppSyncClient` object on the local device. @@ -827,7 +827,7 @@ try { } ``` -### Delta Sync +## Delta Sync DeltaSync allows you to perform automatic synchronization with an AWS AppSync GraphQL server. The client will perform reconnection, exponential backoff, and retries when network errors take place for simplified data replication to devices. It does this by taking the results of a GraphQL query and caching it in the local Apollo cache. The DeltaSync API manages writes to the Apollo cache for you, and all rendering in your app (such as from React components, Angular bindings) should be done through a read-only fetch. diff --git a/src/fragments/sdk/api/ios/graphql.mdx b/src/fragments/sdk/api/ios/graphql.mdx index 7f3011ee440..88f07cea37b 100644 --- a/src/fragments/sdk/api/ios/graphql.mdx +++ b/src/fragments/sdk/api/ios/graphql.mdx @@ -8,7 +8,7 @@ You can integrate with AWS AppSync using the following steps: The Amplify CLI provides support for AppSync that make this process easy. Using the CLI, you can configure an AWS AppSync API, download required client side configuration files, and generate client side code within minutes by running a few simple commands on the command line. -### Configuration +## Configuration The AWS SDKs support configuration through a centralized file called `awsconfiguration.json` that defines your AWS regions and service endpoints. You obtain this file in one of two ways, depending on whether you are creating your AppSync API in the AppSync console or using the Amplify CLI. @@ -16,11 +16,11 @@ The AWS SDKs support configuration through a centralized file called `awsconfigu - If you are creating your API with the Amplify CLI (using `amplify add api`), the `awsconfiguration.json` file is automatically downloaded and updated each time you run `amplify push` to update your cloud resources. The file is placed in the root directory of your iOS project, and you need to add it to your Xcode project. -### Code Generation +## Code Generation To execute GraphQL operations in iOS you need to run a code generation process, which requires both the GraphQL schema and the statements (for example, queries, mutations, or subscriptions) that your client defines. The Amplify CLI toolchain helps you do this by automatically pulling down your schema and generating default GraphQL queries, mutations, and subscriptions before kicking off the code generation process. If your client requirements change, you can alter these GraphQL statements and regenerate your types. -#### AppSync APIs Created in the Console +### AppSync APIs Created in the Console After installing the Amplify CLI open a terminal, go to your Xcode project root, and then run the following: @@ -31,7 +31,7 @@ amplify add codegen --apiId XXXXXX The `XXXXXX` is the unique AppSync API identifier that you can find in the console in the root of your API's integration page. When you run this command you can accept the defaults, which create an `API.swift` file, and a `graphql` folder with your statements, in your root directory. -#### AppSync APIs Created Using the CLI +### AppSync APIs Created Using the CLI Navigate in your terminal to an Xcode project directory and run the following: @@ -81,7 +81,7 @@ amplify console api When prompted, select **GraphQL**. This will open the AWS AppSync console for you to run Queries, Mutations, or Subscriptions at the server and see the changes in your client app. -### Import SDK and Config +## Import SDK and Config To use AppSync in your Xcode project, modify your Podfile with a dependency of the AWS AppSync SDK as follows: @@ -94,7 +94,7 @@ end Run `pod install` from your terminal and open up the `.xcworkspace` Xcode project. Add the `API.swift` and `awsconfiguration.json` files to your project **(File->Add Files to ..->Add)** and then build your project, ensuring there are no issues. -### Client Initialization +## Client Initialization Initialize the AppSync client your application delegate by creating `AWSAppSyncClientConfiguration` and `AWSAppSyncClient` like the following: @@ -167,7 +167,7 @@ struct ContentView: View { } ``` -### Run a Query +## Run a Query Now that the client is set up, you can run a GraphQL query. The syntax is `appSyncClient?.fetch(query: Query() {(result, error)})` where `` comes from the GraphQL statements that `amplify codegen` created. For example, if you have a `ListTodos` query your code will look like the following: @@ -190,7 +190,7 @@ appSyncClient?.fetch(query: ListTodosQuery(), cachePolicy: .returnCacheDataAndFe `returnCacheDataAndFetch` pulls results from the local cache first before retrieving data over the network. This gives a snappy UX and offline support. -#### Considerations for SwiftUI +### Considerations for SwiftUI When using `List` and `ForEach` for SwiftUI the structure needs to conform to `Identifiable`. The code generated for Swift does not make the structure `Identifiable` but as long as you have a unique id associated with the object then you can retroactively mark a field as unique. Here is some example code for `ListTodosQuery()` @@ -201,7 +201,7 @@ ForEach(listTodosStore.listTodos.identified(by:\.id)){ todo in ``` -### Run a Mutation +## Run a Mutation To add data you need to run a GraphQL mutation. The syntax is `appSyncClient?.perform(mutation: Mutation() {(result, error)})` where `` comes from the GraphQL statements that `amplify codegen` created. However, most GraphQL schemas organize mutations with an `input` type for maintainability, which is what the AppSync console and Amplify CLI do as well. Therefore, you need to pass this as a parameter called `input`, as in the following example: @@ -219,11 +219,11 @@ appSyncClient?.perform(mutation: CreateTodoMutation(input: mutationInput)) { (re } ``` -#### Working with Complex Objects +### Working with Complex Objects Sometimes you might want to create logical objects that have more complex data, such as images or videos, as part of their structure. For example, you might create a Person type with a profile picture or a Post type that has an associated image. You can use AWS AppSync to model these as GraphQL types and [automatically store them to S3](/gen1/[platform]/sdk/storage/graphql-api/). -### Subscribe to Data +## Subscribe to Data Finally, it's time to set up a subscription to real-time data. The syntax `appSyncClient?.subscribe(subscription: Subscription() {(result, transaction, error)})` where `` comes from the GraphQL statements that `amplify codegen` created. Note that the AppSync console and Amplify GraphQL transformer have a common nomenclature that puts the word `On` in front of a subscription as in the following example: @@ -252,7 +252,7 @@ do { Like mutations, subscriptions can also take input types, in which case they will be subscribing to particular events based on the input. To learn more about subscription arguments, see [AWS AppSync Subscription Arguments](https://docs.aws.amazon.com/appsync/latest/devguide/real-time-data.html#using-subscription-arguments). -### Client Architecture +## Client Architecture The AppSync client supports offline scenarios with a programming model that provides a "write through cache". This allows you to both render data in the UI when offline as well as add/update through an "optimistic response". The below diagram shows how the AppSync client interfaces with the network GraphQL calls, its offline mutation queue, the Apollo cache, and your application code. @@ -281,7 +281,7 @@ appSyncClient?.apolloClient?.cacheKeyForObject = { $0["id"] } If you are performing a mutation, you can write an “optimistic response” anytime to this cache even if you are offline. You use the AppSync client to connect by passing in the query to update, reading the items off the cache. This normally returns a single item or list of items, depending on the GraphQL response type of the query to update. At this point you would add to the list, remove, or update it as appropriate and write back the response to the store persisting it to disk. When you reconnect to the network any responses from the service will overwrite the changes as the authoritative response. -#### Offline Mutations +### Offline Mutations As outlined in the architecture section, all query results are automatically persisted to disc with the AppSync client. For updating data through mutations when offline you will need to use an "optimistic response" with a transaction. This is done by passing an `optimisticUpdate` in the `appSyncClient?.perform()` mutation method using a `transaction`, where you pass in a query that will be updated in the cache. Inside of this transaction, you can write to the store via `appSyncClient?.store?.withinReadWriteTransaction`. @@ -341,11 +341,11 @@ func optimisticCreateTodo(input: CreateTodoInput, query:ListTodosQuery) { You might add similar code in your app for updating or deleting items using an optimistic response, it would look largely similar except that you might overwrite or remove an element from the `data.listTodos?.items` array. -### Authorization Modes +## Authorization Modes For client authorization AppSync supports API Keys, Amazon IAM credentials (we recommend using Amazon Cognito Identity Pools for this option), Amazon Cognito User Pools, and 3rd party OIDC providers. This is inferred from the `awsconfiguration.json` file when you call `AWSAppSyncClientConfiguration(appSyncServiceConfig: AWSAppSyncServiceConfig()`. -#### API Key +### API Key API Key is the easiest way to setup and prototype your application with AppSync. It's also a good option if your application is completely public. If your application needs to interact with other AWS services besides AppSync, such as S3, you will need to use IAM credentials provided by Cognito Identity Pools, which also supports "Guest" access. See [the authentication section for more details](/gen1/[platform]/sdk/auth/). For manual configuration, add the following snippet to your `awsconfiguration.json` file: @@ -379,7 +379,7 @@ do { } ``` -#### Cognito User Pools +### Cognito User Pools Amazon Cognito User Pools is the most common service to use with AppSync when adding user Sign-Up and Sign-In to your application. If your application needs to interact with other AWS services besides AppSync, such as S3, you will need to use IAM credentials with Cognito Identity Pools. The Amplify CLI can automatically configure this for you when running `amplify add auth` and can also automatically federate User Pools with Identity Pools. This allows you to have both User Pool credentials for AppSync and AWS credentials for S3. You can then use the `AWSMobileClient` for automatic credentials refresh [as outlined in the authentication section](/gen1/[platform]/sdk/auth/). For manual configuration, add the following snippet to your `awsconfiguration.json` file: @@ -438,7 +438,7 @@ class MyCognitoUserPoolsAuthProvider : AWSCognitoUserPoolsAuthProviderAsync { } ``` -#### IAM +### IAM When using AWS IAM in a mobile application you should leverage Amazon Cognito Identity Pools. The Amplify CLI can automatically configure this for you when running `amplify add auth`. You can then use the `AWSMobileClient` for automatic credentials refresh [as outlined in the authentication section](/gen1/[platform]/sdk/auth/) For manual configuration, add the following snippet to your `awsconfiguration.json` file: @@ -480,7 +480,7 @@ do { } ``` -#### OIDC +### OIDC If you are using a 3rd party OIDC provider you will need to configure it and manage the details of token refreshes yourself. Update the `awsconfiguration.json` file and code snippet as follows: @@ -521,7 +521,7 @@ do { } ``` -#### Multi-Auth +### Multi-Auth This section talks about the capability of AWS AppSync to configure multiple authorization modes for a single AWS AppSync endpoint and region. Follow the [AWS AppSync Multi-Auth](https://docs.aws.amazon.com/appsync/latest/devguide/security.html#using-additional-authorization-modes) to configure multiple authorization modes for your AWS AppSync endpoint. @@ -683,7 +683,7 @@ appSyncClient?.fetch(query: GetPostQuery()) { (result, error) in } ``` -### Clear cache +## Clear cache Clears the data cached by the `AWSAppSyncClient` object on the local device. @@ -703,7 +703,7 @@ let clearCacheOptions = ClearCacheOptions( appSyncClient.clearCaches(options: clearCacheOptions) ``` -### Delta Sync +## Delta Sync DeltaSync allows you to perform automatic synchronization with an AWS AppSync GraphQL server. The client will perform reconnection, exponential backoff, and retries when network errors take place for simplified data replication to devices. It does this by taking the results of a GraphQL query and caching it in the local Apollo cache. diff --git a/src/fragments/sdk/auth/android/federated-identities.mdx b/src/fragments/sdk/auth/android/federated-identities.mdx index 5d95a9d863f..18b6934da4e 100644 --- a/src/fragments/sdk/auth/android/federated-identities.mdx +++ b/src/fragments/sdk/auth/android/federated-identities.mdx @@ -1,6 +1,6 @@ Currently, the federation feature in the AWSMobileClient supports Cognito Identity Pools only. -### Federated Sign In +## Federated Sign In ```java AWSMobileClient.getInstance().federatedSignIn(IdentityProvider.FACEBOOK.toString(), "FACEBOOK_TOKEN_HERE", new Callback() { @@ -20,7 +20,7 @@ AWSMobileClient.getInstance().federatedSignIn(IdentityProvider.FACEBOOK.toString The API calls to get AWS credentials will be asynchronously blocked until you fetch the social provider's token and give it to `AWSMobileClient`. Once you pass the tokens, the `AWSMobileClient` will fetch AWS Credentials using the new tokens and unblock all waiting calls. It will then use the new credentials. -#### SAML with Cognito Identity +### SAML with Cognito Identity To federate your SAML sign-in provider as a user sign-in provider for AWS services called in your app, you will pass tokens to `AWSMobileClient.getInstance().federatedSignIn()`. You must first register your SAML application with AWS IAM by using the following [instructions](https://docs.aws.amazon.com/cognito/latest/developerguide/saml-identity-provider.html). @@ -60,7 +60,7 @@ AWSMobileClient.getInstance().federatedSignIn("YOUR_SAML_PROVIDER_NAME", "YOUR_S }); ``` -### Set up Facebook +## Set up Facebook To federate Facebook as a user sign-in provider for AWS services called in your app, you will pass tokens to `AWSMobileClient.getInstance().federatedSignIn()`. You must first register your application with Facebook by using the [Facebook Developers portal](https://developers.facebook.com/) and configure this with Amazon Cognito Identity Pools. @@ -111,7 +111,7 @@ You can now [configure Facebook in your mobile app](#facebook-login-in-your-mobi Note that the CLI allows you to select more than one identity provider for your app. You can also run `amplify auth update` to add an identity provider to an existing auth configuration. -### Set up Google +## Set up Google To federate Google as a user sign-in provider for AWS services called in your app, you will pass tokens to `AWSMobileClient.getInstance().federatedSignIn()`. You must first register your application with Google Sign-In in the Google Developers Console, and then configure this with Amazon Cognito Identity Pools. @@ -156,7 +156,7 @@ You can now [configure Google in your mobile app](#google-login-in-your-mobile-a > Note that the CLI allows you to select more than one identity provider for your app. You can also run `amplify update auth` to add an identity provider to an existing auth configuration. -### Set up Sign in with Apple +## Set up Sign in with Apple To federate Sign in with Apple as a user sign-in provider for AWS services called in your app, you will pass tokens to `AWSMobileClient.getInstance().federatedSignIn()`. You must set up your application to use Sign in with Apple, and then configure Amazon Cognito Identity Pools to use Apple as an authentication provider. There are three main steps to setting up Sign in with Apple: implementing Sign in with Apple in your app, configuring Sign in with Apple as an authentication provider in your Amazon Cognito Identity Pool, and passing the Sign in with Apple token to AWSMobileClient via `federatedSignIn`. @@ -197,7 +197,7 @@ To federate Sign in with Apple as a user sign-in provider for AWS services calle After the `federatedSignIn` method successfully completes, `AWSMobileClient` will automatically use the federated identity to obtain credentials to make AWS service calls. -### Facebook Login in Your Mobile App +## Facebook Login in Your Mobile App > **Use Android API level 23 or higher** The `AWSMobileClient` library for Android sign-in provides the activity and view for presenting a `SignInUI` for the sign-in providers you configure. This library depends on the Android SDK API Level 23 or higher. @@ -307,7 +307,7 @@ public class AuthenticatorActivity extends Activity { } ``` -### Google Login in Your Mobile App +## Google Login in Your Mobile App > **Use Android API level 23 or higher** The `AWSMobileClient` library for Android sign-in provides the activity and view for presenting a `SignInUI` for the sign-in providers you configure. This library depends on the Android SDK API Level 23 or higher. diff --git a/src/fragments/sdk/storage/ios/getting-started.mdx b/src/fragments/sdk/storage/ios/getting-started.mdx index bb4f900a6f4..2a4239f3853 100644 --- a/src/fragments/sdk/storage/ios/getting-started.mdx +++ b/src/fragments/sdk/storage/ios/getting-started.mdx @@ -1,8 +1,8 @@ -### Overview +## Overview Enable your app to store and retrieve user files from cloud storage with the permissions model that suits your purpose. The Amplify CLI will deploy and configures cloud storage buckets using [Amazon Simple Storage Service](http://docs.aws.amazon.com/AmazonS3/latest/dev/). -### Storage Access +## Storage Access The CLI configures three different access levels on the storage bucket: public, protected and private. When you run `amplify add storage`, the CLI will configure appropriate IAM policies on the bucket using an Amazon Cognito Identity Pools IAM Role. You will have the option of adding CRUD (Create, Read, Update, and Delete) permissions as well so that Authenticated and Guest users will be granted different permissions based on these levels. @@ -14,7 +14,7 @@ If you had previously enabled user sign-in by running `amplify add auth` in your > The `cognito_user_identity_id` corresponds to the owner's unique Amazon Cognito Identity ID. See [Authentication](/gen1/[platform]/sdk/auth/working-with-api/#utility-properties) for more information on how to get the `cognito_user_identity_id` for a signed in user. -### Set Up Your Backend +## Set Up Your Backend 1. Complete the [Get Started](/gen1/[platform]/start/getting-started/introduction/) steps before you proceed. @@ -56,11 +56,11 @@ If you had previously enabled user sign-in by running `amplify add auth` in your - Clear the `Copy items if needed` check box. - Choose `Create groups`, and then choose `Finish`. -##### Lambda Triggers +### Lambda Triggers The Amplify CLI supports associating Lambda triggers for Amazon S3 and DynamoDB events. This can be useful for a use case where you want to invoke a Lambda function after a create or update operation on a DynamoDB table managed by the CLI. [Read More](/gen1/[platform]/tools/cli/usage/lambda-triggers/#s3-lambda-triggers) -### Connect to Your Backend +## Connect to Your Backend Use the following steps to add storage services to your app. diff --git a/src/fragments/start/getting-started/flutter/nextsteps.mdx b/src/fragments/start/getting-started/flutter/nextsteps.mdx index c3e8a7a957b..0f3863fe743 100644 --- a/src/fragments/start/getting-started/flutter/nextsteps.mdx +++ b/src/fragments/start/getting-started/flutter/nextsteps.mdx @@ -8,7 +8,7 @@ in more depth or dive into the other categories and add them to your application - [REST API](/gen1/[platform]/build-a-backend/restapi/set-up-rest-api/) - [Storage](/gen1/[platform]/build-a-backend/storage/set-up-storage/) -### Escape Hatch +## Escape Hatch As an alternative to the Amplify client libraries, or in situations where the libraries do not provide the functionality you require, the underlying AWS services can be communicated with [directly](/gen1/[platform]/start/project-setup/escape-hatch/) diff --git a/src/fragments/start/getting-started/next/setup.mdx b/src/fragments/start/getting-started/next/setup.mdx index 25a4202bc10..47329c57e1b 100644 --- a/src/fragments/start/getting-started/next/setup.mdx +++ b/src/fragments/start/getting-started/next/setup.mdx @@ -1,6 +1,7 @@ This tutorial is built using the pages directory from NextJS. To learn more about using Amplify with the NextJS app directory please visit this [documentation page](/gen1/[platform]/build-a-backend/server-side-rendering/set-up-ssr/#use-amplify-with-nextjs-app-router-app-directory). +**Note:** We currently support Next.js versions 13.5.0 up to 14.x. We are working to support version 15 or newer. diff --git a/src/pages/[platform]/build-a-backend/add-aws-services/analytics/personalize-recommendations/index.mdx b/src/pages/[platform]/build-a-backend/add-aws-services/analytics/personalize-recommendations/index.mdx index 5bb220ff0a3..e71f032ca08 100644 --- a/src/pages/[platform]/build-a-backend/add-aws-services/analytics/personalize-recommendations/index.mdx +++ b/src/pages/[platform]/build-a-backend/add-aws-services/analytics/personalize-recommendations/index.mdx @@ -35,7 +35,7 @@ To record event data, you need the following: For more information, see [Record Events](https://docs.aws.amazon.com/personalize/latest/dg/recording-events.html). -### Installation and Configuration +## Installation and Configuration After creating the Amazon Personalize dataset group, you need to add the `personalize:PutEvents` permission to your AWS Identity and Access Management (IAM) user roles. @@ -73,7 +73,7 @@ Amplify.configure({ } }); ``` -### Working with the API +## Working with the API You can use the `Identify` event type to track a user identity. This lets you connect a user to their actions and record traits about them. To identify a user, specify a unique identifier for the userId property. Consider the following user interactions when choosing when and how often to call record with the Identify eventType: diff --git a/src/pages/[platform]/build-a-backend/add-aws-services/analytics/set-up-analytics/index.mdx b/src/pages/[platform]/build-a-backend/add-aws-services/analytics/set-up-analytics/index.mdx index 34d70a829c4..2577a83d329 100644 --- a/src/pages/[platform]/build-a-backend/add-aws-services/analytics/set-up-analytics/index.mdx +++ b/src/pages/[platform]/build-a-backend/add-aws-services/analytics/set-up-analytics/index.mdx @@ -39,14 +39,12 @@ An application with Amplify libraries integrated and a minimum target of any of - **macOS 10.15**, using **Xcode 14.1** or later. - **tvOS 13.0**, using **Xcode 14.3** or later. - **watchOS 9.0**, using **Xcode 14.3** or later. -- **visionOS 1.0**, using **Xcode 15 beta 2** or later. (Preview support - see below for more details.) +- **visionOS 1.0**, using **Xcode 15** or later. (Preview support - see below for more details.) -visionOS support is currently in **preview** and can be used by targeting the [`visionos-preview`](https://github.com/aws-amplify/amplify-swift/tree/visionos-preview) branch. -As new Xcode 15 beta versions are released, the branch will be updated with any necessary fixes on a best effort basis. - -For more information on how to use the `visionos-preview` branch, see [Platform Support](https://github.com/aws-amplify/amplify-swift/tree/visionos-preview#platform-support). +visionOS support is currently in **preview** and can be used by using the latest [Amplify Release](https://github.com/aws-amplify/amplify-swift/releases). +As new Xcode and visionOS versions are released, the support will be updated with any necessary fixes on a best effort basis. diff --git a/src/pages/[platform]/build-a-backend/add-aws-services/custom-resources/index.mdx b/src/pages/[platform]/build-a-backend/add-aws-services/custom-resources/index.mdx index 0928aba64b7..4f61e7851a4 100644 --- a/src/pages/[platform]/build-a-backend/add-aws-services/custom-resources/index.mdx +++ b/src/pages/[platform]/build-a-backend/add-aws-services/custom-resources/index.mdx @@ -170,7 +170,7 @@ const client = new SNSClient({ region: process.env.AWS_REGION }); export const handler: Handler = async (event) => { const { subject, body, recipient } = event; const command = new PublishCommand({ - TopicArn: process.env.TOPIC_ARN, + TopicArn: process.env.SNS_TOPIC_ARN, Message: JSON.stringify({ subject, body, diff --git a/src/pages/[platform]/build-a-backend/add-aws-services/deletion-backup-resources/index.mdx b/src/pages/[platform]/build-a-backend/add-aws-services/deletion-backup-resources/index.mdx index 1dbb7623b43..d1c468ed93e 100644 --- a/src/pages/[platform]/build-a-backend/add-aws-services/deletion-backup-resources/index.mdx +++ b/src/pages/[platform]/build-a-backend/add-aws-services/deletion-backup-resources/index.mdx @@ -159,3 +159,32 @@ plan.addSelection("BackupPlanSelection", { }); // highlight-end ``` + +## Retaining resources on stack deletion + +For example, if you would like to retain a resource on stack deletion, you can use the `applyRemovalPolicy` property on the resource to add a retention policy. + +```ts title="amplify/backend.ts" +import { defineBackend } from "@aws-amplify/backend"; +import { auth } from "./auth/resource"; +import { data } from "./data/resource"; +import { RemovalPolicy } from "aws-cdk-lib"; +import { storage } from "./storage/resource"; + +const backend = defineBackend({ + auth, + data, + storage, +}); + +// highlight-start +// Retain the S3 bucket on stack deletion +backend.storage.resources.bucket.applyRemovalPolicy(RemovalPolicy.RETAIN); + +// Retain the Cognito user pool on stack deletion +backend.auth.resources.userPool.applyRemovalPolicy(RemovalPolicy.RETAIN); + +// Retain the DynamoDB table on stack deletion +backend.data.resources.cfnResources.amplifyDynamoDbTables["Todo"].applyRemovalPolicy(RemovalPolicy.RETAIN); +// highlight-end +``` diff --git a/src/pages/[platform]/build-a-backend/add-aws-services/geo/amazon-location-sdk/index.mdx b/src/pages/[platform]/build-a-backend/add-aws-services/geo/amazon-location-sdk/index.mdx index 1497aececea..eda1a60200e 100644 --- a/src/pages/[platform]/build-a-backend/add-aws-services/geo/amazon-location-sdk/index.mdx +++ b/src/pages/[platform]/build-a-backend/add-aws-services/geo/amazon-location-sdk/index.mdx @@ -203,7 +203,7 @@ Log.i("MyAmplifyApp", response.entries.toString()) -### Documentation Resources +## Documentation Resources * [How to manage Amazon Location Service resources through console](https://docs.aws.amazon.com/location/latest/developerguide/welcome.html) @@ -254,7 +254,7 @@ do { } ``` -### Documentation Resources +## Documentation Resources - [How to manage Amazon Location Service resources through console](https://docs.aws.amazon.com/location/latest/developerguide/welcome.html) diff --git a/src/pages/[platform]/build-a-backend/add-aws-services/geo/set-up-geo/index.mdx b/src/pages/[platform]/build-a-backend/add-aws-services/geo/set-up-geo/index.mdx index 3cb76c85cf4..69846f5b435 100644 --- a/src/pages/[platform]/build-a-backend/add-aws-services/geo/set-up-geo/index.mdx +++ b/src/pages/[platform]/build-a-backend/add-aws-services/geo/set-up-geo/index.mdx @@ -164,10 +164,8 @@ For a full example, please follow the [project setup walkthrough](/[platform]/st -visionOS support is currently in **preview** and can be used by targeting the [`visionos-preview`](https://github.com/aws-amplify/amplify-swift/tree/visionos-preview) branch. -As new Xcode 15 beta versions are released, the branch will be updated with any necessary fixes on a best effort basis. - -For more information on how to use the `visionos-preview` branch, see [Platform Support](https://github.com/aws-amplify/amplify-swift/tree/visionos-preview#platform-support). +visionOS support is currently in **preview** and can be used by using the latest [Amplify Release](https://github.com/aws-amplify/amplify-swift/releases). +As new Xcode and visionOS versions are released, the support will be updated with any necessary fixes on a best effort basis. diff --git a/src/pages/[platform]/build-a-backend/add-aws-services/in-app-messaging/integrate-application/index.mdx b/src/pages/[platform]/build-a-backend/add-aws-services/in-app-messaging/integrate-application/index.mdx index 634260d1949..4cd767ad511 100644 --- a/src/pages/[platform]/build-a-backend/add-aws-services/in-app-messaging/integrate-application/index.mdx +++ b/src/pages/[platform]/build-a-backend/add-aws-services/in-app-messaging/integrate-application/index.mdx @@ -27,7 +27,7 @@ export function getStaticProps(context) { } -### Install the Amplify React Native Package and other dependencies +## Install the Amplify React Native Package and other dependencies Installing the `@aws-amplify/react-native` will bring in the necessary polyfills for React Native. @@ -45,7 +45,7 @@ Installing the `@aws-amplify/react-native` will bring in the necessary polyfills npm add @aws-amplify/react-native @react-native-community/netinfo @react-native-async-storage/async-storage ``` -### Install Amplify UI for React Native and its dependencies +## Install Amplify UI for React Native and its dependencies Although Amplify In-App Messaging can be used as a standalone JavaScript library, this guide will show you how to use it together with Amplify UI, which currently supports integration with React and React Native, to get started quickly. @@ -63,7 +63,7 @@ npm add @aws-amplify/ui-react-native react-native-safe-area-context {/* TODO What should be done with this page for non-react frameworks */} -### Install Amplify UI for React +## Install Amplify UI for React Although Amplify In-App Messaging can be used as a standalone JavaScript library, this guide will show you how to use it together with Amplify UI, which currently supports integration with React and React Native, to get started quickly. @@ -78,7 +78,7 @@ npm add @aws-amplify/ui-react @aws-amplify/ui-react-notifications ``` -### Integrate Amplify UI +## Integrate Amplify UI Amplify UI provides a Higher-Order Component for ease of integrating the In-App Messaging UI with your application. Simply wrap your application root component in, for example, `App.js`. diff --git a/src/pages/[platform]/build-a-backend/add-aws-services/interactions/chatbot/index.mdx b/src/pages/[platform]/build-a-backend/add-aws-services/interactions/chatbot/index.mdx index 6c8044c5779..79ee6609bde 100644 --- a/src/pages/[platform]/build-a-backend/add-aws-services/interactions/chatbot/index.mdx +++ b/src/pages/[platform]/build-a-backend/add-aws-services/interactions/chatbot/index.mdx @@ -27,7 +27,7 @@ export function getStaticProps(context) { } -### Send messages to bot +## Send messages to bot You can send a text message to chatbot backend with `send()` command. The method returns a promise that includes the chatbot response. ```javascript title="src/App.tsx" @@ -45,7 +45,7 @@ const response = await Interactions.send({ console.log(response.message); ``` -### Display end of chat message +## Display end of chat message You can use `onComplete()` method to register a function to catch errors or chatbot confirmations when the session successfully ends. diff --git a/src/pages/[platform]/build-a-backend/add-aws-services/logging/set-up-logging/index.mdx b/src/pages/[platform]/build-a-backend/add-aws-services/logging/set-up-logging/index.mdx index dcf1b3239f5..1a980604b32 100644 --- a/src/pages/[platform]/build-a-backend/add-aws-services/logging/set-up-logging/index.mdx +++ b/src/pages/[platform]/build-a-backend/add-aws-services/logging/set-up-logging/index.mdx @@ -82,10 +82,8 @@ For a full example, please follow the [mobile support walkthrough](/swift/start/ -visionOS support is currently in **preview** and can be used by targeting the [`visionos-preview`](https://github.com/aws-amplify/amplify-swift/tree/visionos-preview) branch. -As new Xcode 15 beta versions are released, the branch will be updated with any necessary fixes on a best effort basis. - -For more information on how to use the `visionos-preview` branch, see [Platform Support](https://github.com/aws-amplify/amplify-swift/tree/visionos-preview#platform-support). +visionOS support is currently in **preview** and can be used by using the latest [Amplify Release](https://github.com/aws-amplify/amplify-swift/releases). +As new Xcode and visionOS versions are released, the support will be updated with any necessary fixes on a best effort basis. diff --git a/src/pages/[platform]/build-a-backend/add-aws-services/logging/view-logs/index.mdx b/src/pages/[platform]/build-a-backend/add-aws-services/logging/view-logs/index.mdx index 684659f4c2a..0959835eec2 100644 --- a/src/pages/[platform]/build-a-backend/add-aws-services/logging/view-logs/index.mdx +++ b/src/pages/[platform]/build-a-backend/add-aws-services/logging/view-logs/index.mdx @@ -27,7 +27,7 @@ For an authenticated user, the log stream name is `. -### Working with the API +## Working with the API Generate an audio buffer for playback from a text input. diff --git a/src/pages/[platform]/build-a-backend/auth/concepts/multi-factor-authentication/index.mdx b/src/pages/[platform]/build-a-backend/auth/concepts/multi-factor-authentication/index.mdx index 122d25d0f6b..731e5b31427 100644 --- a/src/pages/[platform]/build-a-backend/auth/concepts/multi-factor-authentication/index.mdx +++ b/src/pages/[platform]/build-a-backend/auth/concepts/multi-factor-authentication/index.mdx @@ -28,11 +28,15 @@ export function getStaticProps() { }; } -Amplify Auth supports Multi-factor Authentication (MFA) for user sign-in flows. MFA is an extra layer of security used to make sure that users trying to gain access to an account are who they say they are. It requires users to provide additional information to verify their identity. Amplify Auth supports the MFA methods with Time-based-One-Time Passwords (TOTP) as well as text messages (SMS). In this guide we will review how you can set up MFA using TOTP and SMS and the tradeoffs between these methods to help you choose the right set up for your application. We will also review how to set up MFA to remember a device and reduce sign-in friction for your users. +Amplify Auth supports multi-factor authentication (MFA) for user sign-in flows. MFA is an extra layer of security used to make sure that users trying to gain access to an account are who they say they are. It requires users to provide additional information to verify their identity. Amplify Auth supports MFA with time-based one-time passwords (TOTP), text messages (SMS), and email. + +In this guide we will review how you can set up MFA with each of these methods and the discuss tradeoffs between them to help you choose the right setup for your application. We will also review how to set up MFA to remember a device and reduce sign-in friction for your users. ## Configure multi-factor authentication -Use `defineAuth` to enable MFA for your app. The example below is setting up MFA with TOTP but not SMS as you can see that the phone number is not a required attribute. If you are using SMS, then the `PhoneNumber` attribute must be `true`. +Use `defineAuth` to enable MFA for your app. The example below is setting up MFA with TOTP but not SMS as you can see that the phone number is not a required attribute. +- If you plan to use SMS for MFA, then the `phoneNumber` attribute must be marked as required in your `userAttributes`. Note that if you have `loginWith.phone` as `true` this attribute will automatically be marked as required. +- If you plan to use email for MFA, then the `email` attribute must also be `true` must be marked as required in your `userAttributes`. Note that if you have `loginWith.email` as `true` this attribute will automatically be marked as required. ```ts title="amplify/auth/resource.ts" import { defineAuth } from '@aws-amplify/backend'; @@ -44,31 +48,208 @@ export const auth = defineAuth({ // highlight-start multifactor: { mode: 'OPTIONAL', - totp: true - } + totp: true, + }, // highlight-end + userAttributes: { + phoneNumber: { + required: true + } + } }); ``` -When multi-factor authentication (MFA) is REQUIRED with SMS in your backend auth resource, you will need to pass the phone number during sign-up API call. If you are using the `email` or `username` as the primary sign-in mechanism, you will need to pass the `phone_number` attribute as a user attribute. This will change depending on if you enable SMS, TOTP, or both. Visit the [multi-factor authentication documentation](/[platform]/build-a-backend/auth/concepts/multi-factor-authentication/) to learn more about enabling MFA on your backend auth resource. + +**Note:** Email-based MFA is currently not supported with `defineAuth`. We are working towards supporting this feature. For more information, visit the [feature request in GitHub](https://github.com/aws-amplify/amplify-backend/issues/2159). + +To take advantage of this feature with an Amplify generated backend, the underlying CDK construct can be extended manually. See [overriding Cognito User Pool multi-factor authentication options](/[platform]/build-a-backend/auth/modify-resources-with-cdk/#override-cognito-userpool-multi-factor-authentication-options) for more information. + + +When MFA is `REQUIRED` with SMS in your backend auth resource, you will need to pass the phone number during sign-up API call. If you are using the `email` or `username` as the primary sign-in mechanism, you will need to pass the `phone_number` attribute as a user attribute. + +Similarly, when MFA is `REQUIRED` with email as your delivery mechanism, you will need to pass an email address during the sign-up API call. If you are using `phoneNumber` or `username` as the primary sign-in mechanism, you will need to pass the `email` attribute as a user attribute. + +This configuration may change depending on the combination of MFA methods enabled in your user pool. ### Understand your MFA options When enabling MFA you will have two key decisions to make: -- **MFA enforcement:** As part of this setup you will determine how MFA is enforced. If you require MFA by setting MFA login to "ON", all your users will need to complete MFA to sign in. If you keep it "Optional", your users will have the choice whether to enable MFA or not for their account. -- **MFA methods:** You will also specify which MFA method you are using - TOTP (Time-based One-time Password), SMS (text message), or both. We recommend that you use TOTP-based MFA as it is more secure and you can reserve SMS for account recovery. +- **MFA enforcement:** As part of this setup you will determine how MFA is enforced. If you require MFA by setting MFA mode to `REQUIRED`, all your users will need to complete MFA to sign in. If you keep it `OPTIONAL`, your users will have the choice whether to enable MFA or not for their account. +- **MFA methods:** You will also specify which MFA method you are using: TOTP (Time-based One-time Password), SMS (text message), email, or any combination thereof. We recommend that you use TOTP-based MFA as it is more secure and you can reserve SMS or email for account recovery. - + -| | Time-based One-time Password (TOTP) | Short Message Service (SMS) | -| --- | --- | --- | -| **Description** | Generates a short-lived numeric code for user authentication that includes a shared secret key and current time using an authenticator app. | Generates a one-time code shared via text message that is entered with other credentials for user authentication. | -| **Benefits** | More secure than SMS since the code is generated locally and not transmitted over a network. TOTP also works without cell service as long as the TOTP app is installed. | Easy to set up with a user-provided phone number and is familiar to users as a common authentication method. | -| **Constraints** | Requires an app to generate codes and adds to the initial setup of an account. Codes also expire quickly and must be used promptly after it is generated. | SMS requires cell service and can include an additional cost for the user. Although rare, SMS messages can also be intercepted. | +| | Time-based One-time Password (TOTP) | Short Message Service (SMS) | Email | +| --- | --- | --- | --- | +| **Description** | Generates a short-lived numeric code for user authentication that includes a shared secret key and current time using an authenticator app. | Generates a one-time code shared via text message that is entered with other credentials for user authentication. | Generates a one-time code sent to the user's registered email address. The user must access the email and enter the code to complete the authentication process. | +| **Benefits** | More secure than SMS since the code is generated locally and not transmitted over a network. TOTP also works without cell service as long as the TOTP app is installed. | Easy to set up with a user-provided phone number and is familiar to users as a common authentication method. | Email is a widely used and familiar communication channel that requires no additional hardware or software requirements on the user's end. | +| **Constraints** | Requires an app to generate codes and adds to the initial setup of an account. Codes also expire quickly and must be used promptly after it is generated. | SMS requires cell service and can include an additional cost for the user. Although rare, SMS messages can also be intercepted. | Depends on the availability and reliability of email services. Although rare, emails can be intercepted or accounts can become compromised. | + + +If multiple MFA methods are enabled for the user, and none are set as preferred, the `signIn` API will return `CONTINUE_SIGN_IN_WITH_MFA_SELECTION` as the next step in the auth flow. During this scenario, the user should be prompted to select the MFA method they want to use to sign in and their preference should be passed to `confirmSignIn`. + + + + +```ts +import { confirmSignIn, type SignInOutput } from 'aws-amplify/auth'; + +function handleSignInNextSteps(output: SignInOutput) { + const { nextStep } = output; + switch (nextStep.signInStep) { + // ... + case 'CONTINUE_SIGN_IN_WITH_MFA_SELECTION': + const allowedMFATypes = nextStep.allowedMFATypes; + const mfaType = promptUserForMFAType(allowedMFATypes); + case 'CONFIRM_SIGN_IN_WITH_SMS_CODE': + // prompt user to enter otp code delivered via SMS + break; + case 'CONFIRM_SIGN_IN_WITH_TOTP_CODE': + // prompt user to enter otp code from their authenticator app + break; + case 'CONFIRM_SIGN_IN_WITH_EMAIL_CODE': + // prompt user to enter otp code delivered via EMAIL + break; + // ... + } +} + +type MfaType = 'SMS' | 'TOTP' | 'EMAIL'; + +function promptUserForMFAType(allowedMFATypes?: MfaType[]): MfaType { + // Prompt user to select MFA type +} + +async function handleMFASelection(mfaType: MfaType) { + try { + const output = await confirmSignIn({ + challengeResponse: mfaType, + }); + handleSignInNextSteps(output); + } catch (error) { + console.log(error); + } +} +``` + + + +```kotlin +fun signIn(username: String, password: String) { + val result: AuthSignInResult + try { + result = Amplify.Auth.signIn(username, password) + } catch (e: AuthException) { + Log.e("MFASelection", "Failed to sign in", e) + } + handleNextSignInStep(username, result.nextStep) +} + +fun handleNextSignInStep( + username: String, + nextStep: AuthNextSignInStep +) { + when (nextStep.signInStep) { + AuthSignInStep.CONTINUE_SIGN_IN_WITH_MFA_SELECTION -> { + // User has multiple MFA methods and none are preferred + promptUserForMfaType(nextStep.allowedMFATypes) + } + else -> { + // Handle other SignInSteps + } + } +} + +fun promptUserForMfaType(mfaTypes: Set?) { + // Prompt user to select one of the passed-in MFA Types + // Then invoke Amplify.Auth.confirmSignIn(selectedMfaType.challengeResponse) +} +``` + + + +If multiple MFA methods are enabled for the user, and none are set as preferred, the `signIn` API will return `continueSignInWithMFASelection` as the next step in the auth flow. During this scenario, the user should be prompted to select the MFA method they want to use to sign in and their preference should be passed to `confirmSignIn`. + + + + +```dart +Future _handleSignInResult(SignInResult result) async { + switch (result.nextStep.signInStep) { + // ··· + case AuthSignInStep.continueSignInWithMfaSelection: + final allowedMfaTypes = result.nextStep.allowedMfaTypes!; + final selection = await _promptUserPreference(allowedMfaTypes); + return _handleMfaSelection(selection); + // ··· + } +} + +Future _promptUserPreference(Set allowedTypes) async { + // ··· +} + +Future _handleMfaSelection(MfaType selection) async { + try { + final result = await Amplify.Auth.confirmSignIn( + confirmationValue: selection.confirmationValue, + ); + return _handleSignInResult(result); + } on AuthException catch (e) { + safePrint('Error sending MFA selection: ${e.message}'); + } +} +``` + + + + +```swift +func signIn(username: String, password: String) async { + do { + let signInResult = try await Amplify.Auth.signIn(username: username, password: password) + switch signInResult.nextStep { + + case .continueSignInWithMFASelection(let allowedMFATypes): + print("Received next step as continue sign in by selecting MFA type") + print("Allowed MFA types \(allowedMFATypes)") + + // Prompt the user to select the MFA type they want to use + // Then invoke `confirmSignIn` api with the MFA type + + default: + + // Use has successfully signed in to the app + print("Step: \(signInResult.nextStep)") + } + } catch let error as AuthError{ + print ("Sign in failed \(error)") + } catch { + print("Unexpected error: \(error)") + } +} + +func confirmSignInWithTOTPAsMFASelection() async { + do { + let signInResult = try await Amplify.Auth.confirmSignIn( + challengeResponse: MFAType.totp.challengeResponse) + + if case .confirmSignInWithTOTPCode = signInResult.nextStep { + print("Received next step as confirm sign in with TOTP") + } + + } catch { + print("Confirm sign in failed \(error)") + } +} +``` + + + ## Multi-factor authentication with SMS @@ -674,72 +855,504 @@ If a user loses access to their TOTP device, they will need to contact an admini In a scenario where MFA is marked as "Required" in the Cognito User Pool and another MFA method is not set up, the administrator would need to first initiate an [`AdminUpdateUserAttributes`](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminUpdateUserAttributes.html) call and update the user's phone number attribute. Once this is complete, the administrator can continue changing the MFA preference to SMS as suggested above. -## Set up a user's preferred MFA method +## Multi-factor authentication with EMAIL + + +**Note:** Email-based MFA is currently not supported in the [Authenticator component](https://ui.docs.amplify.aws/react/connected-components/authenticator). We are working towards supporting this feature. For more information, visit the [feature request in GitHub](https://github.com/aws-amplify/amplify-ui/issues/5983). -### Fetch the current user's MFA preferences + + -Invoke the following API to get the current MFA preference and enabled MFA types, if any, for the current user. + + - +If you are using the [Authenticator component](https://ui.docs.amplify.aws/swift/connected-components/authenticator) with Amplify, this feature works without any additional code. The guide below is for writing your own implementation. + + + + + + + +If you are using the [Authenticator component](https://ui.docs.amplify.aws/flutter/connected-components/authenticator) with Amplify, this feature works without any additional code. The guide below is for writing your own implementation. + + + + + + + +If you are using the [Authenticator component](https://ui.docs.amplify.aws/android/connected-components/authenticator) with Amplify, this feature works without any additional code. The guide below is for writing your own implementation. + + + + +Once you have setup email as your second layer of authentication with MFA as shown above, your users will get an authentication code via email to complete sign-in after they sign in with their username and password. + + + +In order to send email authentication codes, the following prerequisites must be met: +- Cognito must be configured to send emails using [Amazon Simple Email Service (Amazon SES)](/[platform]/build-a-backend/auth/moving-to-production/#email). +- [Advanced Security Features (ASF)](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pool-settings-advanced-security.html) must be enabled in your user pool. +- If account recovery is enabled in Cognito, the delivery method for recovery messages cannot be set to `Email only` + + + + +Additional pricing applies for ASF. [Learn more about Amazon Cognito pricing](https://aws.amazon.com/cognito/pricing/) + + +### Enable EMAIL MFA during sign-up + +You will need to pass `email` as a user attribute to enable email MFA for your users during sign-up. However, if the primary sign-in mechanism for your Cognito resource is already `email` (without enabling `username`), then you do not need to pass it as an attribute. + + ```ts -import { fetchMFAPreference } from 'aws-amplify/auth'; +import { signUp } from 'aws-amplify/auth'; -const { enabled, preferred } = await fetchMFAPreference(); +await signUp({ + username: "+15555555555", + password: "hunter2", + options: { + userAttributes: { + email: "hello@mycompany.com", + }, + }, +}); +``` + + + + + + + +```java +ArrayList attributes = new ArrayList<>(); +attributes.add(new AuthUserAttribute(AuthUserAttributeKey.email(), "my@email.com")); +attributes.add(new AuthUserAttribute(AuthUserAttributeKey.phoneNumber(), "+15551234567")); + +Amplify.Auth.signUp( + "username", + "Password123", + AuthSignUpOptions.builder().userAttributes(attributes).build(), + result -> Log.i("AuthQuickstart", result.toString()), + error -> Log.e("AuthQuickstart", error.toString()) +); +``` + + + + +```kotlin +val attrs = mapOf( + AuthUserAttributeKey.email() to "my@email.com", + AuthUserAttributeKey.phoneNumber() to "+15551234567" +) +val options = AuthSignUpOptions.builder() + .userAttributes(attrs.map { AuthUserAttribute(it.key, it.value) }) + .build() +Amplify.Auth.signUp("username", "Password123", options, + { Log.i("AuthQuickstart", "Sign up result = $it") }, + { Log.e("AuthQuickstart", "Sign up failed", it) } +) ``` + + + + +```kotlin +val attrs = mapOf( + AuthUserAttributeKey.email() to "my@email.com", + AuthUserAttributeKey.phoneNumber() to "+15551234567" +) +val options = AuthSignUpOptions.builder() + .userAttributes(attrs.map { AuthUserAttribute(it.key, it.value) }) + .build() +try { + val result = Amplify.Auth.signUp("username", "Password123", options) + Log.i("AuthQuickstart", "Sign up OK: $result") +} catch (error: AuthException) { + Log.e("AuthQuickstart", "Sign up failed", error) +} +``` + + + + +```java +ArrayList attributes = new ArrayList<>(); +attributes.add(new AuthUserAttribute(AuthUserAttributeKey.email(), "my@email.com")); +attributes.add(new AuthUserAttribute(AuthUserAttributeKey.phoneNumber(), "+15551234567")); + +RxAmplify.Auth.signUp( + "username", + "Password123", + AuthSignUpOptions.builder().userAttributes(attributes).build()) + .subscribe( + result -> Log.i("AuthQuickstart", result.toString()), + error -> Log.e("AuthQuickstart", error.toString()) + ); +``` + + + + ```dart -Future getCurrentMfaPreference() async { - final cognitoPlugin = Amplify.Auth.getPlugin(AmplifyAuthCognito.pluginKey); - - final currentPreference = await cognitoPlugin.fetchMfaPreference(); - safePrint('Enabled MFA types for user: ${currentPreference.enabled}'); - safePrint('Preferred MFA type for user: ${currentPreference.preferred}'); +Future signUpWithEmailVerification( + String username, + String password, +) async { + await Amplify.Auth.signUp( + username: username, + password: password, + options: SignUpOptions( + userAttributes: { + AuthUserAttributeKey.email: 'test@example.com', + // ... if required + AuthUserAttributeKey.phoneNumber: '+18885551234', + }, + ), + ); } ``` ```swift -func getMFAPreferences() async throws { - let authCognitoPlugin = try Amplify.Auth.getPlugin( - for: "awsCognitoAuthPlugin") as? AWSCognitoAuthPlugin +func signUp(username: String, password: String, email: String, phonenumber: String) async { + do { + let signUpResult = try await Amplify.Auth.signUp( + username: username, + password: password, + options: .init(userAttributes: [ + AuthUserAttribute(.email, value: email), + AuthUserAttribute(.phoneNumber, value: phonenumber) + ]) + ) + if case let .confirmUser(deliveryDetails, _, userId) = signUpResult.nextStep { + print("Delivery details \(String(describing: deliveryDetails)) for userId: \(String(describing: userId)))") + } else { + print("SignUp Complete") + } + } catch let error as AuthError { + print("An error occurred while registering a user \(error)") + } catch { + print("Unexpected error: \(error)") + } +} +``` + - let result = try await authCognitoPlugin?.fetchMFAPreference() +By default, you have to verify a user account after they sign up using the `confirmSignUp` API. Following the initial `signUp` request, a one-time passcode will be sent to the user's phone number or email, depending on your Amazon Cognito configuration. - print("Enabled MFA types: \(result?.enabled)") - print("Preferred MFA type: \(result?.preferred)") + +```ts +import { confirmSignUp } from 'aws-amplify/auth'; + +await confirmSignUp({ + username: "+15555555555", + confirmationCode: "123456", +}) +``` + + + + + + + +```java + try { + Amplify.Auth.confirmSignUp( + "username", + "confirmation code", + result -> Log.i("AuthQuickstart", "Confirm signUp result completed: " + result.isSignUpComplete()), + error -> Log.e("AuthQuickstart", "An error occurred while confirming sign up: " + error) + ); +} catch (Exception error) { + Log.e("AuthQuickstart", "unexpected error: " + error); +} +``` + + + + +```kotlin + try { + Amplify.Auth.confirmSignUp( + "username", + "confirmation code", + { result -> + Log.i("AuthQuickstart", "Confirm signUp result completed: ${result.isSignUpComplete}") + } + ) { error -> + Log.e("AuthQuickstart", "An error occurred while confirming sign up: $error") + } +} catch (error: Exception) { + Log.e("AuthQuickstart", "unexpected error: $error") +} +``` + + + + +```kotlin +try { + val result = Amplify.Auth.confirmSignUp( + "username", + "confirmation code" + ) + Log.i("AuthQuickstart", "Confirm signUp result completed: ${result.isSignUpComplete}") +} catch (error: Exception) { + Log.e("AuthQuickstart", "unexpected error: $error") } ``` + + + + +```java +RxAmplify.Auth.confirmSignUp( + "username", + "confirmation code").subscribe( + result -> Log.i("AuthQuickstart", "Confirm signUp result completed: " + result.isSignUpComplete()), + error -> Log.e("AuthQuickstart", "An error occurred while confirming sign up: " + error) +); +``` + + + -### Update the current user's MFA preferences + +```dart +Future confirmSignUpEmailVerification( + String username, + String otpCode, +) async { + await Amplify.Auth.confirmSignUp( + username: username, + confirmationCode: otpCode, + ); +} +``` + -Invoke the following API to update the MFA preference for the current user. - + +```swift +func confirmSignUp(for username: String, with confirmationCode: String) async { + do { + let confirmSignUpResult = try await Amplify.Auth.confirmSignUp( + for: username, + confirmationCode: confirmationCode + ) + print("Confirm sign up result completed: \(confirmSignUpResult.isSignUpComplete)") + } catch let error as AuthError { + print("An error occurred while confirming sign up \(error)") + } catch { + print("Unexpected error: \(error)") + } +} +``` + -Only one MFA method can be marked as preferred at a time. If the user has multiple MFA methods enabled and tries to mark more than one MFA method as preferred, the API will throw an error. +### Manage EMAIL MFA during sign-in - +After a user signs in, if they have MFA enabled for their account, a challenge will be issued that requires calling the `confirmSignIn` API with the user provided confirmation code sent to their email address. - +If MFA is **ON** or enabled for the user, you must call `confirmSignIn` with the OTP sent to their email address. + + +```ts +import { confirmSignIn } from 'aws-amplify/auth'; + +await confirmSignIn({ + challengeResponse: "123456" +}); +``` + + + + + + +```java +try { + Amplify.Auth.confirmSignIn( + "confirmation code", + result -> { + if (result.isSignedIn()) { + Log.i("AuthQuickstart", "Confirm signIn succeeded"); + } else { + Log.i("AuthQuickstart", "Confirm sign in not complete. There might be additional steps: " + result.getNextStep()); + // Switch on the next step to take appropriate actions. + // If `result.isSignedIn` is true, the next step + // is 'done', and the user is now signed in. + } + }, + error -> Log.e("AuthQuickstart", "Confirm sign in failed: " + error) + ); +} catch (Exception error) { + Log.e("AuthQuickstart", "Unexpected error: " + error); +} +``` + + + + +```kotlin +try { + Amplify.Auth.confirmSignIn( + "confirmation code", + { result -> + if (result.isSignedIn) { + Log.i("AuthQuickstart","Confirm signIn succeeded") + } else { + Log.i("AuthQuickstart", "Confirm sign in not complete. There might be additional steps: ${result.nextStep}") + // Switch on the next step to take appropriate actions. + // If `result.isSignedIn` is true, the next step + // is 'done', and the user is now signed in. + } + } + ) { error -> Log.e("AuthQuickstart", "Confirm sign in failed: $error")} +} catch (error: Exception) { + Log.e("AuthQuickstart", "Unexpected error: $error") +} +``` + + + + +```kotlin +try { + val result = Amplify.Auth.confirmSignIn( + "confirmation code" + ) + if (result.isSignedIn) { + Log.i("AuthQuickstart", "Confirm signIn succeeded") + } else { + Log.i("AuthQuickstart", "Confirm sign in not complete. There might be additional steps: ${result.nextStep}" + ) + // Switch on the next step to take appropriate actions. + // If `result.isSignedIn` is true, the next step + // is 'done', and the user is now signed in. + } +} catch (error: Exception) { + Log.e("AuthQuickstart", "Unexpected error: $error") +} +``` + + + + +```java + +RxAmplify.Auth.confirmSignIn( + "confirmation code").subscribe( + result -> { + if (result.isSignedIn()) { + Log.i("AuthQuickstart", "Confirm signIn succeeded"); + } else { + Log.i("AuthQuickstart", "Confirm sign in not complete. There might be additional steps: " + result.getNextStep()); + // Switch on the next step to take appropriate actions. + // If `result.isSignedIn` is true, the next step + // is 'done', and the user is now signed in. + } + }, + error -> Log.e("AuthQuickstart", "Confirm sign in failed: " + error) + ); +``` + + + + + + +```dart +Future confirmSignInEmailVerification(String otpCode) async { + await Amplify.Auth.confirmSignIn( + confirmationValue: otpCode, + ); +} +``` + + + +```swift +func confirmSignIn() async { + do { + let signInResult = try await Amplify.Auth.confirmSignIn( + challengeResponse: "") + print("Confirm sign in succeeded. Next step: \(signInResult.nextStep)") + } catch let error as AuthError { + print("Confirm sign in failed \(error)") + } catch { + print("Unexpected error: \(error)") + } +} +``` + + +After a user has been signed in, call `updateMFAPreference` to record the MFA type as enabled for the user and optionally set it as preferred so that subsequent logins default to using this MFA type. + + ```ts import { updateMFAPreference } from 'aws-amplify/auth'; -await updateMFAPreference({ sms: 'ENABLED', totp: 'PREFERRED' }); +await updateMFAPreference({ email: 'PREFERRED' }); ``` + + + + +```java +if (Amplify.Auth.getPlugin("awsCognitoAuthPlugin") instanceof AWSCognitoAuthPlugin) { + AWSCognitoAuthPlugin plugin = (AWSCognitoAuthPlugin) Amplify.Auth.getPlugin("awsCognitoAuthPlugin"); + plugin.updateMFAPreference( + MFAPreference.DISABLED, // SMS Preference + MFAPreference.DISABLED, // TOTP Preference + MFAPreference.PREFERRED, // Email Preference + () -> Log.i("AuthQuickstart", "MFA preference updated successfully"), + e -> Log.e("AuthQuickstart", "Failed to update MFA preference.", e) + ); + } +``` + + + + +```kotlin +if (Amplify.Auth.getPlugin("awsCognitoAuthPlugin") is AWSCognitoAuthPlugin) { + val plugin = Amplify.Auth.getPlugin("awsCognitoAuthPlugin") as? AWSCognitoAuthPlugin + plugin?.updateMFAPreference( + MFAPreference.DISABLED, // SMS Preference + MFAPreference.DISABLED, // TOTP Preference + MFAPreference.PREFERRED, // Email Preference + { Log.i("AuthQuickstart", "MFA preference updated successfully" ) }, + { e: AuthException? -> Log.e("AuthQuickstart", "Failed to update MFA preference", e) } + ) +} +``` + + + + + + ```dart Future updateMfaPreferences() async { final cognitoPlugin = Amplify.Auth.getPlugin(AmplifyAuthCognito.pluginKey); await cognitoPlugin.updateMfaPreference( - sms: MfaPreference.enabled, - totp: MfaPreference.preferred, + email: MfaPreference.enabled, // or .preferred ); } ``` @@ -751,132 +1364,167 @@ func updateMFAPreferences() async throws { let authCognitoPlugin = try Amplify.Auth.getPlugin( for: "awsCognitoAuthPlugin") as? AWSCognitoAuthPlugin - let smsMfaPreference: MFAPreference = .enabled - let totpMfaPreference: MFAPreference = .preferred + let emailMfaPreference: MFAPreference = .preferred try await authCognitoPlugin?.updateMFAPreference( - sms: smsMfaPreference, - totp: totpMfaPreference) + email: emailMfaPreference) } ``` - -If multiple MFA methods are enabled for the user, the `signIn` API will return `CONTINUE_SIGN_IN_WITH_MFA_SELECTION` as the next step in the auth flow. During this scenario, the user should be prompted to select the MFA method they want to use to sign in and their preference should be passed to `confirmSignIn`. +## Set up a user's preferred MFA method + +Depending on your user pool configuration, it's possible that multiple MFA options may be available to a given user. In order to avoid requiring your users to select an MFA method each time they sign-in to your application, Amplify provides two utility APIs to manage an individual user's MFA preferences. + +### Fetch the current user's MFA preferences +Invoke the following API to get the current MFA preference and enabled MFA types, if any, for the current user. + + ```ts -import { confirmSignIn, SignInOutput } from 'aws-amplify/auth'; +import { fetchMFAPreference } from 'aws-amplify/auth'; -function handleSignInNextSteps(output: SignInOutput) { - const { nextStep } = output; - switch (nextStep.signInStep) { - // ... - case 'CONTINUE_SIGN_IN_WITH_MFA_SELECTION': - const allowedMFATypes = nextStep.allowedMFATypes; - const mfaType = promptUserForMFAType(allowedMFATypes); - case 'CONFIRM_SIGN_IN_WITH_SMS_CODE': - // display user to enter otp code; - break; - case 'CONFIRM_SIGN_IN_WITH_TOTP_CODE': - // display user to enter otp code; - break; - // ... - } -} +const { enabled, preferred } = await fetchMFAPreference(); +``` + -function promptUserForMFAType( - allowedMFATypes?: ('SMS' | 'TOTP')[] -): 'SMS' | 'TOTP' { - // Prompt user to select MFA type + + + + +```java +if (Amplify.Auth.getPlugin("awsCognitoAuthPlugin") instanceof AWSCognitoAuthPlugin) { + AWSCognitoAuthPlugin plugin = (AWSCognitoAuthPlugin) Amplify.Auth.getPlugin("awsCognitoAuthPlugin"); + plugin.fetchMFAPreference( + preference -> Log.i( + "AuthQuickStart", + "Fetched MFA preference, enabled: " + preference.getEnabled() + ", preferred: " + preference.getPreferred() + ), + e -> Log.e("AuthQuickStart", "Failed to fetch MFA preference.", e) + ); } +``` -async function handleMFASelection(mfaType: 'SMS' | 'TOTP') { - try { - const output = await confirmSignIn({ - challengeResponse: mfaType - }); - handleSignInNextSteps(output); - } catch (error) { - console.log(error); - } -} + + + +```kotlin +val cognitoAuthPlugin = Amplify.Auth.getPlugin("awsCognitoAuthPlugin") as? AWSCognitoAuthPlugin +cognitoAuthPlugin?.fetchMFAPreference( + { Log.d("AuthQuickStart", "Fetched MFA preference, enabled: ${it.enabled}, preferred: ${it.preferred}") }, + { Log.e("AuthQuickStart", "Failed to fetch MFA preference.", it) } +) ``` - - -If multiple MFA methods are enabled for the user, the `signIn` API will return `continueSignInWithMFASelection` as the next step in the auth flow. During this scenario, the user should be prompted to select the MFA method they want to use to sign in and their preference should be passed to `confirmSignIn`. + + - ```dart -Future _handleSignInResult(SignInResult result) async { - switch (result.nextStep.signInStep) { - // ··· - case AuthSignInStep.continueSignInWithMfaSelection: - final allowedMfaTypes = result.nextStep.allowedMfaTypes!; - final selection = await _promptUserPreference(allowedMfaTypes); - return _handleMfaSelection(selection); - // ··· - } +Future getCurrentMfaPreference() async { + final cognitoPlugin = Amplify.Auth.getPlugin(AmplifyAuthCognito.pluginKey); + + final currentPreference = await cognitoPlugin.fetchMfaPreference(); + safePrint('Enabled MFA types for user: ${currentPreference.enabled}'); + safePrint('Preferred MFA type for user: ${currentPreference.preferred}'); } +``` + -Future _promptUserPreference(Set allowedTypes) async { - // ··· + +```swift +func getMFAPreferences() async throws { + let authCognitoPlugin = try Amplify.Auth.getPlugin( + for: "awsCognitoAuthPlugin") as? AWSCognitoAuthPlugin + + let result = try await authCognitoPlugin?.fetchMFAPreference() + + print("Enabled MFA types: \(result?.enabled)") + print("Preferred MFA type: \(result?.preferred)") } +``` + -Future _handleMfaSelection(MfaType selection) async { - try { - final result = await Amplify.Auth.confirmSignIn( - confirmationValue: selection.confirmationValue, +### Update the current user's MFA preferences + +Invoke the following API to update the MFA preference for the current user. + + + +Only one MFA method can be marked as preferred at a time. If the user has multiple MFA methods enabled and tries to mark more than one MFA method as preferred, the API will throw an error. + + + + +```ts +import { updateMFAPreference } from 'aws-amplify/auth'; + +await updateMFAPreference({ sms: 'ENABLED', totp: 'PREFERRED' }); +``` + + + + + + +```java +if (Amplify.Auth.getPlugin("awsCognitoAuthPlugin") instanceof AWSCognitoAuthPlugin) { + AWSCognitoAuthPlugin plugin = (AWSCognitoAuthPlugin) Amplify.Auth.getPlugin("awsCognitoAuthPlugin"); + plugin.updateMFAPreference( + MFAPreference.DISABLED, // SMS Preference + MFAPreference.PREFERRED, // TOTP Preference + null // Email Preference + () -> Log.i( "AuthQuickStart", "Preference updated successfully"), + e -> Log.e("AuthQuickStart", "Failed to update MFA preference.", e) ); - return _handleSignInResult(result); - } on AuthException catch (e) { - safePrint('Error resending code: ${e.message}'); - } } ``` - - + + + +```kotlin +val cognitoAuthPlugin = Amplify.Auth.getPlugin("awsCognitoAuthPlugin") as? AWSCognitoAuthPlugin +cognitoAuthPlugin?.updateMFAPreference( + MFAPreference.DISABLED, // SMS Preference + MFAPreference.PREFERRED, // TOTP Preference + null, // Email Preference + { Log.d("AuthQuickStart", "Preference updated successfully") }, + { Log.e("AuthQuickStart", "Failed to update MFA preference.", it) } +) +``` -```swift -func signIn(username: String, password: String) async { - do { - let signInResult = try await Amplify.Auth.signIn(username: username, password: password) - switch signInResult.nextStep { + - case .continueSignInWithMFASelection(let allowedMFATypes): - print("Received next step as continue sign in by selecting MFA type") - print("Allowed MFA types \(allowedMFATypes)") - - // Prompt the user to select the MFA type they want to use - // Then invoke `confirmSignIn` api with the MFA type - - default: - - // Use has successfully signed in to the app - print("Step: \(signInResult.nextStep)") - } - } catch let error as AuthError{ - print ("Sign in failed \(error)") - } catch { - print("Unexpected error: \(error)") - } + + + + +```dart +Future updateMfaPreferences() async { + final cognitoPlugin = Amplify.Auth.getPlugin(AmplifyAuthCognito.pluginKey); + + await cognitoPlugin.updateMfaPreference( + sms: MfaPreference.enabled, + totp: MfaPreference.preferred, + ); } +``` + -func confirmSignInWithTOTPAsMFASelection() async { - do { - let signInResult = try await Amplify.Auth.confirmSignIn( - challengeResponse: MFAType.totp.challengeResponse) + +```swift +func updateMFAPreferences() async throws { + let authCognitoPlugin = try Amplify.Auth.getPlugin( + for: "awsCognitoAuthPlugin") as? AWSCognitoAuthPlugin - if case .confirmSignInWithTOTPCode = signInResult.nextStep { - print("Received next step as confirm sign in with TOTP") - } + let smsMfaPreference: MFAPreference = .enabled + let totpMfaPreference: MFAPreference = .preferred - } catch { - print("Confirm sign in failed \(error)") - } + try await authCognitoPlugin?.updateMFAPreference( + sms: smsMfaPreference, + totp: totpMfaPreference) } ``` diff --git a/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/manage-user-sessions/index.mdx b/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/manage-user-sessions/index.mdx index 5cc42d9189e..67cae9f1983 100644 --- a/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/manage-user-sessions/index.mdx +++ b/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/manage-user-sessions/index.mdx @@ -105,7 +105,7 @@ Future fetchAuthSession() async { } ``` -### Retrieving AWS credentials +## Retrieving AWS credentials Sometimes it can be helpful to retrieve the instance of the underlying plugin which has more specific typing. In case of Cognito, calling `fetchAuthSession` on the Cognito plugin returns AWS-specific values such as the identity ID, AWS credentials, and Cognito User Pool tokens. diff --git a/src/pages/[platform]/build-a-backend/auth/multi-step-sign-in/index.mdx b/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/multi-step-sign-in/index.mdx similarity index 63% rename from src/pages/[platform]/build-a-backend/auth/multi-step-sign-in/index.mdx rename to src/pages/[platform]/build-a-backend/auth/connect-your-frontend/multi-step-sign-in/index.mdx index 4a738a3fbde..eee41bf9520 100644 --- a/src/pages/[platform]/build-a-backend/auth/multi-step-sign-in/index.mdx +++ b/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/multi-step-sign-in/index.mdx @@ -4,7 +4,7 @@ export const meta = { title: 'Multi-step sign-in', description: 'Use Amazon Cognito Auth plugin to complete a multi step authentication flow', - platforms: ['android', 'swift', 'flutter'] + platforms: ['android', 'swift', 'flutter', 'react', 'nextjs', 'javascript', 'react-native', 'vue', 'angular'] }; export const getStaticPaths = async () => { @@ -20,6 +20,532 @@ export function getStaticProps(context) { }; } + +After a user has finished signup, they can proceed to sign in. Amplify Auth signin flows can be multi-step processes. The required steps are determined by the configuration provided when you define your auth resources. See the [multi-factor authentication](/[platform]/build-a-backend/auth/concepts/multi-factor-authentication/) page for more information. + +Depending on the configuration, you may need to call various APIs to finish authenticating a user's signin attempt. To identify the next step in a signin flow, inspect the `nextStep` parameter of the signin result. + +```typescript +import { + confirmSignIn, + confirmSignUp, + resetPassword, + signIn, +} from 'aws-amplify/auth'; + +const { nextStep } = await signIn({ + username: 'hello@mycompany.com', + password: 'hunter2', +}); + +if ( + nextStep.signInStep === 'CONFIRM_SIGN_IN_WITH_SMS_CODE' || + nextStep.signInStep === 'CONFIRM_SIGN_IN_WITH_EMAIL_CODE' || + nextStep.signInStep === 'CONFIRM_SIGN_IN_WITH_TOTP_CODE' +) { + // collect OTP from user + await confirmSignIn({ + challengeResponse: '123456', + }); +} + +if (nextStep.signInStep === 'CONTINUE_SIGN_IN_WITH_MFA_SELECTION') { + // present nextStep.allowedMFATypes to user + // collect user selection + await confirmSignIn({ + challengeResponse: 'EMAIL', // 'EMAIL', 'SMS', or 'TOTP' + }); +} + +if (nextStep.signInStep === 'CONTINUE_SIGN_IN_WITH_MFA_SETUP_SELECTION') { + // present nextStep.allowedMFATypes to user + // collect user selection + await confirmSignIn({ + challengeResponse: 'EMAIL', // 'EMAIL' or 'TOTP' + }); +} + +if (nextStep.signInStep === 'CONTINUE_SIGN_IN_WITH_EMAIL_SETUP') { + // collect email address from user + await confirmSignIn({ + challengeResponse: 'hello@mycompany.com', + }); +} + +if (nextStep.signInStep === 'CONTINUE_SIGN_IN_WITH_TOTP_SETUP') { + // present nextStep.totpSetupDetails.getSetupUri() to user + // collect OTP from user + await confirmSignIn({ + challengeResponse: '123456', + }); +} + +if (nextStep.signInStep === 'CONFIRM_SIGN_IN_WITH_CUSTOM_CHALLENGE') { + // collect custom challenge answer from user + await confirmSignIn({ + challengeResponse: 'custom-challenge-answer', + }); +} + +if (nextStep.signInStep === 'CONFIRM_SIGN_IN_WITH_NEW_PASSWORD_REQUIRED') { + // collect new password from user + await confirmSignIn({ + challengeResponse: 'new-password', + }); +} + +if (nextStep.signInStep === 'RESET_PASSWORD') { + // initiate reset password flow + await resetPassword({ + username: 'username', + }); +} + +if (nextStep.signInStep === 'CONFIRM_SIGN_UP') { + // user was not confirmed during sign up process + // if user has confirmation code, invoke `confirmSignUp` api + // otherwise, invoke `resendSignUpCode` to resend the code + await confirmSignUp({ + username: 'username', + confirmationCode: '123456', + }); +} + +if (nextStep.signInStep === 'DONE') { + // signin complete +} +``` + +## Confirm sign-in with SMS MFA + +If the next step is `CONFIRM_SIGN_IN_WITH_SMS_CODE`, Amplify Auth has sent the user a random code over SMS and is waiting for the user to verify that code. To handle this step, your app's UI must prompt the user to enter the code. After the user enters the code, pass the value to the `confirmSignIn` API. + + + +The result includes an `AuthCodeDeliveryDetails` member. It includes additional information about the code delivery, such as the partial phone number of the SMS recipient, which can be used to prompt the user on where to look for the code. + + + +```ts +import { type SignInOutput, confirmSignIn } from '@aws-amplify/auth'; + +async function handleSignInResult(result: SignInOutput) { + switch (result.nextStep.signInStep) { + case 'CONFIRM_SIGN_IN_WITH_SMS_CODE': { + const { codeDeliveryDetails } = result.nextStep; + // OTP has been delivered to user via SMS + // Inspect codeDeliveryDetails for additional delivery information + console.log( + `A confirmation code has been sent to ${codeDeliveryDetails?.destination}`, + ); + console.log( + `Please check your ${codeDeliveryDetails?.deliveryMedium} for the code.`, + ); + break; + } + } +} + +async function confirmMfaCode(mfaCode: string) { + const result = await confirmSignIn({ challengeResponse: mfaCode }); + + return handleSignInResult(result); +} + +``` + +## Confirm sign-in with TOTP MFA + +If the next step is `CONFIRM_SIGN_IN_WITH_TOTP_CODE`, you should prompt the user to enter the TOTP code from their associated authenticator app during set up. The code is a six-digit number that changes every 30 seconds. The user must enter the code before the 30-second window expires. + +After the user enters the code, your implementation must pass the value to Amplify Auth `confirmSignIn` API. + + +```ts +import { type SignInOutput, confirmSignIn } from '@aws-amplify/auth'; + +async function handleSignInResult(result: SignInOutput) { + switch (result.nextStep.signInStep) { + case 'CONFIRM_SIGN_IN_WITH_TOTP_CODE': { + // Prompt user to open their authenticator app to retrieve the code + console.log( + `Enter a one-time code from your registered authenticator app`, + ); + break; + } + } +} +// Then, pass the TOTP code to `confirmSignIn` +async function confirmTotpCode(totpCode: string) { + const result = await confirmSignIn({ challengeResponse: totpCode }); + + return handleSignInResult(result); +} + +``` + +## Confirm sign-in with Email MFA + +If the next step is `CONFIRM_SIGN_IN_WITH_EMAIL_CODE`, Amplify Auth has sent the user a random code to their email address and is waiting for the user to verify that code. To handle this step, your app's UI must prompt the user to enter the code. After the user enters the code, pass the value to the `confirmSignIn` API. + + + +The result includes an `AuthCodeDeliveryDetails` member. It includes additional information about the code delivery, such as the partial email address of the recipient, which can be used to prompt the user on where to look for the code. + + + +```ts +import { type SignInOutput, confirmSignIn } from '@aws-amplify/auth'; + +async function handleSignInResult(result: SignInOutput) { + switch (result.nextStep.signInStep) { + case 'CONFIRM_SIGN_IN_WITH_EMAIL_CODE': { + const { codeDeliveryDetails } = result.nextStep; + // OTP has been delivered to user via Email + // Inspect codeDeliveryDetails for additional delivery information + console.log( + `A confirmation code has been sent to ${codeDeliveryDetails?.destination}`, + ); + console.log( + `Please check your ${codeDeliveryDetails?.deliveryMedium} for the code.`, + ); + break; + } + } +} + +async function confirmMfaCode(mfaCode: string) { + const result = await confirmSignIn({ challengeResponse: mfaCode }); + + return handleSignInResult(result); +} + +``` + + +## Continue sign-in with MFA Selection + +If the next step is `CONTINUE_SIGN_IN_WITH_MFA_SELECTION`, the user must select the MFA method to use. Amplify Auth currently supports SMS, TOTP, and EMAIL as MFA methods. After the user selects an MFA method, your implementation must pass the selected MFA method to Amplify Auth using `confirmSignIn` API. + +The MFA types which are currently supported by Amplify Auth are: + +- `SMS` +- `TOTP` +- `EMAIL` + +Once Amplify receives the users selection, you can expect to handle a follow up `nextStep` corresponding with the selected MFA type for setup: +- If `SMS` is selected, `CONFIRM_SIGN_IN_WITH_SMS_CODE` will be the next step. +- If `TOTP` is selected, `CONFIRM_SIGN_IN_WITH_TOTP_CODE` will be the next step. +- If `EMAIL` is selected, `CONFIRM_SIGN_IN_WITH_EMAIL_CODE` will be the next step. + + +```ts +import { type SignInOutput, confirmSignIn } from '@aws-amplify/auth'; + +async function handleSignInResult(result: SignInOutput) { + switch (result.nextStep.signInStep) { + case 'CONTINUE_SIGN_IN_WITH_MFA_SELECTION': { + const { allowedMFATypes } = result.nextStep; + // Present available MFA options to user + // Prompt for selection + console.log(`There are multiple MFA options available for sign in.`); + console.log(`Select an MFA type from the allowedMfaTypes list.`); + break; + } + } +} + +type MfaType = 'SMS' | 'TOTP' | 'EMAIL'; + +async function handleMfaSelection(mfaType: MfaType) { + const result = await confirmSignIn({ challengeResponse: mfaType }); + + return handleSignInResult(result); +} + +``` + +## Continue sign-in with Email Setup + +If the next step is `CONTINUE_SIGN_IN_WITH_EMAIL_SETUP`, then the user must provide an email address to complete the sign in process. Once this value has been collected from the user, call the `confirmSignIn` API to continue. + +```ts +import { type SignInOutput, confirmSignIn } from '@aws-amplify/auth'; + +async function handleSignInResult(result: SignInOutput) { + switch (result.nextStep.signInStep) { + case 'CONTINUE_SIGN_IN_WITH_EMAIL_SETUP': { + // Prompt the user to enter an email address they would like to use for MFA + break; + } + } +} + +// Then, pass the email address to `confirmSignIn` +async function confirmEmail(email: string) { + const result = await confirmSignIn({ challengeResponse: email }); + + return handleSignInResult(result); +} + +``` + +## Continue sign-in with TOTP Setup + +The `CONTINUE_SIGN_IN_WITH_TOTP_SETUP` step signifies that the user must set up TOTP before they can sign in. The step returns an associated value of type TOTPSetupDetails which must be used to configure an authenticator app like Microsoft Authenticator or Google Authenticator. TOTPSetupDetails provides a helper method called getSetupURI which generates a URI that can be used, for example, in a button to open the user's installed authenticator app. For more advanced use cases, TOTPSetupDetails also contains a sharedSecret which can be used to either generate a QR code or be manually entered into an authenticator app. + +Once the authenticator app is set up, the user can generate a TOTP code and provide it to the library to complete the sign in process. + + +```ts +import { type SignInOutput, confirmSignIn } from '@aws-amplify/auth'; + +async function handleSignInResult(result: SignInOutput) { + switch (result.nextStep.signInStep) { + case 'CONTINUE_SIGN_IN_WITH_TOTP_SETUP': { + const { totpSetupDetails } = result.nextStep; + const appName = 'my_app_name'; + const setupUri = totpSetupDetails.getSetupUri(appName); + // Open setupUri with an authenticator app + // Prompt user to enter OTP code to complete setup + break; + } + } +} + +// Then, pass the collected OTP code to `confirmSignIn` +async function confirmTotpCode(totpCode: string) { + const result = await confirmSignIn({ challengeResponse: totpCode }); + + return handleSignInResult(result); +} + +``` + +## Continue sign-in with MFA Setup Selection + +If the next step is `CONTINUE_SIGN_IN_WITH_MFA_SETUP_SELECTION`, then the user must indicate which of the available MFA methods they would like to setup. After the user selects an MFA method to setup, your implementation must pass the selected MFA method to the `confirmSignIn` API. + +The MFA types which are currently supported by Amplify Auth for setup are: + +- `TOTP` +- `EMAIL` + +Once Amplify receives the users selection, you can expect to handle a follow up `nextStep` corresponding with the selected MFA type for setup: +- If `EMAIL` is selected, `CONTINUE_SIGN_IN_WITH_EMAIL_SETUP` will be the next step. +- If `TOTP` is selected, `CONTINUE_SIGN_IN_WITH_TOTP_SETUP` will be the next step. + +```ts +import { type SignInOutput, confirmSignIn } from '@aws-amplify/auth'; + +async function handleSignInResult(result: SignInOutput) { + switch (result.nextStep.signInStep) { + case 'CONTINUE_SIGN_IN_WITH_MFA_SETUP_SELECTION': { + const { allowedMFATypes } = result.nextStep; + // Present available MFA options to user + // Prompt for selection + console.log(`There are multiple MFA options available for setup.`); + console.log(`Select an MFA type from the allowedMFATypes list.`); + break; + } + } +} + +type MfaType = 'SMS' | 'TOTP' | 'EMAIL'; + +async function handleMfaSelection(mfaType: MfaType) { + const result = await confirmSignIn({ challengeResponse: mfaType }); + + return handleSignInResult(result); +} + +``` + +## Confirm sign-in with custom challenge + +If the next step is `CONFIRM_SIGN_IN_WITH_CUSTOM_CHALLENGE`, Amplify Auth is awaiting completion of a custom authentication challenge. The challenge is based on the AWS Lambda trigger you configured as part of a custom sign in flow. + +For example, your custom challenge Lambda may pass a prompt to the frontend which requires the user to enter a secret code. + +```ts +import { type SignInOutput, confirmSignIn } from '@aws-amplify/auth'; + +async function handleSignInResult(result: SignInOutput) { + switch (result.nextStep.signInStep) { + case 'CONFIRM_SIGN_IN_WITH_CUSTOM_CHALLENGE': { + const params = result.nextStep.additionalInfo; + const hint = params.hint!; + // Prompt user to enter custom challenge response + console.log(hint); // `Enter the secret code` + break; + } + } +} + +``` + +To complete this step, you should prompt the user for the custom challenge answer, and pass the answer to the `confirmSignIn` API. + +```ts +async function confirmCustomChallenge(answer: string) { + const result = await confirmSignIn({ challengeResponse: answer }); + + return handleSignInResult(result); +} +``` + + + +**Special Handling on `confirmSignIn`** + +If `failAuthentication=true` is returned by the Lambda, Cognito will invalidate the session of the request. This is represented by a `NotAuthorizedException` and requires restarting the sign-in flow by calling `signIn` again. + + + +## Confirm sign-in with new password + +If the next step is `CONFIRM_SIGN_IN_WITH_NEW_PASSWORD_REQUIRED`, Amplify Auth requires the user choose a new password they proceeding with the sign in. + +Prompt the user for a new password and pass it to the `confirmSignIn` API. + +See the [sign-in](/[platform]/build-a-backend/auth/connect-your-frontend/sign-in/) and [manage-password](/[platform]/build-a-backend/auth/manage-users/manage-passwords/) docs for more information. + +```ts +import { type SignInOutput, confirmSignIn } from '@aws-amplify/auth'; + +async function handleSignInResult(result: SignInOutput) { + switch (result.nextStep.signInStep) { + case 'CONFIRM_SIGN_IN_WITH_NEW_PASSWORD_REQUIRED': { + // Prompt user to enter a new password + console.log(`Please enter a new password.`); + break; + } + } +} + +async function confirmNewPassword(newPassword: string) { + const result = await confirmSignIn({ challengeResponse: newPassword }); + + return handleSignInResult(result); +} + +``` + +## Reset password + +If the next step is `RESET_PASSWORD`, Amplify Auth requires that the user reset their password before proceeding. +Use the `resetPassword` API to guide the user through resetting their password, then call `signIn` to restart the sign-in flow. + +See the [reset password](/[platform]/build-a-backend/auth/manage-users/manage-passwords/) docs for more information. + +```ts +import { + type ResetPasswordOutput, + type SignInOutput, + resetPassword, +} from '@aws-amplify/auth'; + +async function handleSignInResult(result: SignInOutput) { + switch (result.nextStep.signInStep) { + case 'RESET_PASSWORD': { + const resetPasswordResult = await resetPassword({ username }); + // initiate reset password flow + await handleResetPasswordResult(resetPasswordResult); + break; + } + } +} + +async function handleResetPasswordResult( + resetPasswordResult: ResetPasswordOutput, +) { + switch (resetPasswordResult.nextStep.resetPasswordStep) { + case 'CONFIRM_RESET_PASSWORD_WITH_CODE': { + const { codeDeliveryDetails } = resetPasswordResult.nextStep; + console.log( + `A confirmation code has been sent to ${codeDeliveryDetails.destination}.`, + ); + console.log( + `Please check your ${codeDeliveryDetails.destination} for the code.`, + ); + break; + } + case 'DONE': { + console.log(`Successfully reset password.`); + break; + } + } +} + +``` + +## Confirm Signup + +If the next step is `CONFIRM_SIGN_UP`, Amplify Auth requires that the user confirm their email or phone number before proceeding. +Use the `resendSignUpCode` API to send a new sign up code to the registered email or phone number, followed by `confirmSignUp` to complete the sign up. + +See the [sign up](/[platform]/build-a-backend/auth/connect-your-frontend/sign-up/) docs for more information. + + + +The result includes an `AuthCodeDeliveryDetails` member. It includes additional information about the code delivery, such as the partial phone number of the SMS recipient, which can be used to prompt the user on where to look for the code. + + + +```ts +import { + type SignInOutput, + confirmSignUp, + resendSignUpCode, +} from '@aws-amplify/auth'; + +async function handleSignInResult(result: SignInOutput) { + switch (result.nextStep.signInStep) { + case 'CONFIRM_SIGN_UP': { + // Resend sign up code to the registered user + const { destination, deliveryMedium } = await resendSignUpCode({ + username, + }); + console.log(`A confirmation code has been sent to ${destination}.`); + console.log(`Please check your ${deliveryMedium} for the code.`); + break; + } + } +} + +async function handleConfirmSignUp(username: string, confirmationCode: string) { + await confirmSignUp({ + username, + confirmationCode, + }); +} + +``` + +Once the sign up is confirmed, call `signIn` again to restart the sign-in flow. + +## Done + +The sign-in flow is complete when the next step is `DONE`, which means the user is successfully authenticated. +As a convenience, the `SignInResult` also provides the `isSignedIn` property, which will be true if the next step is `DONE`. + +```ts +import { type SignInOutput } from '@aws-amplify/auth'; + +async function handleSignInResult(result: SignInOutput) { + switch (result.nextStep.signInStep) { + case 'DONE': { + // `result.isSignedIn` is `true` + console.log(`Sign in is complete.`); + break; + } + } +} + +``` + + + After a user has finished signup, they can proceed to sign in. Amplify Auth signin flows can be multi step processes. The required steps are determined by the configuration you provided when you define your auth resources like described on [Manage MFA Settings](/[platform]/build-a-backend/auth/concepts/multi-factor-authentication/) page. @@ -63,6 +589,12 @@ Future _handleSignInResult(SignInResult result) async { switch (result.nextStep.signInStep) { case AuthSignInStep.continueSignInWithMfaSelection: // Handle select from MFA methods case + case AuthSignInStep.continueSignInWithMfaSetupSelection: + // Handle select from MFA methods available to setup + case AuthSignInStep.continueSignInWithEmailMfaSetup: + // Handle email setup case + case AuthSignInStep.confirmSignInWithOtpCode: + // Handle email MFA case case AuthSignInStep.continueSignInWithTotpSetup: // Handle TOTP setup case case AuthSignInStep.confirmSignInWithTotpMfaCode: @@ -82,10 +614,9 @@ Future _handleSignInResult(SignInResult result) async { } } ``` -### Confirm signin with SMS MFA +## Confirm sign-in with SMS MFA -If the next step is `confirmSignInWithSmsMfaCode`, Amplify Auth has sent the user a random code over SMS and is waiting for the user to verify that code. -To handle this step, your app's UI must prompt the user to enter the code. After the user enters the code, pass the value to the `confirmSignIn` API. +If the next step is `confirmSignInWithSmsMfaCode`, Amplify Auth has sent the user a random code over SMS and is waiting for the user to verify that code. To handle this step, your app's UI must prompt the user to enter the code. After the user enters the code, pass the value to the `confirmSignIn` API. @@ -125,7 +656,7 @@ Future confirmMfaUser(String mfaCode) async { } ``` -### Confirm signin with TOTP MFA +## Confirm sign-in with TOTP MFA If the next step is `confirmSignInWithTOTPCode`, you should prompt the user to enter the TOTP code from their associated authenticator app during set up. The code is a six-digit number that changes every 30 seconds. The user must enter the code before the 30-second window expires. @@ -156,14 +687,58 @@ Future confirmTotpUser(String totpCode) async { } ``` -### Continue signin with MFA Selection +## Confirm sign-in with Email MFA + +If the next step is `confirmSignInWithOtpCode`, Amplify Auth has sent the user a random code to their email address and is waiting for the user to verify that code. To handle this step, your app's UI must prompt the user to enter the code. After the user enters the code, pass the value to the `confirmSignIn` API. + + -If the next step is `continueSignInWithMFASelection`, the user must select the MFA method to use. Amplify Auth currently only supports SMS and TOTP as MFA methods. After the user selects an MFA method, your implementation must pass the selected MFA method to Amplify Auth using `confirmSignIn` API. +The result includes an `AuthCodeDeliveryDetails` member. It includes additional information about the code delivery, such as the partial email address of +the recipient, which can be used to prompt the user on where to look for the code. + + + +```dart +Future _handleSignInResult(SignInResult result) async { + switch (result.nextStep.signInStep) { + case AuthSignInStep.confirmSignInWithOtpCode: + final codeDeliveryDetails = result.nextStep.codeDeliveryDetails!; + _handleCodeDelivery(codeDeliveryDetails); + // ... + } +} + +void _handleCodeDelivery(AuthCodeDeliveryDetails codeDeliveryDetails) { + safePrint( + 'A confirmation code has been sent to ${codeDeliveryDetails.destination}. ' + 'Please check your ${codeDeliveryDetails.deliveryMedium.name} for the code.', + ); +} +``` + +```dart +Future confirmMfaUser(String mfaCode) async { + try { + final result = await Amplify.Auth.confirmSignIn( + confirmationValue: mfaCode, + ); + return _handleSignInResult(result); + } on AuthException catch (e) { + safePrint('Error confirming MFA code: ${e.message}'); + } +} +``` + + +## Continue sign-in with MFA Selection + +If the next step is `continueSignInWithMFASelection`, the user must select the MFA method to use. Amplify Auth currently supports SMS, TOTP, and email as MFA methods. After the user selects an MFA method, your implementation must pass the selected MFA method to Amplify Auth using `confirmSignIn` API. The MFA types which are currently supported by Amplify Auth are: - `MfaType.sms` - `MfaType.totp` +- `MfaType.email` ```dart Future _handleSignInResult(SignInResult result) async { @@ -193,7 +768,35 @@ Future _handleMfaSelection(MfaType selection) async { } ``` -### Continue signin with TOTP Setup +## Continue sign-in with Email Setup + +If the next step is `continueSignInWithEmailMfaSetup`, then the user must provide an email address to complete the sign in process. Once this value has been collected from the user, call the `confirmSignIn` API to continue. + +```dart +Future _handleSignInResult(SignInResult result) async { + switch (result.nextStep.signInStep) { + // ··· + case AuthSignInStep.continueSignInWithEmailMfaSetup: + // Prompt user to enter an email address they would like to use for MFA + // ··· + } +} + +// Then, pass the email address to `confirmSignIn` + +Future confirmEmailUser(String emailAddress) async { + try { + final result = await Amplify.Auth.confirmSignIn( + confirmationValue: emailAddress, + ); + return _handleSignInResult(result); + } on AuthException catch (e) { + safePrint('Error confirming email address: ${e.message}'); + } +} +``` + +## Continue sign-in with TOTP Setup If the next step is `continueSignInWithTOTPSetup`, then the user must provide a TOTP code to complete the sign in process. The step returns an associated value of type `TOTPSetupDetails` which would be used for generating TOTP. `TOTPSetupDetails` provides a helper method called `getSetupURI` that can be used to generate a URI, which can be used by native password managers for TOTP association. For example. if the URI is used on Apple platforms, it will trigger the platform's native password manager to associate TOTP with the account. For more advanced use cases, `TOTPSetupDetails` also contains the `sharedSecret` that will be used to either generate a QR code or can be manually entered into an authenticator app. @@ -225,7 +828,45 @@ Future confirmTotpUser(String totpCode) async { } } ``` -### Confirm signin with custom challenge + +## Continue sign-in with MFA Setup Selection +If the next step is `continueSignInWithMfaSetupSelection`, then the user must indicate which of the available MFA methods they would like to setup. After the user selects an MFA method to setup, your implementation must pass the selected MFA method to the `confirmSignIn` API. + +The MFA types which are currently supported by Amplify Auth are: + +- `MfaType.sms` +- `MfaType.totp` +- `MfaType.email` + +```dart +Future _handleSignInResult(SignInResult result) async { + switch (result.nextStep.signInStep) { + // ··· + case AuthSignInStep.continueSignInWithMfaSetupSelection: + final allowedMfaTypes = result.nextStep.allowedMfaTypes!; + final selection = await _promptUserPreference(allowedMfaTypes); + return _handleMfaSelection(selection); + // ··· + } +} + +Future _promptUserPreference(Set allowedTypes) async { + // ··· +} + +Future _handleMfaSelection(MfaType selection) async { + try { + final result = await Amplify.Auth.confirmSignIn( + confirmationValue: selection.confirmationValue, + ); + return _handleSignInResult(result); + } on AuthException catch (e) { + safePrint('Error selecting MFA method: ${e.message}'); + } +} +``` + +## Confirm sign-in with custom challenge If the next step is `confirmSignInWithCustomChallenge`, Amplify Auth is awaiting completion of a custom authentication challenge. The challenge is based on the AWS Lambda trigger you configured as part of a [custom sign in flow](/[platform]/build-a-backend/auth/customize-auth-lifecycle/custom-auth-flows/#sign-in-a-user). @@ -267,7 +908,7 @@ If `failAuthentication=true` is returned by the Lambda, Cognito will invalidate -### Confirm signin with new password +## Confirm sign-in with new password If the next step is `confirmSignInWithNewPassword`, Amplify Auth requires the user choose a new password they proceeding with the sign in. Prompt the user for a new password and pass it to the `confirmSignIn` API. @@ -296,7 +937,7 @@ Future confirmNewPassword(String newPassword) async { } ``` -### Reset password +## Reset password If the next step is `resetPassword`, Amplify Auth requires that the user reset their password before proceeding. Use the `resetPassword` API to guide the user through resetting their password, then call `Amplify.Auth.signIn` when that's complete to restart the sign-in flow. @@ -333,7 +974,7 @@ void _handleCodeDelivery(AuthCodeDeliveryDetails codeDeliveryDetails) { ); } ``` -### Confirm Signup +## Confirm Signup If the next step is `resetPassword`, Amplify Auth requires that the user confirm their email or phone number before proceeding. Use the `resendSignUpCode` API to send a new sign up code to the registered email or phone number, followed by `confirmSignUp` to complete the sign up. @@ -387,7 +1028,7 @@ Future confirmSignUp({ Once the sign up is confirmed, call `Amplify.Auth.signIn` again to restart the sign-in flow. -### Done +## Done The sign-in flow is complete when the next step is `done`, which means the user is successfully authenticated. As a convenience, the `SignInResult` also provides the `isSignedIn` property, which will be true if the next step is `done`. @@ -435,20 +1076,33 @@ try { { AuthNextSignInStep nextStep = result.getNextStep(); switch (nextStep.getSignInStep()) { - case CONFIRM_SIGN_IN_WITH_TOTP_CODE -> { + case CONFIRM_SIGN_IN_WITH_TOTP_CODE: { Log.i("AuthQuickstart", "Received next step as confirm sign in with TOTP code"); // Prompt the user to enter the TOTP code generated in their authenticator app // Then invoke `confirmSignIn` api with the code break; } - case CONTINUE_SIGN_IN_WITH_TOTP_SETUP -> { + case CONTINUE_SIGN_IN_WITH_MFA_SETUP_SELECTION: { + Log.i("AuthQuickstart", "Received next step as continue sign in by selecting an MFA method to setup"); + Log.i("AuthQuickstart", "Allowed MFA types for setup" + nextStep.getAllowedMFATypes()); + // Prompt the user to select the MFA type they want to setup + // Then invoke `confirmSignIn` api with the MFA type + break; + } + case CONTINUE_SIGN_IN_WITH_EMAIL_MFA_SETUP: { + Log.i("AuthQuickstart", "Received next step as continue sign in by setting up email MFA"); + // Prompt the user to enter the email address they would like to use to receive OTPs + // Then invoke `confirmSignIn` api with the email address + break; + } + case CONTINUE_SIGN_IN_WITH_TOTP_SETUP: { Log.i("AuthQuickstart", "Received next step as continue sign in by setting up TOTP"); Log.i("AuthQuickstart", "Shared secret that will be used to set up TOTP in the authenticator app" + nextStep.getTotpSetupDetails().getSharedSecret()); // Prompt the user to enter the TOTP code generated in their authenticator app // Then invoke `confirmSignIn` api with the code break; } - case CONTINUE_SIGN_IN_WITH_MFA_SELECTION -> { + case CONTINUE_SIGN_IN_WITH_MFA_SELECTION: { Log.i("AuthQuickstart", "Received next step as continue sign in by selecting MFA type"); Log.i("AuthQuickstart", "Allowed MFA type" + nextStep.getAllowedMFATypes()); // Prompt the user to select the MFA type they want to use @@ -462,6 +1116,13 @@ try { // Then invoke `confirmSignIn` api with the code break; } + case CONFIRM_SIGN_IN_WITH_OTP: { + Log.i("AuthQuickstart", "OTP code sent to " + nextStep.getCodeDeliveryDetails().getDestination()); + Log.i("AuthQuickstart", "Additional Info :" + nextStep.getAdditionalInfo()); + // Prompt the user to enter the OTP MFA code they received + // Then invoke `confirmSignIn` api with the code + break; + } case CONFIRM_SIGN_IN_WITH_CUSTOM_CHALLENGE: { Log.i("AuthQuickstart", "Custom challenge, additional info: " + nextStep.getAdditionalInfo()); // Prompt the user to enter custom challenge answer @@ -522,9 +1183,20 @@ try { val nextStep = result.nextStep when(nextStep.signInStep){ AuthSignInStep.CONFIRM_SIGN_IN_WITH_TOTP_CODE -> { - Log.i("AuthQuickstart", "Received next step as confirm sign in with TOTP code") - // Prompt the user to enter the TOTP code generated in their authenticator app - // Then invoke `confirmSignIn` api with the code + Log.i("AuthQuickstart", "Received next step as confirm sign in with TOTP code") + // Prompt the user to enter the TOTP code generated in their authenticator app + // Then invoke `confirmSignIn` api with the code + } + AuthSignInStep.CONTINUE_SIGN_IN_WITH_MFA_SETUP_SELECTION -> { + Log.i("AuthQuickstart", "Received next step as continue sign in by selecting an MFA method to setup"); + Log.i("AuthQuickstart", "Allowed MFA types for setup" + nextStep.getAllowedMFATypes()); + // Prompt the user to select the MFA type they want to setup + // Then invoke `confirmSignIn` api with the MFA type + } + AuthSignInStep.CONTINUE_SIGN_IN_WITH_EMAIL_MFA_SETUP -> { + Log.i("AuthQuickstart", "Received next step as continue sign in by setting up email MFA"); + // Prompt the user to enter the email address they would like to use to receive OTPs + // Then invoke `confirmSignIn` api with the email address } AuthSignInStep.CONTINUE_SIGN_IN_WITH_TOTP_SETUP -> { Log.i("AuthQuickstart", "Received next step as continue sign in by setting up TOTP") @@ -544,6 +1216,12 @@ try { // Prompt the user to enter the SMS MFA code they received // Then invoke `confirmSignIn` api with the code } + AuthSignInStep.CONFIRM_SIGN_IN_WITH_OTP -> { + Log.i("AuthQuickstart", "OTP code sent to " + nextStep.getCodeDeliveryDetails().getDestination()); + Log.i("AuthQuickstart", "Additional Info :" + nextStep.getAdditionalInfo()); + // Prompt the user to enter the OTP MFA code they received + // Then invoke `confirmSignIn` api with the code + } AuthSignInStep.CONFIRM_SIGN_IN_WITH_CUSTOM_CHALLENGE -> { Log.i("AuthQuickstart","Custom challenge, additional info: ${nextStep.additionalInfo}") // Prompt the user to enter custom challenge answer @@ -605,6 +1283,17 @@ try { // Prompt the user to enter the TOTP code generated in their authenticator app // Then invoke `confirmSignIn` api with the code } + AuthSignInStep.CONTINUE_SIGN_IN_WITH_MFA_SETUP_SELECTION -> { + Log.i("AuthQuickstart", "Received next step as continue sign in by selecting an MFA method to setup"); + Log.i("AuthQuickstart", "Allowed MFA types for setup" + nextStep.getAllowedMFATypes()); + // Prompt the user to select the MFA type they want to setup + // Then invoke `confirmSignIn` api with the MFA type + } + AuthSignInStep.CONTINUE_SIGN_IN_WITH_EMAIL_MFA_SETUP -> { + Log.i("AuthQuickstart", "Received next step as continue sign in by setting up email MFA"); + // Prompt the user to enter the email address they would like to use to receive OTPs + // Then invoke `confirmSignIn` api with the email address + } AuthSignInStep.CONTINUE_SIGN_IN_WITH_TOTP_SETUP -> { Log.i("AuthQuickstart", "Received next step as continue sign in by setting up TOTP") Log.i("AuthQuickstart", "Shared secret that will be used to set up TOTP in the authenticator app ${nextStep.totpSetupDetails.sharedSecret}") @@ -623,6 +1312,12 @@ try { // Prompt the user to enter the SMS MFA code they received // Then invoke `confirmSignIn` api with the code } + AuthSignInStep.CONFIRM_SIGN_IN_WITH_OTP -> { + Log.i("AuthQuickstart", "OTP code sent to ${nextStep.codeDeliveryDetails?.destination}") + Log.i("AuthQuickstart", "Additional Info ${nextStep.additionalInfo}") + // Prompt the user to enter the OTP MFA code they received + // Then invoke `confirmSignIn` api with the code + } AuthSignInStep.CONFIRM_SIGN_IN_WITH_CUSTOM_CHALLENGE -> { Log.i("AuthQuickstart", "Custom challenge, additional info: ${nextStep.additionalInfo}") // Prompt the user to enter custom challenge answer @@ -674,20 +1369,33 @@ RxAmplify.Auth.signIn("username", "password", options).subscribe( { AuthNextSignInStep nextStep = result.getNextStep(); switch (nextStep.getSignInStep()) { - case CONFIRM_SIGN_IN_WITH_TOTP_CODE -> { + case CONFIRM_SIGN_IN_WITH_TOTP_CODE: { Log.i("AuthQuickstart", "Received next step as confirm sign in with TOTP code"); // Prompt the user to enter the TOTP code generated in their authenticator app // Then invoke `confirmSignIn` api with the code break; } - case CONTINUE_SIGN_IN_WITH_TOTP_SETUP -> { + case CONTINUE_SIGN_IN_WITH_MFA_SETUP_SELECTION: { + Log.i("AuthQuickstart", "Received next step as continue sign in by selecting an MFA method to setup"); + Log.i("AuthQuickstart", "Allowed MFA types for setup" + nextStep.getAllowedMFATypes()); + // Prompt the user to select the MFA type they want to setup + // Then invoke `confirmSignIn` api with the MFA type + break; + } + case CONTINUE_SIGN_IN_WITH_EMAIL_MFA_SETUP: { + Log.i("AuthQuickstart", "Received next step as continue sign in by setting up email MFA"); + // Prompt the user to enter the email address they would like to use to receive OTPs + // Then invoke `confirmSignIn` api with the email address + break; + } + case CONTINUE_SIGN_IN_WITH_TOTP_SETUP: { Log.i("AuthQuickstart", "Received next step as continue sign in by setting up TOTP"); Log.i("AuthQuickstart", "Shared secret that will be used to set up TOTP in the authenticator app" + nextStep.getTotpSetupDetails().getSharedSecret()); // Prompt the user to enter the TOTP code generated in their authenticator app // Then invoke `confirmSignIn` api with the code break; } - case CONTINUE_SIGN_IN_WITH_MFA_SELECTION -> { + case CONTINUE_SIGN_IN_WITH_MFA_SELECTION: { Log.i("AuthQuickstart", "Received next step as continue sign in by selecting MFA type"); Log.i("AuthQuickstart", "Allowed MFA type" + nextStep.getAllowedMFATypes()); // Prompt the user to select the MFA type they want to use @@ -701,6 +1409,13 @@ RxAmplify.Auth.signIn("username", "password", options).subscribe( // Then invoke `confirmSignIn` api with the code break; } + case CONFIRM_SIGN_IN_WITH_OTP: { + Log.i("AuthQuickstart", "OTP code sent to " + nextStep.getCodeDeliveryDetails().getDestination()); + Log.i("AuthQuickstart", "Additional Info :" + nextStep.getAdditionalInfo()); + // Prompt the user to enter the OTP MFA code they received + // Then invoke `confirmSignIn` api with the code + break; + } case CONFIRM_SIGN_IN_WITH_CUSTOM_CHALLENGE: { Log.i("AuthQuickstart", "Custom challenge, additional info: " + nextStep.getAdditionalInfo()); // Prompt the user to enter custom challenge answer @@ -746,7 +1461,7 @@ RxAmplify.Auth.signIn("username", "password", options).subscribe( -### Confirm signin with SMS MFA +## Confirm sign-in with SMS MFA If the next step is `CONFIRM_SIGN_IN_WITH_SMS_MFA_CODE`, Amplify Auth has sent the user a random code over SMS, and is waiting to find out if the user successfully received it. To handle this step, your app's UI must prompt the user to enter the code. After the user enters the code, your implementation must pass the value to Amplify Auth `confirmSignIn` API. @@ -846,23 +1561,38 @@ RxAmplify.Auth.confirmSignIn( -### Confirm signin with TOTP MFA +## Confirm sign-in with TOTP MFA -If the next step is `confirmSignInWithTOTPCode`, you should prompt the user to enter the TOTP code from their associated authenticator app during set up. The code is a six-digit number that changes every 30 seconds. The user must enter the code before the 30-second window expires. +If the next step is `CONFIRM_SIGN_IN_WITH_TOTP_CODE`, you should prompt the user to enter the TOTP code from their associated authenticator app during set up. The code is a six-digit number that changes every 30 seconds. The user must enter the code before the 30-second window expires. After the user enters the code, your implementation must pass the value to Amplify Auth `confirmSignIn` API. -### Continue signin with MFA Selection -If the next step is `continueSignInWithMFASelection`, the user must select the MFA method to use. Amplify Auth currently only supports SMS and TOTP as MFA methods. After the user selects an MFA method, your implementation must pass the selected MFA method to Amplify Auth using `confirmSignIn` API. +## Confirm sign-in with Email MFA -### Continue signin with TOTP Setup +If the next step is `CONFIRM_SIGN_IN_WITH_EMAIL_MFA_CODE`, Amplify Auth has sent the user a random code to their email address and is waiting to find out if the user successfully received it. To handle this step, your app's UI must prompt the user to enter the code. After the user enters the code, your implementation must pass the value to Amplify Auth `confirmSignIn` API. -If the next step is `continueSignInWithTOTPSetup`, then the user must provide a TOTP code to complete the sign in process. The step returns an associated value of type `TOTPSetupDetails` which would be used for generating TOTP. `TOTPSetupDetails` provides a helper method called `getSetupURI` that can be used to generate a URI, which can be used by native password managers for TOTP association. For example. if the URI is used on Apple platforms, it will trigger the platform's native password manager to associate TOTP with the account. For more advanced use cases, `TOTPSetupDetails` also contains the `sharedSecret` that will be used to either generate a QR code or can be manually entered into an authenticator app. +Note: the signIn result also includes an `AuthCodeDeliveryDetails` member. It includes additional information about the code delivery such as the partial email address of the recipient. + +## Continue sign-in with MFA Selection + +If the next step is `CONTINUE_SIGN_IN_WITH_MFA_SELECTION`, the user must select the MFA method to use. Amplify Auth currently supports SMS, TOTP, and email as MFA methods. After the user selects an MFA method, your implementation must pass the selected MFA method to Amplify Auth using `confirmSignIn` API. + +## Continue sign-in with Email Setup + +If the next step is `CONTINUE_SIGN_IN_WITH_EMAIL_MFA_SETUP`, then the user must provide an email address to complete the sign in process. Once this value has been collected from the user, call the `confirmSignIn` API to continue. + +## Continue sign-in with TOTP Setup + +If the next step is `CONTINUE_SIGN_IN_WITH_TOTP_SETUP`, then the user must provide a TOTP code to complete the sign in process. The step returns an associated value of type `TOTPSetupDetails` which would be used for generating TOTP. `TOTPSetupDetails` provides a helper method called `getSetupURI` that can be used to generate a URI, which can be used by native password managers for TOTP association. For example. if the URI is used on Apple platforms, it will trigger the platform's native password manager to associate TOTP with the account. For more advanced use cases, `TOTPSetupDetails` also contains the `sharedSecret` that will be used to either generate a QR code or can be manually entered into an authenticator app. Once the authenticator app is set up, the user can generate a TOTP code and provide it to the library to complete the sign in process. -### Confirm signin with custom challenge +## Continue sign-in with MFA Setup Selection + +If the next step is `CONTINUE_SIGN_IN_WITH_MFA_SETUP_SELECTION`, the user must select the MFA method to setup. Amplify Auth currently supports SMS, TOTP, and email as MFA methods. After the user selects an MFA method, your implementation must pass the selected MFA method to Amplify Auth using `confirmSignIn` API. + +## Confirm sign-in with custom challenge If the next step is `CONFIRM_SIGN_IN_WITH_CUSTOM_CHALLENGE`, Amplify Auth is awaiting completion of a custom authentication challenge. The challenge is based on the Lambda trigger you setup when you configured a [custom sign in flow](/[platform]/build-a-backend/auth/customize-auth-lifecycle/custom-auth-flows/#sign-in-a-user). To complete this step, you should prompt the user for the custom challenge answer, and pass the answer to the `confirmSignIn` API. @@ -873,19 +1603,19 @@ If the next step is `CONFIRM_SIGN_IN_WITH_CUSTOM_CHALLENGE`, Amplify Auth is awa ```java try { Amplify.Auth.confirmSignIn( - "challenge answer", - result -> { - if (result.isSignedIn()) { - Log.i("AuthQuickstart", "Confirm signIn succeeded"); - } else { - Log.i("AuthQuickstart", "Confirm sign in not complete. There might be additional steps: " + result.getNextStep()); - // Switch on the next step to take appropriate actions. - // If `signInResult.isSignedIn` is true, the next step - // is 'done', and the user is now signed in. - } - }, - error -> Log.e("AuthQuickstart", "Confirm sign in failed: " + error) - ); + "challenge answer", + result -> { + if (result.isSignedIn()) { + Log.i("AuthQuickstart", "Confirm signIn succeeded"); + } else { + Log.i("AuthQuickstart", "Confirm sign in not complete. There might be additional steps: " + result.getNextStep()); + // Switch on the next step to take appropriate actions. + // If `signInResult.isSignedIn` is true, the next step + // is 'done', and the user is now signed in. + } + }, + error -> Log.e("AuthQuickstart", "Confirm sign in failed: " + error) + ); } catch (Exception error) { Log.e("AuthQuickstart", "Unexpected error: " + error); } @@ -897,21 +1627,21 @@ try { ```kotlin try { -Amplify.Auth.confirmSignIn( - "challenge answer", - { result -> - if (result.isSignedIn) { - Log.i("AuthQuickstart","Confirm signIn succeeded") - } else { - Log.i("AuthQuickstart", "Confirm sign in not complete. There might be additional steps: ${result.nextStep}") - // Switch on the next step to take appropriate actions. - // If `signInResult.isSignedIn` is true, the next step - // is 'done', and the user is now signed in. - } - } - ) { error -> - Log.e("AuthQuickstart", "Confirm sign in failed: $error") - } + Amplify.Auth.confirmSignIn( + "challenge answer", + { result -> + if (result.isSignedIn) { + Log.i("AuthQuickstart","Confirm signIn succeeded") + } else { + Log.i("AuthQuickstart", "Confirm sign in not complete. There might be additional steps: ${result.nextStep}") + // Switch on the next step to take appropriate actions. + // If `signInResult.isSignedIn` is true, the next step + // is 'done', and the user is now signed in. + } + } + ) { error -> + Log.e("AuthQuickstart", "Confirm sign in failed: $error") + } } catch (error: Exception) { Log.e("AuthQuickstart", "Unexpected error: $error") } @@ -946,19 +1676,19 @@ try { ```java RxAmplify.Auth.confirmSignIn( - "challenge answer").subscribe( - result -> { - if (result.isSignedIn()) { - Log.i("AuthQuickstart", "Confirm signIn succeeded"); - } else { - Log.i("AuthQuickstart", "Confirm sign in not complete. There might be additional steps: " + result.getNextStep()); - // Switch on the next step to take appropriate actions. - // If `signInResult.isSignedIn` is true, the next step - // is 'done', and the user is now signed in. - } - }, - error -> Log.e("AuthQuickstart", "Confirm sign in failed: " + error) - ); + "challenge answer").subscribe( + result -> { + if (result.isSignedIn()) { + Log.i("AuthQuickstart", "Confirm signIn succeeded"); + } else { + Log.i("AuthQuickstart", "Confirm sign in not complete. There might be additional steps: " + result.getNextStep()); + // Switch on the next step to take appropriate actions. + // If `signInResult.isSignedIn` is true, the next step + // is 'done', and the user is now signed in. + } + }, + error -> Log.e("AuthQuickstart", "Confirm sign in failed: " + error) +); ``` @@ -976,7 +1706,7 @@ NotAuthorizedException{message=Failed since user is not authorized., cause=NotAu -### Confirm signin with new password +## Confirm sign-in with new password If you receive a `UserNotConfirmedException` while signing in, Amplify Auth requires a new password for the user before they can proceed. Prompt the user for a new password and pass it to the `confirmSignIn` API. @@ -1067,7 +1797,7 @@ RxAmplify.Auth.confirmSignIn( -### Reset password +## Reset password If you receive `PasswordResetRequiredException`, authentication flow could not proceed without resetting the password. The next step is to invoke `resetPassword` api and follow the reset password flow. @@ -1129,7 +1859,7 @@ RxAmplify.Auth.resetPassword( -### Confirm Signup +## Confirm Signup If you receive `CONFIRM_SIGN_UP` as a next step, sign up could not proceed without confirming user information such as email or phone number. The next step is to invoke the `confirmSignUp` API and follow the confirm signup flow. @@ -1199,7 +1929,7 @@ RxAmplify.Auth.confirmSignUp( -### Get Current User +## Get Current User This call fetches the current logged in user and should be used after a user has been successfully signed in. If the user is signed in, it will return the current userId and username. @@ -1255,7 +1985,7 @@ try { -### Done +## Done Sign In flow is complete when you get `done`. This means the user is successfully authenticated. As a convenience, the SignInResult also provides the `isSignedIn` property, which will be true if the next step is `done`. @@ -1283,7 +2013,7 @@ func signIn(username: String, password: String) async { let signInResult = try await Amplify.Auth.signIn(username: username, password: password) switch signInResult.nextStep { case .confirmSignInWithSMSMFACode(let deliveryDetails, let info): - print("SMS code send to \(deliveryDetails.destination)") + print("SMS code sent to \(deliveryDetails.destination)") print("Additional info \(String(describing: info))") // Prompt the user to enter the SMSMFA code they received @@ -1294,6 +2024,12 @@ func signIn(username: String, password: String) async { // Prompt the user to enter the TOTP code generated in their authenticator app // Then invoke `confirmSignIn` api with the code + + case .confirmSignInWithOTP(let deliveryDetails): + print("Email code sent to \(deliveryDetails.destination)") + + // Prompt the user to enter the Email MFA code they received + // Then invoke `confirmSignIn` api with the code case .continueSignInWithTOTPSetup(let setUpDetails): print("Received next step as continue sign in by setting up TOTP") @@ -1302,6 +2038,19 @@ func signIn(username: String, password: String) async { // Prompt the user to enter the TOTP code generated in their authenticator app // Then invoke `confirmSignIn` api with the code + case .continueSignInWithEmailMFASetup: + print("Received next step as continue sign in by setting up email MFA") + + // Prompt the user to enter the email address they wish to use for MFA + // Then invoke `confirmSignIn` api with the email address + + case .continueSignInWithMFASetupSelection(let allowedMFATypes): + print("Received next step as continue sign in by selecting MFA type to setup") + print("Allowed MFA types \(allowedMFATypes)") + + // Prompt the user to select the MFA type they want to setup + // Then invoke `confirmSignIn` api with the MFA type + case .continueSignInWithMFASelection(let allowedMFATypes): print("Received next step as continue sign in by selecting MFA type") print("Allowed MFA types \(allowedMFATypes)") @@ -1353,7 +2102,7 @@ func signIn(username: String, password: String) async { The `nextStep` property is of enum type `AuthSignInStep`. Depending on its value, your code should take one of the following actions: -### Confirm signin with SMS MFA +## Confirm sign-in with SMS MFA If the next step is `confirmSignInWithSMSMFACode`, Amplify Auth has sent the user a random code over SMS, and is waiting to find out if the user successfully received it. To handle this step, your app's UI must prompt the user to enter the code. After the user enters the code, your implementation must pass the value to Amplify Auth `confirmSignIn` API. Note: the signin result also includes an `AuthCodeDeliveryDetails` member. It includes additional information about the code delivery such as the partial phone number of the SMS recipient. @@ -1414,7 +2163,7 @@ func confirmSignIn(confirmationCodeFromUser: String) -> AnyCancellable { -### Confirm signin with TOTP MFA +## Confirm sign-in with TOTP MFA If the next step is `confirmSignInWithTOTPCode`, you should prompt the user to enter the TOTP code from their associated authenticator app during set up. The code is a six-digit number that changes every 30 seconds. The user must enter the code before the 30-second window expires. @@ -1474,9 +2223,76 @@ func confirmSignIn(totpCode: String) -> AnyCancellable { -### Continue signin with MFA Selection -If the next step is `continueSignInWithMFASelection`, the user must select the MFA method to use. Amplify Auth currently only supports SMS and TOTP as MFA methods. After the user selects an MFA method, your implementation must pass the selected MFA method to Amplify Auth using `confirmSignIn` API. +## Confirm sign-in with Email MFA +If the next step is `confirmSignInWithOTP`, Amplify Auth has sent a random code to the user's email address, and is waiting to find out if the user successfully received it. To handle this step, your app's UI must prompt the user to enter the code. After the user enters the code, your implementation must pass the value to Amplify Auth `confirmSignIn` API. + + + +**Note:** the sign-in result also includes an `AuthCodeDeliveryDetails` member. It includes additional information about the code delivery such as the partial email address of the recipient. + + + + + + + +```swift +func confirmSignIn(confirmationCodeFromUser: String) async { + do { + let signInResult = try await Amplify.Auth.confirmSignIn(challengeResponse: confirmationCodeFromUser) + if signInResult.isSignedIn { + print("Confirm sign in succeeded. The user is signed in.") + } else { + print("Confirm sign in succeeded.") + print("Next step: \(signInResult.nextStep)") + // Switch on the next step to take appropriate actions. + // If `signInResult.isSignedIn` is true, the next step + // is 'done', and the user is now signed in. + } + } catch let error as AuthError { + print("Confirm sign in failed \(error)") + } catch { + print("Unexpected error: \(error)") + } +} +``` + + + + + +```swift +func confirmSignIn(confirmationCodeFromUser: String) -> AnyCancellable { + Amplify.Publisher.create { + try await Amplify.Auth.confirmSignIn(challengeResponse: confirmationCodeFromUser) + }.sink { + if case let .failure(authError) = $0 { + print("Confirm sign in failed \(authError)") + } + } + receiveValue: { signInResult in + if signInResult.isSignedIn { + print("Confirm sign in succeeded. The user is signed in.") + } else { + print("Confirm sign in succeeded.") + print("Next step: \(signInResult.nextStep)") + // Switch on the next step to take appropriate actions. + // If `signInResult.isSignedIn` is true, the next step + // is 'done', and the user is now signed in. + } + } +} +``` + + + + + + +## Continue sign-in with MFA Selection + +If the next step is `continueSignInWithMFASelection`, the user must select the MFA method to use. Amplify Auth currently supports SMS, TOTP, and email as MFA methods. After the user selects an MFA method, your implementation must pass the selected MFA method to Amplify Auth using `confirmSignIn` API. @@ -1523,7 +2339,20 @@ func confirmSignInWithTOTPAsMFASelection() -> AnyCancellable { -### Continue signin with TOTP Setup + +## Continue sign-in with Email Setup +If the next step is `continueSignInWithEmailMFASetup`, then the user must provide an email address to complete the sign in process. Once this value has been collected from the user, call the `confirmSignIn` API to continue. + +```swift +// Confirm sign in with Email Setup +case .continueSignInWithEmailMFASetup: + print("Received next step as continue sign in by setting up email MFA") + + // Prompt the user to enter the email address they wish to use for MFA + // Then invoke `confirmSignIn` api with the email address +``` + +## Continue sign-in with TOTP Setup If the next step is `continueSignInWithTOTPSetup`, then the user must provide a TOTP code to complete the sign in process. The step returns an associated value of type `TOTPSetupDetails` which would be used for generating TOTP. `TOTPSetupDetails` provides a helper method called `getSetupURI` that can be used to generate a URI, which can be used by native password managers for TOTP association. For example. if the URI is used on Apple platforms, it will trigger the platform's native password manager to associate TOTP with the account. For more advanced use cases, `TOTPSetupDetails` also contains the `sharedSecret` that will be used to either generate a QR code or can be manually entered into an authenticator app. @@ -1596,7 +2425,57 @@ func confirmSignInWithTOTPSetup(totpCodeFromAuthenticatorApp: String) -> AnyCanc -### Confirm signin with custom challenge +## Continue sign-in with MFA Setup Selection + +If the next step is `continueSignInWithMFASetupSelection`, the user must indicate which of the available MFA methods they would like to setup. After the user selects an MFA method to setup, your implementation must pass the selected MFA method to the `confirmSignIn` API. + + + + + +```swift +func continueSignInWithEmailMFASetupSelection() async { + do { + let signInResult = try await Amplify.Auth.confirmSignIn( + challengeResponse: MFAType.email.challengeResponse) + + if case .confirmSignInWithTOTPCode = signInResult.nextStep { + print("Received next step as confirm sign in with TOTP") + } + + } catch { + print("Confirm sign in failed \(error)") + } +} +``` + + + + + +```swift +func continueSignInWithEmailMFASetupSelection() -> AnyCancellable { + Amplify.Publisher.create { + try await Amplify.Auth.confirmSignIn( + challengeResponse: MFAType.email.challengeResponse) + }.sink { + if case let .failure(authError) = $0 { + print("Confirm sign in failed \(authError)") + } + } + receiveValue: { signInResult in + if case .confirmSignInWithTOTPCode = signInResult.nextStep { + print("Received next step as confirm sign in with TOTP") + } + } +} +``` + + + + + +## Confirm sign-in with custom challenge If the next step is `confirmSignInWithCustomChallenge`, Amplify Auth is awaiting completion of a custom authentication challenge. The challenge is based on the Lambda trigger you setup when you configured a [custom sign in flow](/[platform]/build-a-backend/auth/customize-auth-lifecycle/custom-auth-flows/#sign-in-a-user). To complete this step, you should prompt the user for the custom challenge answer, and pass the answer to the `confirmSignIn` API. @@ -1667,7 +2546,7 @@ Exception: notAuthorized{message=Failed since user is not authorized., cause=No -### Confirm signin with new password +## Confirm sign-in with new password If the next step is `confirmSignInWithNewPassword`, Amplify Auth requires a new password for the user before they can proceed. Prompt the user for a new password and pass it to the `confirmSignIn` API. @@ -1727,7 +2606,7 @@ func confirmSignIn(newPasswordFromUser: String) -> AnyCancellable { -### Reset password +## Reset password If you receive `resetPassword`, authentication flow could not proceed without resetting the password. The next step is to invoke `resetPassword` api and follow the reset password flow. @@ -1773,7 +2652,7 @@ func resetPassword(username: String) -> AnyCancellable { -### Confirm Signup +## Confirm Signup If you receive `confirmSignUp` as a next step, sign up could not proceed without confirming user information such as email or phone number. The next step is to invoke the `confirmSignUp` API and follow the confirm signup flow. @@ -1820,7 +2699,7 @@ func confirmSignUp(for username: String, with confirmationCode: String) -> AnyCa -### Done +## Done Signin flow is complete when you get `done`. This means the user is successfully authenticated. As a convenience, the SignInResult also provides the `isSignedIn` property, which will be true if the next step is `done`. diff --git a/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/sign-in/index.mdx b/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/sign-in/index.mdx index e497d3c9acf..d018ea92424 100644 --- a/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/sign-in/index.mdx +++ b/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/sign-in/index.mdx @@ -66,7 +66,7 @@ The quickest way to get started with Amplify Auth in your frontend application i {/* signIn api definition */} - + ```ts import { signIn } from 'aws-amplify/auth' @@ -253,52 +253,76 @@ func signIn(username: String, password: String) -> AnyCancellable { The `signIn` API response will include a `nextStep` property, which can be used to determine if further action is required. It may return the following next steps: - -- `CONFIRM_SIGN_IN_WITH_NEW_PASSWORD_REQUIRED` - The user was created with a temporary password and must set a new one. Complete the process with `confirmSignIn`. -- `CONFIRM_SIGN_IN_WITH_CUSTOM_CHALLENGE` - The sign-in must be confirmed with a custom challenge response. Complete the process with `confirmSignIn`. -- `CONFIRM_SIGN_IN_WITH_TOTP_CODE` - The sign-in must be confirmed with a TOTP code from the user. Complete the process with `confirmSignIn`. -- `CONTINUE_SIGN_IN_WITH_TOTP_SETUP` - The TOTP setup process must be continued. Complete the process with `confirmSignIn`. -- `CONFIRM_SIGN_IN_WITH_SMS_CODE` - The sign-in must be confirmed with a SMS code from the user. Complete the process with `confirmSignIn`. -- `CONTINUE_SIGN_IN_WITH_MFA_SELECTION` - The user must select their mode of MFA verification before signing in. Complete the process with `confirmSignIn`. -- `RESET_PASSWORD` - The user must reset their password via `resetPassword`. -- `CONFIRM_SIGN_UP` - The user hasn't completed the sign-up flow fully and must be confirmed via `confirmSignUp`. -- `DONE` - The sign in process has been completed. + +| Next Step | Description | +| --------- | ----------- | +| `CONFIRM_SIGN_IN_WITH_NEW_PASSWORD_REQUIRED` | The user was created with a temporary password and must set a new one. Complete the process with `confirmSignIn`. | +| `CONFIRM_SIGN_IN_WITH_CUSTOM_CHALLENGE` | The sign-in must be confirmed with a custom challenge response. Complete the process with `confirmSignIn`. | +| `CONFIRM_SIGN_IN_WITH_TOTP_CODE` | The sign-in must be confirmed with a TOTP code from the user. Complete the process with `confirmSignIn`. | +| `CONFIRM_SIGN_IN_WITH_SMS_CODE` | The sign-in must be confirmed with a SMS code from the user. Complete the process with `confirmSignIn`. | +| `CONFIRM_SIGN_IN_WITH_EMAIL_CODE` | The sign-in must be confirmed with a EMAIL code from the user. Complete the process with `confirmSignIn`. | +| `CONTINUE_SIGN_IN_WITH_MFA_SELECTION` | The user must select their mode of MFA verification before signing in. Complete the process with `confirmSignIn`. | +| `CONTINUE_SIGN_IN_WITH_MFA_SETUP_SELECTION` | The user must select their mode of MFA verification to setup. Complete the process by passing either `"EMAIL"` or `"TOTP"` to `confirmSignIn`. | +| `CONTINUE_SIGN_IN_WITH_TOTP_SETUP` | The TOTP setup process must be continued. Complete the process with `confirmSignIn`. | +| `CONTINUE_SIGN_IN_WITH_EMAIL_SETUP` | The EMAIL setup process must be continued. Complete the process by passing a valid email address to `confirmSignIn`. | +| `RESET_PASSWORD` | The user must reset their password via `resetPassword`. | +| `CONFIRM_SIGN_UP` | The user hasn't completed the sign-up flow fully and must be confirmed via `confirmSignUp`. | +| `DONE` | The sign in process has been completed. | - -- `confirmSignInWithNewPassword` - The user was created with a temporary password and must set a new one. Complete the process with `confirmSignIn`. -- `confirmSignInWithCustomChallenge` - The sign-in must be confirmed with a custom challenge response. Complete the process with `confirmSignIn`. -- `confirmSignInWithTOTPCode` - The sign-in must be confirmed with a TOTP code from the user. Complete the process with `confirmSignIn`. -- `continueSignInWithTOTPSetup` - The TOTP setup process must be continued. Complete the process with `confirmSignIn`. -- `confirmSignInWithSMSMFACode` - The sign-in must be confirmed with a SMS code from the user. Complete the process with `confirmSignIn`. -- `continueSignInWithMFASelection` - The user must select their mode of MFA verification before signing in. Complete the process with `confirmSignIn`. -- `resetPassword` - The user must reset their password via `resetPassword`. -- `confirmSignUp` - The user hasn't completed the sign-up flow fully and must be confirmed via `confirmSignUp`. -- `done` - The sign in process has been completed. + +| Next Step | Description | +| --------- | ----------- | +| `CONFIRM_SIGN_IN_WITH_NEW_PASSWORD` | The user was created with a temporary password and must set a new one. Complete the process with `confirmSignIn`. | +| `CONFIRM_SIGN_IN_WITH_CUSTOM_CHALLENGE` | The sign-in must be confirmed with a custom challenge response. Complete the process with `confirmSignIn`. | +| `CONFIRM_SIGN_IN_WITH_TOTP_CODE` | The sign-in must be confirmed with a TOTP code from the user. Complete the process with `confirmSignIn`. | +| `CONFIRM_SIGN_IN_WITH_SMS_MFA_CODE` | The sign-in must be confirmed with a SMS code from the user. Complete the process with `confirmSignIn`. | +| `CONFIRM_SIGN_IN_WITH_OTP` | The sign-in must be confirmed with a code from the user (sent via SMS or Email). Complete the process with `confirmSignIn`. | +| `CONTINUE_SIGN_IN_WITH_MFA_SELECTION` | The user must select their mode of MFA verification before signing in. Complete the process with `confirmSignIn`. | +| `CONTINUE_SIGN_IN_WITH_MFA_SETUP_SELECTION` | The user must select their mode of MFA verification to setup. Complete the process by passing either `MFAType.EMAIL.challengeResponse` or `MFAType.TOTP.challengeResponse` to `confirmSignIn`. | +| `CONTINUE_SIGN_IN_WITH_TOTP_SETUP` | The TOTP setup process must be continued. Complete the process with `confirmSignIn`. | +| `CONTINUE_SIGN_IN_WITH_EMAIL_MFA_SETUP` | The EMAIL setup process must be continued. Complete the process by passing a valid email address to `confirmSignIn`. | +| `RESET_PASSWORD` | The user must reset their password via `resetPassword`. | +| `CONFIRM_SIGN_UP` | The user hasn't completed the sign-up flow fully and must be confirmed via `confirmSignUp`. | +| `DONE` | The sign in process has been completed. | -For more information on handling the TOTP and MFA steps that may be returned, see [multi-factor authentication](/[platform]/build-a-backend/auth/concepts/multi-factor-authentication/). - -### Confirm sign-in - - - -```ts title="src/main.ts" -import { confirmSignIn, signIn } from 'aws-amplify/auth' + +| Next Step | Description | +| --------- | ----------- | +| `confirmSignInWithNewPassword` | The user was created with a temporary password and must set a new one. Complete the process with `confirmSignIn`. | +| `confirmSignInWithCustomChallenge` | The sign-in must be confirmed with a custom challenge response. Complete the process with `confirmSignIn`. | +| `confirmSignInWithTOTPCode` | The sign-in must be confirmed with a TOTP code from the user. Complete the process with `confirmSignIn`. | +| `confirmSignInWithSMSMFACode` | The sign-in must be confirmed with a SMS code from the user. Complete the process with `confirmSignIn`. | +| `confirmSignInWithOTP` | The sign-in must be confirmed with a code from the user (sent via SMS or Email). Complete the process with `confirmSignIn`. | +| `continueSignInWithMFASelection` | The user must select their mode of MFA verification before signing in. Complete the process with `confirmSignIn`. | +| `continueSignInWithMFASetupSelection` | The user must select their mode of MFA verification to setup. Complete the process by passing either `MFAType.email.challengeResponse` or `MFAType.totp.challengeResponse ` to `confirmSignIn`. | +| `continueSignInWithTOTPSetup` | The TOTP setup process must be continued. Complete the process with `confirmSignIn`. | +| `continueSignInWithEmailMFASetup` | The EMAIL setup process must be continued. Complete the process by passing a valid email address to `confirmSignIn`. | +| `resetPassword` | The user must reset their password via `resetPassword`. | +| `confirmSignUp` | The user hasn't completed the sign-up flow fully and must be confirmed via `confirmSignUp`. | +| `done` | The sign in process has been completed. | + -const { nextStep } = await signIn({ - username: "hello@mycompany.com", - password: "hunter2", -}) + +| Next Step | Description | +| --------- | ----------- | +| `confirmSignInWithNewPassword` | The user was created with a temporary password and must set a new one. Complete the process with `confirmSignIn`. | +| `confirmSignInWithCustomChallenge` | The sign-in must be confirmed with a custom challenge response. Complete the process with `confirmSignIn`. | +| `confirmSignInWithTotpMfaCode` | The sign-in must be confirmed with a TOTP code from the user. Complete the process with `confirmSignIn`. | +| `confirmSignInWithSmsMfaCode` | The sign-in must be confirmed with a SMS code from the user. Complete the process with `confirmSignIn`. | +| `confirmSignInWithOtpCode` | The sign-in must be confirmed with a code from the user (sent via SMS or Email). Complete the process with `confirmSignIn`. | +| `continueSignInWithMfaSelection` | The user must select their mode of MFA verification before signing in. Complete the process with `confirmSignIn`. | +| `continueSignInWithMfaSetupSelection` | The user must select their mode of MFA verification to setup. Complete the process by passing either `"EMAIL"` or `"TOTP"` to `confirmSignIn`. | +| `continueSignInWithTotpSetup` | The TOTP setup process must be continued. Complete the process with `confirmSignIn`. | +| `continueSignInWithEmailMfaSetup` | The EMAIL setup process must be continued. Complete the process by passing a valid email address to `confirmSignIn`. | +| `resetPassword` | The user must reset their password via `resetPassword`. | +| `confirmSignUp` | The user hasn't completed the sign-up flow fully and must be confirmed via `confirmSignUp`. | +| `done` | The sign in process has been completed. | + -if (nextStep === "CONFIRM_SIGN_IN_WITH_SMS_CODE") { - await confirmSignIn({ - challengeResponse: "12345" - }) -} -``` +For more information on handling the MFA steps that may be returned, see [multi-factor authentication](/[platform]/build-a-backend/auth/concepts/multi-factor-authentication/). - {/* @todo */} @@ -404,7 +428,13 @@ export default function App() { {/* with multi-factor auth */} ## With multi-factor auth enabled -When multi-factor authentication (MFA) is **required** with SMS in your backend auth resource, you will need to pass the phone number during sign-up API call. If you are using the `email` or `username` as the primary sign-in mechanism, you will need to pass the `phone_number` attribute as a user attribute. This will change depending on if you enable SMS, TOTP, or both. Visit the [multi-factor authentication documentation](/[platform]/build-a-backend/auth/concepts/multi-factor-authentication/) to learn more about enabling MFA on your backend auth resource. +When you have Email or SMS MFA enabled, Cognito will send messages to your users on your behalf. Email and SMS messages require that your users have email address and phone number attributes respectively. It is recommended to set these attributes as required in your user pool if you wish to use either Email MFA or SMS MFA. When these attributes are required, a user must provide these details before they can complete the sign up process. + +If you have set MFA to be required and you have activated more than one authentication factor, Cognito will prompt new users to select an MFA factor they want to use. Users must have a phone number to select SMS and an email address to select email MFA. + +If a user doesn't have the necessary attributes defined for any available message based MFA, Cognito will prompt them to set up TOTP. + +Visit the [multi-factor authentication documentation](/[platform]/build-a-backend/auth/concepts/multi-factor-authentication/) to learn more about enabling MFA on your backend auth resource. @@ -550,12 +580,58 @@ func signUp(username: String, password: String, email: String, phonenumber: Stri - -You will then confirm sign-up, sign in, and receive a `nextStep` in the sign-in result of type `CONFIRM_SIGN_IN_WITH_SMS_MFA_CODE`. A confirmation code will also be texted to the phone number provided above. Pass the code you received to the `confirmSignIn` API: +### Confirm sign-in + + +Following sign in, you will receive a `nextStep` in the sign-in result of one of the following types. Collect the user response and then pass to the `confirmSignIn` API to complete the sign in flow. +| Next Step | Description | +| --------- | ----------- | +| `CONFIRM_SIGN_IN_WITH_TOTP_CODE` | The sign-in must be confirmed with a TOTP code from the user. Complete the process with `confirmSignIn`. | +| `CONFIRM_SIGN_IN_WITH_SMS_CODE` | The sign-in must be confirmed with a SMS code from the user. Complete the process with `confirmSignIn`. | +| `CONFIRM_SIGN_IN_WITH_EMAIL_CODE` | The sign-in must be confirmed with a EMAIL code from the user. Complete the process with `confirmSignIn`. | +| `CONTINUE_SIGN_IN_WITH_MFA_SELECTION` | The user must select their mode of MFA verification before signing in. Complete the process with `confirmSignIn`. | +| `CONTINUE_SIGN_IN_WITH_MFA_SETUP_SELECTION` | The user must select their mode of MFA verification to setup. Complete the process by passing either `"EMAIL"` or `"TOTP"` to `confirmSignIn`. | +| `CONTINUE_SIGN_IN_WITH_TOTP_SETUP` | The TOTP setup process must be continued. Complete the process with `confirmSignIn`. | +| `CONTINUE_SIGN_IN_WITH_EMAIL_SETUP` | The EMAIL setup process must be continued. Complete the process by passing a valid email address to `confirmSignIn`. | + + + +Following sign in, you will receive a `nextStep` in the sign-in result of one of the following types. Collect the user response and then pass to the `confirmSignIn` API to complete the sign in flow. +| Next Step | Description | +| --------- | ----------- | +| `CONFIRM_SIGN_IN_WITH_TOTP_CODE` | The sign-in must be confirmed with a TOTP code from the user. Complete the process with `confirmSignIn`. | +| `CONFIRM_SIGN_IN_WITH_SMS_MFA_CODE` | The sign-in must be confirmed with a SMS code from the user. Complete the process with `confirmSignIn`. | +| `CONFIRM_SIGN_IN_WITH_OTP` | The sign-in must be confirmed with a code from the user (sent via SMS or Email). Complete the process with `confirmSignIn`. | +| `CONTINUE_SIGN_IN_WITH_MFA_SELECTION` | The user must select their mode of MFA verification before signing in. Complete the process with `confirmSignIn`. | +| `CONTINUE_SIGN_IN_WITH_MFA_SETUP_SELECTION` | The user must select their mode of MFA verification to setup. Complete the process by passing either `MFAType.EMAIL.challengeResponse` or `MFAType.TOTP.challengeResponse` to `confirmSignIn`. | +| `CONTINUE_SIGN_IN_WITH_TOTP_SETUP` | The TOTP setup process must be continued. Complete the process with `confirmSignIn`. | +| `CONTINUE_SIGN_IN_WITH_EMAIL_MFA_SETUP` | The EMAIL setup process must be continued. Complete the process by passing a valid email address to `confirmSignIn`. | -You will then confirm sign-up, sign in, and receive a `nextStep` in the sign-in result of type `confirmSignInWithSMSMFACode`. A confirmation code will also be texted to the phone number provided above. Pass the code you received to the `confirmSignIn` API: +Following sign in, you will receive a `nextStep` in the sign-in result of one of the following types. Collect the user response and then pass to the `confirmSignIn` API to complete the sign in flow. +| Next Step | Description | +| --------- | ----------- | +| `confirmSignInWithTOTPCode` | The sign-in must be confirmed with a TOTP code from the user. Complete the process with `confirmSignIn`. | +| `confirmSignInWithSMSMFACode` | The sign-in must be confirmed with a SMS code from the user. Complete the process with `confirmSignIn`. | +| `confirmSignInWithOTP` | The sign-in must be confirmed with a code from the user (sent via SMS or Email). Complete the process with `confirmSignIn`. | +| `continueSignInWithMFASelection` | The user must select their mode of MFA verification before signing in. Complete the process with `confirmSignIn`. | +| `continueSignInWithMFASetupSelection` | The user must select their mode of MFA verification to setup. Complete the process by passing either `MFAType.email.challengeResponse` or `MFAType.totp.challengeResponse ` to `confirmSignIn`. | +| `continueSignInWithTOTPSetup` | The TOTP setup process must be continued. Complete the process with `confirmSignIn`. | +| `continueSignInWithEmailMFASetup` | The EMAIL setup process must be continued. Complete the process by passing a valid email address to `confirmSignIn`. | + + + +Following sign in, you will receive a `nextStep` in the sign-in result of one of the following types. Collect the user response and then pass to the `confirmSignIn` API to complete the sign in flow. +| Next Step | Description | +| --------- | ----------- | +| `confirmSignInWithTotpMfaCode` | The sign-in must be confirmed with a TOTP code from the user. Complete the process with `confirmSignIn`. | +| `confirmSignInWithSmsMfaCode` | The sign-in must be confirmed with a SMS code from the user. Complete the process with `confirmSignIn`. | +| `confirmSignInWithOtpCode` | The sign-in must be confirmed with a code from the user (sent via SMS or Email). Complete the process with `confirmSignIn`. | +| `continueSignInWithMfaSelection` | The user must select their mode of MFA verification before signing in. Complete the process with `confirmSignIn`. | +| `continueSignInWithMfaSetupSelection` | The user must select their mode of MFA verification to setup. Complete the process by passing either `MfaType.email.confirmationValue` or `MfaType.totp.confirmationValue` to `confirmSignIn`. | +| `continueSignInWithTotpSetup` | The TOTP setup process must be continued. Complete the process with `confirmSignIn`. | +| `continueSignInWithEmailMfaSetup` | The EMAIL setup process must be continued. Complete the process by passing a valid email address to `confirmSignIn`. | @@ -566,6 +642,62 @@ You will then confirm sign-up, sign in, and receive a `nextStep` in the sign-in + + +```ts title="src/main.ts" +import { confirmSignIn, signIn } from "aws-amplify/auth"; + +const { nextStep } = await signIn({ + username: "hello@mycompany.com", + password: "hunter2", +}); + +if ( + nextStep.signInStep === "CONFIRM_SIGN_IN_WITH_SMS_CODE" || + nextStep.signInStep === "CONFIRM_SIGN_IN_WITH_EMAIL_CODE" || + nextStep.signInStep === "CONFIRM_SIGN_IN_WITH_TOTP_CODE" +) { + // collect OTP from user + await confirmSignIn({ + challengeResponse: "123456", + }); +} + +if (nextStep.signInStep === "CONTINUE_SIGN_IN_WITH_MFA_SELECTION") { + // present nextStep.allowedMFATypes to user + // collect user selection + await confirmSignIn({ + challengeResponse: "EMAIL", // 'EMAIL', 'SMS', or 'TOTP' + }); +} + +if (nextStep.signInStep === "CONTINUE_SIGN_IN_WITH_MFA_SETUP_SELECTION") { + // present nextStep.allowedMFATypes to user + // collect user selection + await confirmSignIn({ + challengeResponse: "EMAIL", // 'EMAIL' or 'TOTP' + }); +} + +if (nextStep.signInStep === "CONTINUE_SIGN_IN_WITH_EMAIL_SETUP") { + // collect email address from user + await confirmSignIn({ + challengeResponse: "hello@mycompany.com", + }); +} + +if (nextStep.signInStep === "CONTINUE_SIGN_IN_WITH_TOTP_SETUP") { + // present nextStep.totpSetupDetails.getSetupUri() to user + // collect OTP from user + await confirmSignIn({ + challengeResponse: "123456", + }); +} + +``` + + + diff --git a/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/sign-up/index.mdx b/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/sign-up/index.mdx index 794d6b3ddf3..692d8f82939 100644 --- a/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/sign-up/index.mdx +++ b/src/pages/[platform]/build-a-backend/auth/connect-your-frontend/sign-up/index.mdx @@ -285,15 +285,26 @@ func signUp(username: String, password: String, email: String, phonenumber: Stri The `signUp` API response will include a `nextStep` property, which can be used to determine if further action is required. It may return the following next steps: - -- `CONFIRM_SIGN_UP` - The sign up needs to be confirmed by collecting a code from the user and calling `confirmSignUp`. -- `DONE` - The sign up process has been fully completed. -- `COMPLETE_AUTO_SIGN_IN` - The sign up process needs to complete by invoking the `autoSignIn` API. + +| Next Step | Description | +| --------- | ----------- | +| `CONFIRM_SIGN_UP` | The sign up needs to be confirmed by collecting a code from the user and calling `confirmSignUp`. | +| `DONE` | The sign up process has been fully completed. | +| `COMPLETE_AUTO_SIGN_IN` | The sign up process needs to complete by invoking the `autoSignIn` API. | + + + +| Next Step | Description | +| --------- | ----------- | +| `CONFIRM_SIGN_UP_STEP` | The sign up needs to be confirmed by collecting a code from the user and calling `confirmSignUp`. | +| `DONE` | The sign up process has been fully completed. | -- `confirmUser` - The sign up needs to be confirmed by collecting a code from the user and calling `confirmSignUp` API. -- `done` - The sign up process has been fully completed. +| Next Step | Description | +| --------- | ----------- | +| `confirmSignUp` | The sign up needs to be confirmed by collecting a code from the user and calling `confirmSignUp`. | +| `done` | The sign up process has been fully completed. | ## Confirm sign-up @@ -308,7 +319,7 @@ By default, each user that signs up remains in the unconfirmed status until they You can confirm the sign-up after receiving a confirmation code from the user: - + ```ts import { confirmSignUp } from 'aws-amplify/auth'; diff --git a/src/pages/[platform]/build-a-backend/auth/customize-auth-lifecycle/custom-auth-flows/index.mdx b/src/pages/[platform]/build-a-backend/auth/customize-auth-lifecycle/custom-auth-flows/index.mdx index c4c093a03e8..9ba6bd7f9b3 100644 --- a/src/pages/[platform]/build-a-backend/auth/customize-auth-lifecycle/custom-auth-flows/index.mdx +++ b/src/pages/[platform]/build-a-backend/auth/customize-auth-lifecycle/custom-auth-flows/index.mdx @@ -33,16 +33,14 @@ An application with Amplify libraries integrated and a minimum target of any of - **macOS 10.15**, using **Xcode 14.1** or later. - **tvOS 13.0**, using **Xcode 14.3** or later. - **watchOS 9.0**, using **Xcode 14.3** or later. -- **visionOS 1.0**, using **Xcode 15 beta 2** or later. (Preview support - see below for more details.) +- **visionOS 1.0**, using **Xcode 15** or later. (Preview support - see below for more details.) For a full example, please follow the [project setup walkthrough](/[platform]/start/quickstart/). -visionOS support is currently in **preview** and can be used by targeting the [`visionos-preview`](https://github.com/aws-amplify/amplify-swift/tree/visionos-preview) branch. -As new Xcode 15 beta versions are released, the branch will be updated with any necessary fixes on a best effort basis. - -For more information on how to use the `visionos-preview` branch, see [Platform Support](https://github.com/aws-amplify/amplify-swift/tree/visionos-preview#platform-support). +visionOS support is currently in **preview** and can be used by using the latest [Amplify Release](https://github.com/aws-amplify/amplify-swift/releases). +As new Xcode and visionOS versions are released, the support will be updated with any necessary fixes on a best effort basis. diff --git a/src/pages/[platform]/build-a-backend/auth/modify-resources-with-cdk/index.mdx b/src/pages/[platform]/build-a-backend/auth/modify-resources-with-cdk/index.mdx index ceb39bdef66..3d5c3b8b143 100644 --- a/src/pages/[platform]/build-a-backend/auth/modify-resources-with-cdk/index.mdx +++ b/src/pages/[platform]/build-a-backend/auth/modify-resources-with-cdk/index.mdx @@ -57,6 +57,60 @@ cfnUserPool.policies = { }; ``` +## Override Cognito UserPool multi-factor authentication options +While Email MFA is not yet supported with `defineAuth`, this feature can be enabled by modifying the underlying CDK construct. + +Start by ensuring your `defineAuth` resource configuration includes a compatible account recovery option and a custom SES sender. + +```ts title="amplify/auth/resource.ts" +import { defineAuth } from "@aws-amplify/backend" + +/** + * Define and configure your auth resource + * @see https://docs.amplify.aws/gen2/build-a-backend/auth + */ +export const auth = defineAuth({ + loginWith: { + email: true, + phone: true, + }, + multifactor: { + mode: "OPTIONAL", + sms: true, + totp: false, + }, + // Important! The logic to resolve this value cannot determine whether email mfa is enabled when overriding the resource. + // Be sure to pick a recovery option appropriate for your application. + accountRecovery: "EMAIL_AND_PHONE_WITHOUT_MFA", + senders: { + email: { + fromEmail: "registrations@example.com", + }, + }, +}) +``` +Next, extend the underlying CDK construct by activating [Amazon Cognito's Advanced Security Features (ASF)](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pool-settings-advanced-security.html) and add `EMAIL_OTP` to the enabled MFA options. + +```ts title="amplify/backend.ts" +import { defineBackend } from "@aws-amplify/backend" +import { auth } from "./auth/resource" + +const backend = defineBackend({ + auth, +}) + +const { cfnUserPool } = backend.auth.resources.cfnResources + +// enable ASF +cfnUserPool.userPoolAddOns = { + advancedSecurityMode: "AUDIT", +} + +// add email mfa +// https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cognito-userpool.html#cfn-cognito-userpool-enabledmfas +cfnUserPool.enabledMfas = [...(cfnUserPool.enabledMfas || []), "EMAIL_OTP"] +``` + {/* token validity */} {/* BYO custom idp construct */} {/* extend auth/unauth roles */} diff --git a/src/pages/[platform]/build-a-backend/auth/set-up-auth/index.mdx b/src/pages/[platform]/build-a-backend/auth/set-up-auth/index.mdx index 1903fe1750c..3fae274bd6d 100644 --- a/src/pages/[platform]/build-a-backend/auth/set-up-auth/index.mdx +++ b/src/pages/[platform]/build-a-backend/auth/set-up-auth/index.mdx @@ -571,14 +571,12 @@ An application with Amplify libraries integrated and a minimum target of any of - **macOS 10.15**, using **Xcode 14.1** or later. - **tvOS 13.0**, using **Xcode 14.3** or later. - **watchOS 9.0**, using **Xcode 14.3** or later. -- **visionOS 1.0**, using **Xcode 15 beta 2** or later. (Preview support - see below for more details.) +- **visionOS 1.0**, using **Xcode 15** or later. (Preview support - see below for more details.) - - -visionOS support is currently in **preview** and can be used by targeting the [`visionos-preview`](https://github.com/aws-amplify/amplify-swift/tree/visionos-preview) branch. -As new Xcode 15 beta versions are released, the branch will be updated with any necessary fixes on a best effort basis. + -For more information on how to use the `visionos-preview` branch, see [Platform Support](https://github.com/aws-amplify/amplify-swift/tree/visionos-preview#platform-support). +visionOS support is currently in **preview** and can be used by using the latest [Amplify Release](https://github.com/aws-amplify/amplify-swift/releases). +As new Xcode and visionOS versions are released, the support will be updated with any necessary fixes on a best effort basis. diff --git a/src/pages/[platform]/build-a-backend/auth/sign-in-with-web-ui/index.mdx b/src/pages/[platform]/build-a-backend/auth/sign-in-with-web-ui/index.mdx index 5ba25b10f20..cda3ce8918a 100644 --- a/src/pages/[platform]/build-a-backend/auth/sign-in-with-web-ui/index.mdx +++ b/src/pages/[platform]/build-a-backend/auth/sign-in-with-web-ui/index.mdx @@ -130,14 +130,12 @@ RxAmplify.Auth.signInWithWebUI(this) -**Note:** Social sign-in (OAuth) functionality is only available in **iOS** and **macOS**. +**Note:** Social sign-in (OAuth) functionality is only available in **iOS**, **macOS** and **visionOS**. When configuring social sign-in, it's important to exercise caution when designating attributes as "required." Different social identity providers have varied scopes in terms of the information they respond back to Cognito with. User pool attributes that are initially set up as "required" cannot be changed later, and may require you to migrate the users or create a new user pool. -An application with a minimum target of **iOS 13.0** and/or **macOS 10.15** with Amplify libraries integrated, using **Xcode 14.1** or later. - For a full example, please follow the [project setup walkthrough](/[platform]/start/quickstart/). diff --git a/src/pages/[platform]/build-a-backend/data/connect-event-api/index.mdx b/src/pages/[platform]/build-a-backend/data/connect-event-api/index.mdx new file mode 100644 index 00000000000..777d84dc8c5 --- /dev/null +++ b/src/pages/[platform]/build-a-backend/data/connect-event-api/index.mdx @@ -0,0 +1,103 @@ +import { getCustomStaticPath } from '@/utils/getCustomStaticPath'; + +export const meta = { + title: 'Connect to AWS AppSync Events', + description: + 'Connect to AWS AppSync Events', + platforms: [ + 'angular', + 'javascript', + 'nextjs', + 'react', + 'react-native', + 'vue' + ] +}; + +export const getStaticPaths = async () => { + return getCustomStaticPath(meta.platforms); +}; + +export function getStaticProps(context) { + return { + props: { + platform: context.params.platform, + meta + } + }; +} + +This guide walks through how you can connect to AWS AppSync Events using the Amplify library. + +AWS AppSync Events lets you create secure and performant serverless WebSocket APIs that can broadcast real-time event data to millions of subscribers, without you having to manage connections or resource scaling. With this feature, you can build multi-user features such as a collaborative document editors, chat apps, and live polling systems. + +Learn more about AWS AppSync Events by visiting the [Developer Guide](https://docs.aws.amazon.com/appsync/latest/eventapi/event-api-welcome.html). + +## Connect to an Event API without an existing Amplify backend + +Before you begin, you will need: + +- An Event API created via the AWS Console +- Take note of: HTTP endpoint, region, API Key + +```tsx title="src/App.tsx" +import type { EventsChannel } from 'aws-amplify/data'; +import { useState, useEffect } from 'react'; +import { Amplify } from 'aws-amplify'; +import { events } from 'aws-amplify/data'; + +Amplify.configure({ + API: { + Events: { + endpoint: + 'https://abcdefghijklmnopqrstuvwxyz.appsync-api.us-east-1.amazonaws.com/event', + region: 'us-east-1', + defaultAuthMode: 'apiKey', + apiKey: 'da2-abcdefghijklmnopqrstuvwxyz' + } + } +}); + +export default function App() { + const [myEvents, setMyEvents] = useState([]); + + useEffect(() => { + let channel: EventsChannel; + + const connectAndSubscribe = async () => { + channel = await events.connect('default/channel'); + + channel.subscribe({ + next: (data) => { + console.log('received', data); + setMyEvents((prev) => [data, ...prev]); + }, + error: (err) => console.error('error', err) + }); + }; + + connectAndSubscribe(); + + return () => channel && channel.close(); + }, []); + + async function publishEvent() { + await events.post('default/channel', { some: 'data' }); + } + + return ( + <> + +
    + {myEvents.map((event, index) => ( +
  • {JSON.stringify(event)}
  • + ))} +
+ + ); +} +``` + +## Connect to an Event API with an existing Amplify backend + +Coming Soon diff --git a/src/pages/[platform]/build-a-backend/data/custom-business-logic/search-and-aggregate-queries/index.mdx b/src/pages/[platform]/build-a-backend/data/custom-business-logic/search-and-aggregate-queries/index.mdx index 6d0f35de055..c6e71d688d1 100644 --- a/src/pages/[platform]/build-a-backend/data/custom-business-logic/search-and-aggregate-queries/index.mdx +++ b/src/pages/[platform]/build-a-backend/data/custom-business-logic/search-and-aggregate-queries/index.mdx @@ -116,6 +116,7 @@ Create an OpenSearch instance with encryption. ```ts title="amplify/backend.ts" // highlight-start import * as opensearch from 'aws-cdk-lib/aws-opensearchservice'; +import { RemovalPolicy } from "aws-cdk-lib"; // highlight-end import { defineBackend } from '@aws-amplify/backend'; import { auth } from './auth/resource'; @@ -148,6 +149,8 @@ const openSearchDomain = new opensearch.Domain( { version: opensearch.EngineVersion.OPENSEARCH_2_11, nodeToNodeEncryption: true, + // set removalPolicy to DESTROY to make sure the open search domain is deleted on stack deletion. + removalPolicy: RemovalPolicy.DESTROY, encryptionAtRest: { enabled: true } @@ -155,6 +158,14 @@ const openSearchDomain = new opensearch.Domain( ); // highlight-end ``` + + +**Important considerations:** + +We recommend configuring the `removalPolicy` to destroy resources for sandbox environments. By default, OpenSearch instances are not deleted when you run `npx ampx sandbox delete`, as the default removal policy for stateful resources is set to retain the resource. + + + ## Step 3: Setting Up Zero ETL from DynamoDB to OpenSearch @@ -181,6 +192,7 @@ Get the `s3BucketArn` and `s3BucketName` values from storage resource as shown b ```ts title="amplify/backend.ts" import * as dynamodb from "aws-cdk-lib/aws-dynamodb"; import * as opensearch from "aws-cdk-lib/aws-opensearchservice"; +import { RemovalPolicy } from "aws-cdk-lib"; // highlight-next-line import * as iam from "aws-cdk-lib/aws-iam"; import { defineBackend } from "@aws-amplify/backend"; @@ -220,6 +232,8 @@ const openSearchDomain = new opensearch.Domain( { version: opensearch.EngineVersion.OPENSEARCH_2_11, nodeToNodeEncryption: true, + // set removalPolicy to DESTROY to make sure the open search domain is deleted on stack deletion. + removalPolicy: RemovalPolicy.DESTROY, encryptionAtRest: { enabled: true, }, @@ -307,6 +321,7 @@ Customize the `template_content` JSON-representation to define the data structur ```ts title="amplify/backend.ts" import * as dynamodb from "aws-cdk-lib/aws-dynamodb"; import * as opensearch from "aws-cdk-lib/aws-opensearchservice"; +import { RemovalPolicy } from "aws-cdk-lib"; import * as iam from "aws-cdk-lib/aws-iam"; import { defineBackend } from "@aws-amplify/backend"; import { auth } from "./auth/resource"; @@ -342,6 +357,8 @@ const openSearchDomain = new opensearch.Domain( { version: opensearch.EngineVersion.OPENSEARCH_2_11, nodeToNodeEncryption: true, + // set removalPolicy to DESTROY to make sure the open search domain is deleted on stack deletion. + removalPolicy: RemovalPolicy.DESTROY, encryptionAtRest: { enabled: true, }, @@ -444,6 +461,7 @@ The configuration is a data-prepper feature of OpenSearch. For specific document ```ts title="amplify/backend.ts" import * as dynamodb from "aws-cdk-lib/aws-dynamodb"; import * as opensearch from "aws-cdk-lib/aws-opensearchservice"; +import { RemovalPolicy } from "aws-cdk-lib"; import * as iam from "aws-cdk-lib/aws-iam"; import { defineBackend } from "@aws-amplify/backend"; import { auth } from "./auth/resource"; @@ -479,6 +497,8 @@ const openSearchDomain = new opensearch.Domain( { version: opensearch.EngineVersion.OPENSEARCH_2_11, nodeToNodeEncryption: true, + // set removalPolicy to DESTROY to make sure the open search domain is deleted on stack deletion. + removalPolicy: RemovalPolicy.DESTROY, encryptionAtRest: { enabled: true, }, @@ -636,6 +656,7 @@ Now, create the OSIS pipeline resource: ```ts title="amplify/backend.ts" import * as dynamodb from "aws-cdk-lib/aws-dynamodb"; import * as opensearch from "aws-cdk-lib/aws-opensearchservice"; +import { RemovalPolicy } from "aws-cdk-lib"; import * as iam from "aws-cdk-lib/aws-iam"; // highlight-start import * as osis from "aws-cdk-lib/aws-osis"; @@ -676,6 +697,8 @@ const openSearchDomain = new opensearch.Domain( { version: opensearch.EngineVersion.OPENSEARCH_2_11, nodeToNodeEncryption: true, + // set removalPolicy to DESTROY to make sure the open search domain is deleted on stack deletion. + removalPolicy: RemovalPolicy.DESTROY, encryptionAtRest: { enabled: true, }, diff --git a/src/pages/[platform]/build-a-backend/data/customize-authz/index.mdx b/src/pages/[platform]/build-a-backend/data/customize-authz/index.mdx index 0d844331604..9b35bcfc9eb 100644 --- a/src/pages/[platform]/build-a-backend/data/customize-authz/index.mdx +++ b/src/pages/[platform]/build-a-backend/data/customize-authz/index.mdx @@ -256,9 +256,49 @@ do {
+## IAM authorization + +All Amplify Gen 2 projects enable IAM authorization for data access. This ensures that the Amplify console's [data manager](/[platform]/build-a-backend/data/manage-with-amplify-console/) will be able to access your API. It also allows you to authorize other administrative or machine-to-machine access using your own IAM policies. See the [AWS AppSync Developer Guide](https://docs.aws.amazon.com/appsync/latest/devguide/security_iam_service-with-iam.html) for details on how AWS AppSync works with IAM. + +## Authorization on custom types + +Authorization rules are only supported on data models (model-level and field-level) and custom operations (queries, mutations and subscriptions). They are not fully supported on custom types, including custom types returned by custom operations. For example, consider a custom query that returns a custom type: + +```ts +const schema = a.schema({ + Counter: a.customType({ + value: a.integer(), + }) + .authorization(...), // <-- not supported + getCounter: a + .mutation() + .arguments({ + id: a.string().required(), + }) + .returns(a.ref("Counter")) + .handler( + a.handler.custom({ + entry: "./getCounter.js", + }) + ) + .authorization((allow) => [allow.authenticated()]), +}); + +export type Schema = ClientSchema; + +export const data = defineData({ + schema: schema, + authorizationModes: { + defaultAuthorizationMode: "userPool", + }, +}); +``` + +As you can see, the custom `Counter` type does not support the `.authorization()` modifier. Instead, behind the scenes, Amplify will add appropriate authorization rules to `Counter` to allow authenticated users to access it. That means that any signed-in user will be able to access the custom operation and all fields of the custom type. + -**Note**: Authorization rules are only supported on data models (model-level and field-level) and custom operations (queries, mutations and subscriptions). They are not fully supported on custom types. +**Note**: IAM authorization is not currently supported for custom operations that return custom types if `defaultAuthorizationMode` is not `iam`. See [GitHub issue #2929](https://github.com/aws-amplify/amplify-category-api/issues/2929) for details and suggested workarounds. diff --git a/src/pages/[platform]/build-a-backend/functions/grant-access-to-other-resources/index.mdx b/src/pages/[platform]/build-a-backend/functions/grant-access-to-other-resources/index.mdx index a9f6a34e7a9..29d60b9d7f9 100644 --- a/src/pages/[platform]/build-a-backend/functions/grant-access-to-other-resources/index.mdx +++ b/src/pages/[platform]/build-a-backend/functions/grant-access-to-other-resources/index.mdx @@ -119,7 +119,6 @@ However some constructs provide a `grant*` method to grant access to common poli ```ts title="amplify/backend.ts" import { defineBackend } from "@aws-amplify/backend" -import * as iam from "aws-cdk-lib/aws-iam" import * as sns from "aws-cdk-lib/aws-sns" import { weeklyDigest } from "./functions/weekly-digest/resource" diff --git a/src/pages/[platform]/build-a-backend/storage/data-usage/index.mdx b/src/pages/[platform]/build-a-backend/storage/data-usage/index.mdx index c21bf429637..24e3435c4d1 100644 --- a/src/pages/[platform]/build-a-backend/storage/data-usage/index.mdx +++ b/src/pages/[platform]/build-a-backend/storage/data-usage/index.mdx @@ -26,7 +26,7 @@ By utilizing the library, Amplify gathers API usage metrics from the AWS service Should you have any specific concerns or require additional information for the enhancement of your privacy manifest, please don't hesitate to reach out. -### Contact info +## Contact info | Data Type | Amplify Category | Purpose | Linked To Identity | Tracking | Provided by developer | | ------------------------------ | ------------------ | ------------------- | :------------------: | :--------: | :---------------------: | @@ -37,7 +37,7 @@ Should you have any specific concerns or require additional information for the | **Phone Number** | | | | | | | | Auth | App Functionality | ✅ | ❌ | ✅ | -### User Content +## User Content | Data Type | Amplify Category | Purpose | Linked To Identity | Tracking | Provided by developer | | ------------------------------ | ------------------ | ------------------- | :------------------: | :--------: | :---------------------: | @@ -47,7 +47,7 @@ Should you have any specific concerns or require additional information for the | **Audio Data** | | | | | | | | Predictions | App Functionality | ❌ | ❌ | ✅ | -### Identifiers +## Identifiers | Data Type | Amplify Category | Purpose | Linked To Identity | Tracking | Provided by developer | | ------------------------------ | ------------------ | ------------------- | :------------------: | :--------: | :---------------------: | @@ -58,7 +58,7 @@ Should you have any specific concerns or require additional information for the | | Auth | App Functionality | ✅ | ❌ | ❌ | | | Analytics | Analytics | ✅ | ❌ | ❌ | -### Other Data +## Other Data | Data Type | Amplify Category | Purpose | Linked To Identity | Tracking | Provided by developer | | ------------------------------ | ------------------ | ------------------- | :------------------: | :--------: | :---------------------: | @@ -94,28 +94,28 @@ Should you have any specific concerns or require additional information for the | | Auth | App Functionality | ✅ | ❌ | ❌ | -### Health and Fitness +## Health and Fitness No data is collected -### Financial Info +## Financial Info No data is collected -### Location +## Location No data is collected -### Sensitive Info +## Sensitive Info No data is collected -### Contacts +## Contacts No data is collected -### Browsing History +## Browsing History No data is collected -### Search History +## Search History No data is collected -### Diagnostics +## Diagnostics No data is collected ## Clearing data diff --git a/src/pages/[platform]/build-a-backend/storage/set-up-storage/index.mdx b/src/pages/[platform]/build-a-backend/storage/set-up-storage/index.mdx index 9f1d42046b8..9b18f2bccd1 100644 --- a/src/pages/[platform]/build-a-backend/storage/set-up-storage/index.mdx +++ b/src/pages/[platform]/build-a-backend/storage/set-up-storage/index.mdx @@ -404,11 +404,9 @@ An application with Amplify libraries integrated and a minimum target of any of For a full example, please follow the [project setup walkthrough](/[platform]/start/quickstart/). -{/* is the visionOS support callout relevant here? */} -visionOS support is currently in **preview** and can be used by targeting the [`visionos-preview`](https://github.com/aws-amplify/amplify-swift/tree/visionos-preview) branch. -As new Xcode 15 beta versions are released, the branch will be updated with any necessary fixes on a best effort basis. -For more information on how to use the `visionos-preview` branch, see [Platform Support](https://github.com/aws-amplify/amplify-swift/tree/visionos-preview#platform-support). +visionOS support is currently in **preview** and can be used by using the latest [Amplify Release](https://github.com/aws-amplify/amplify-swift/releases). +As new Xcode and visionOS versions are released, the support will be updated with any necessary fixes on a best effort basis. diff --git a/src/pages/[platform]/build-a-backend/troubleshooting/cdktoolkit-stack/index.mdx b/src/pages/[platform]/build-a-backend/troubleshooting/cdktoolkit-stack/index.mdx new file mode 100644 index 00000000000..651cc37a00e --- /dev/null +++ b/src/pages/[platform]/build-a-backend/troubleshooting/cdktoolkit-stack/index.mdx @@ -0,0 +1,83 @@ +import { getCustomStaticPath } from '@/utils/getCustomStaticPath'; + +export const meta = { + title: 'Troubleshoot CDKToolkit stack issues', + description: 'Addressing issues with CDKToolkit stack', + platforms: [ + "android", + 'angular', + "flutter", + 'javascript', + 'nextjs', + 'react', + 'react-native', + "swift", + 'vue' + ] +}; + +export function getStaticPaths() { + return getCustomStaticPath(meta.platforms); +} + +export function getStaticProps(context) { + return { + props: { + platform: context.params.platform, + meta + } + }; +} + +AWS Amplify requires your AWS account and region to be _bootstrapped_ in order to deploy resources into your account. Amplify uses the [AWS Cloud Development Kit (AWS CDK)](https://aws.amazon.com/cdk/) to scaffold backend resource configurations and orchestrate deployments by using the supplemental resources created by the process of bootstrapping. + +> _Bootstrapping_ is the process of preparing your AWS environment for usage with the AWS Cloud Development Kit (AWS CDK). Before you deploy a CDK stack into an AWS environment, the environment must first be bootstrapped. + +Learn more about bootstrapping by visiting the [AWS documentation for AWS CDK's concept of bootstrapping](https://docs.aws.amazon.com/cdk/v2/guide/bootstrapping.html). + +## Error bootstrapping account + +When deploying an Amplify app you may be redirected to the Amplify Console to complete bootstrapping for your current account ID and region. If this process encounters an error you will be prompted with the following message: + +```text title="Amplify Console" showLineNumbers={false} +Error bootstrapping account in region “”. There is an issue with the CDKToolkit stack which must be resolved manually. +``` + +This typically indicates one or more of the resources within the `CDKToolkit` stack has failed to create or update. Navigate to the [AWS CloudFormation console](https://us-east-1.console.aws.amazon.com/cloudformation/home), select your `CDKToolkit` stack, and select the "Events" tab to view resource events. Here you may identify issues with the corresponding [assets bucket](https://docs.aws.amazon.com/cdk/v2/guide/assets.html) or issues with the IAM roles used for deployments. + +You can mitigate by manually updating your `CDKToolkit` stack using the browser-based [AWS CloudShell](https://aws.amazon.com/cloudshell/): + +```bash title="AWS CloudShell" showLineNumbers={false} +cdk bootstrap aws://$(aws sts get-caller-identity --query Account --output text)/$AWS_REGION +``` + +Or by running `bootstrap` using the AWS CDK CLI from your terminal: + +```bash title="Terminal" showLineNumbers={false} +npx aws-cdk@latest bootstrap aws:/// +``` + +If you continue to experience this issue after applying the workaround noted above, please file an issue in the [GitHub repository for Amplify Backend](https://github.com/aws-amplify/amplify-backend). + +## Stack CDKToolkit already exists + +If you are deploying an Amplify app for the first time and have previously bootstrapped your AWS account to work with CDK, and you encounter the following error in the Amplify Console: + +```text title="Amplify Console" showLineNumbers={false} +Build error! +Stack [CDKToolkit] already exists +``` + +You can mitigate by manually updating your `CDKToolkit` stack using the browser-based [AWS CloudShell](https://aws.amazon.com/cloudshell/): + +```bash title="AWS CloudShell" showLineNumbers={false} +cdk bootstrap aws://$(aws sts get-caller-identity --query Account --output text)/$AWS_REGION +``` + +Or by running `bootstrap` using the AWS CDK CLI from your terminal: + +```bash title="Terminal" showLineNumbers={false} +npx aws-cdk@latest bootstrap aws:/// +``` + +If you continue to experience this issue after applying the workaround noted above, please file an issue in the [GitHub repository for Amplify Backend](https://github.com/aws-amplify/amplify-backend). diff --git a/src/pages/[platform]/build-a-backend/troubleshooting/stack-cdktoolkit-already-exists/index.mdx b/src/pages/[platform]/build-a-backend/troubleshooting/stack-cdktoolkit-already-exists/index.mdx deleted file mode 100644 index 12fd6e8ec8b..00000000000 --- a/src/pages/[platform]/build-a-backend/troubleshooting/stack-cdktoolkit-already-exists/index.mdx +++ /dev/null @@ -1,51 +0,0 @@ -import { getCustomStaticPath } from '@/utils/getCustomStaticPath'; - -export const meta = { - title: 'Troubleshoot "Stack CDKToolkit already exists"', - description: 'Addressing issues with upgrading CDKToolkit stacks', - platforms: [ - "android", - 'angular', - "flutter", - 'javascript', - 'nextjs', - 'react', - 'react-native', - "swift", - 'vue' - ] -}; - -export function getStaticPaths() { - return getCustomStaticPath(meta.platforms); -} - -export function getStaticProps(context) { - return { - props: { - platform: context.params.platform, - meta - } - }; -} - -If you are deploying an Amplify Gen 2 app for the first time and have previously [bootstrapped](https://docs.aws.amazon.com/cdk/v2/guide/bootstrapping.html) your AWS account to work with the [AWS Cloud Development Kit (AWS CDK)](https://aws.amazon.com/cdk/), and you encounter the following error in the Amplify Console: - -```console title="Amplify Console" showLineNumbers={false} -Build error! -Stack [CDKToolkit] already exists -``` - -You can mitigate by manually updating your `CDKToolkit` stack using the browser-based [AWS CloudShell](https://aws.amazon.com/cloudshell/): - -```bash title="AWS CloudShell" showLineNumbers={false} -cdk bootstrap aws://$(aws sts get-caller-identity --query Account --output text)/$AWS_REGION -``` - -Or by running `bootstrap` using the AWS CDK CLI from your terminal: - -```bash title="Terminal" showLineNumbers={false} -npx aws-cdk@latest bootstrap aws:/// -``` - -If you continue to experience this issue after applying the workaround noted above, please file an issue in the [GitHub repository for Amplify Backend](https://github.com/aws-amplify/amplify-backend). diff --git a/src/pages/[platform]/build-ui/figma-to-code/index.mdx b/src/pages/[platform]/build-ui/figma-to-code/index.mdx index ef2a1c94976..dd57cfe6f2a 100644 --- a/src/pages/[platform]/build-ui/figma-to-code/index.mdx +++ b/src/pages/[platform]/build-ui/figma-to-code/index.mdx @@ -39,7 +39,7 @@ This file contains the following pages: Please follow the README in our Figma file to learn how to create your components to optimize for code quality. -## Step 2: Run the Amplify UI Builder Figma plugin in dev mode +## Step 2: Run the Amplify UI Builder Figma plugin After you duplicate the Figma file, you run the Amplify UI Builder figma plugin in dev mode or non-dev mode to generate Amplify UI React code. diff --git a/src/pages/[platform]/build-ui/formbuilder/validations/index.mdx b/src/pages/[platform]/build-ui/formbuilder/validations/index.mdx index 49ddec5045b..140a334c9aa 100644 --- a/src/pages/[platform]/build-ui/formbuilder/validations/index.mdx +++ b/src/pages/[platform]/build-ui/formbuilder/validations/index.mdx @@ -54,7 +54,7 @@ Every form provides an `onValidate` event handler to provide additional validati onValidate={{ address: (value, validationResponse) => { const firstWord = value.split('')[0]; - if (!isNaN(str)) { + if (!isNaN(firstWord)) { // check if the first word is a number return { hasError: true, diff --git a/src/pages/[platform]/deploy-and-host/fullstack-branching/pr-previews/index.mdx b/src/pages/[platform]/deploy-and-host/fullstack-branching/pr-previews/index.mdx index 1481e7dcf98..99b0c39b910 100644 --- a/src/pages/[platform]/deploy-and-host/fullstack-branching/pr-previews/index.mdx +++ b/src/pages/[platform]/deploy-and-host/fullstack-branching/pr-previews/index.mdx @@ -40,7 +40,7 @@ With fullstack previews, you can set up ephemeral fullstack environments on ever 1. The pull request preview is deployed on Amplify and available at `pr-1.appid.amplifyapp.com`. 1. Once the pull request is merged into `main`, the request is closed and the fullstack environment is also automatically torn down. -### Prerequisites +## Prerequisites Before you get started, make sure you have the following: @@ -48,7 +48,7 @@ Before you get started, make sure you have the following: - Ensure that your git repository is private. For security purposes, fullstack previews are disabled for public repositories with Amplify backend templates. -### Enable fullstack previews +## Enable fullstack previews To enable fullstack web previews for your Amplify app, follow these steps: @@ -72,7 +72,7 @@ For **GitHub repositories only**, you can access your preview URL directly on th After the pull request is merged or closed, the preview URL is deleted and any ephemeral fullstack environment is also deleted. -### Share backend resources across Preview branches +## Share backend resources across Preview branches Fullstack previews allow teams a way to preview changes from pull requests before merging code to a production branch. Pull requests let you tell others about changes you’ve pushed to a branch in a repository and the changes can be reviewed by accessing the preview URL. When previews are enabled on a git branch, by default every pull request created against the git branch creates an ephemeral fullstack environment. diff --git a/src/pages/[platform]/start/manual-installation/index.mdx b/src/pages/[platform]/start/manual-installation/index.mdx index 49373ce94f2..8ad25647626 100644 --- a/src/pages/[platform]/start/manual-installation/index.mdx +++ b/src/pages/[platform]/start/manual-installation/index.mdx @@ -150,7 +150,7 @@ defineBackend({ You can also update an existing frontend app. To upgrade existing Amplify code-first DX (Gen 2) apps, use your Node.js package manager (for example, `npm`) to update relevant backend packages: ```bash title="Terminal" showLineNumbers={false} -npm update @aws-amplify/backend@latest @aws-amplify/backend-cli@latest +npm update @aws-amplify/backend @aws-amplify/backend-cli ``` ## Next steps diff --git a/src/pages/[platform]/start/quickstart/nextjs-app-router-client-components/index.mdx b/src/pages/[platform]/start/quickstart/nextjs-app-router-client-components/index.mdx index 086032158b9..1bbcda76efa 100644 --- a/src/pages/[platform]/start/quickstart/nextjs-app-router-client-components/index.mdx +++ b/src/pages/[platform]/start/quickstart/nextjs-app-router-client-components/index.mdx @@ -32,6 +32,12 @@ This Quickstart guide will walk you through how to build a task list application - [git](https://git-scm.com/) v2.14.1 or later - If you are new to these technologies, we recommend you go through the official [React](https://react.dev/learn/tutorial-tic-tac-toe), [Next.js](https://nextjs.org/docs/getting-started/installation), and [TypeScript](https://www.typescriptlang.org/docs/handbook/typescript-from-scratch.html) tutorials first. + + +**Note:** We currently support Next.js versions 13.5.0 up to 14.x. We are working to support version 15 or newer. + + + ## Deploy a fullstack app to AWS We've created a starter "To-do" application to help get started faster. First, you will create a repository in your GitHub account using our starter Next template. diff --git a/src/pages/gen1/[platform]/build-a-backend/graphqlapi/best-practice/query-with-sorting/index.mdx b/src/pages/gen1/[platform]/build-a-backend/graphqlapi/best-practice/query-with-sorting/index.mdx index 4d4d3ebe6e1..2985630ccf4 100644 --- a/src/pages/gen1/[platform]/build-a-backend/graphqlapi/best-practice/query-with-sorting/index.mdx +++ b/src/pages/gen1/[platform]/build-a-backend/graphqlapi/best-practice/query-with-sorting/index.mdx @@ -31,7 +31,7 @@ export function getStaticProps(context) { In this guide you will learn how to implement sorting in a GraphQL API. In our example, you will implement sorting results by date in either an ascending or descending order by implementing an additional data access pattern leveraging a DynamoDB Global Secondary Index using the `@index` GraphQL Transformer directive. -### Overview +## Overview To get started, let's start with a basic GraphQL schema for a Todo app: @@ -68,7 +68,7 @@ By default, the `listTodos` query will return the `items` array **unordered**. M To enable this, you can use the [@index](/gen1/[platform]/build-a-backend/graphqlapi/data-modeling/) directive. This directive will allow you to set a custom `sortKey` on any field in your API. -### Implementation +## Implementation In this example, you will enable sorting by the `createdAt` field. By default, Amplify will populate this `createdAt` field with a timestamp if none is passed in. diff --git a/src/pages/gen1/[platform]/build-a-backend/graphqlapi/best-practice/warehouse-management/index.mdx b/src/pages/gen1/[platform]/build-a-backend/graphqlapi/best-practice/warehouse-management/index.mdx index 2feb1fa7cc8..6ab8c656dc2 100644 --- a/src/pages/gen1/[platform]/build-a-backend/graphqlapi/best-practice/warehouse-management/index.mdx +++ b/src/pages/gen1/[platform]/build-a-backend/graphqlapi/best-practice/warehouse-management/index.mdx @@ -225,7 +225,7 @@ mutation createOrder { } ``` -### 1. Look up employee details by employee ID +## 1. Look up employee details by employee ID This can simply be done by querying the employee model with an employee ID, no `@primaryKey` or `@index` need to be explicitly specified to make this work. @@ -241,7 +241,7 @@ query getEmployee($id: ID!) { } ``` -### 2. Query employee details by employee name +## 2. Query employee details by employee name The `@index` `byName` on the `Employee` type makes this access-pattern feasible because under the hood an index is created and a query is used to match against the name field. You can use this query: @@ -259,11 +259,11 @@ query employeeByName($name: String!) { } ``` -### 3. Find an Employee’s phone number +## 3. Find an Employee’s phone number Either one of the previous queries would work to find an employee’s phone number as long as one has their ID or name. -### 4. Find a customer’s phone number +## 4. Find a customer’s phone number A similar query to those given above but on the Customer model would give you a customer’s phone number. @@ -275,7 +275,7 @@ query getCustomer($customerID: ID!) { } ``` -### 5. Get orders for a given customer within a given date range +## 5. Get orders for a given customer within a given date range There is a one-to-many relation that lets all the orders of a customer be queried. @@ -301,7 +301,7 @@ query getCustomerWithOrdersByDate($customerID: ID!) { } ``` -### 6. Show all open orders within a given date range across all customers +## 6. Show all open orders within a given date range across all customers The `@index` `byCustomerByStatusByDate` enables you to run a query that would work for this access pattern. @@ -327,7 +327,7 @@ query listCustomersWithOrdersByStatusDate { } ``` -### 7. See all employees hired recently +## 7. See all employees hired recently Having `@index(name: "newHire", fields: ["newHire", "id"])` on the `Employee` model allows one to query by whether an employee has been hired recently. @@ -361,7 +361,7 @@ query employeesNewHireByDate { } ``` -### 8. Find all employees working in a given warehouse +## 8. Find all employees working in a given warehouse This needs a one to many relationship from warehouses to employees. As can be seen from the `@hasMany` relationship in the `Warehouse` model, this relationship uses the `byWarehouse` index on the `Employee` model. The relevant query would look like this: @@ -382,7 +382,7 @@ query getWarehouse($warehouseID: ID!) { } ``` -### 9. Get all items on order for a given product +## 9. Get all items on order for a given product This access-pattern would use a one-to-many relation from products to orders. With this query you can get all orders of a given product: @@ -402,7 +402,7 @@ query getProductOrders($productID: ID!) { } ``` -### 10. Get current inventories for a product at all warehouses +## 10. Get current inventories for a product at all warehouses The query needed to get the inventories of a product in all warehouses would be: @@ -420,7 +420,7 @@ query getProductInventoryInfo($productID: ID!) { } ``` -### 11. Get customers by account representative +## 11. Get customers by account representative This uses a has-many relationship between account representatives and customers: @@ -440,7 +440,7 @@ query getCustomersForAccountRepresentative($representativeId: ID!) { } ``` -### 12. Get orders by account representative and date +## 12. Get orders by account representative and date As can be seen in the AccountRepresentative model this relationship uses the `byRepresentativebyDate` field on the `Order` model to create the connection needed. The query needed would look like this: @@ -464,11 +464,11 @@ query getOrdersForAccountRepresentative($representativeId: ID!) { } ``` -### 13. Get all items on order for a given product +## 13. Get all items on order for a given product This is the same as number 9. -### 14. Get all employees with a given job title +## 14. Get all employees with a given job title Using the `byTitle` `@index` makes this access pattern quite easy. @@ -485,7 +485,7 @@ query employeesByJobTitle { } ``` -### 15. Get inventory by product by warehouse +## 15. Get inventory by product by warehouse Here having the inventories be held in a separate model is particularly useful since this model can have its own partition key and sort key such that the inventories themselves can be queried as is needed for this access-pattern. @@ -515,7 +515,7 @@ query byWarehouseId($warehouseID: ID!) { } ``` -### 16. Get total product inventory +## 16. Get total product inventory How this would be done depends on the use case. If one just wants a list of all inventories in all warehouses, one could just run a list inventories on the Inventory model: @@ -531,7 +531,7 @@ query listInventorys { } ``` -### 17. Get sales representatives ranked by order total and sales period +## 17. Get sales representatives ranked by order total and sales period The sales period is either a date range or maybe even a month or week. Therefore you can set the sales period as a string and query using the combination of `salesPeriod` and `orderTotal`. You can also set the `sortDirection` in order to get the return values from largest to smallest: diff --git a/src/pages/gen1/[platform]/build-a-backend/graphqlapi/customize-authorization-rules/index.mdx b/src/pages/gen1/[platform]/build-a-backend/graphqlapi/customize-authorization-rules/index.mdx index 6735fe03231..5baab1fa45b 100644 --- a/src/pages/gen1/[platform]/build-a-backend/graphqlapi/customize-authorization-rules/index.mdx +++ b/src/pages/gen1/[platform]/build-a-backend/graphqlapi/customize-authorization-rules/index.mdx @@ -53,7 +53,7 @@ type Todo In the example above, everyone (`public`) can read every Todo but owner (authenticated users) can create, read, update, and delete their own Todos. -### Global authorization rule (only for getting started) +## Global authorization rule (only for getting started) To help you get started, there's a global authorization rule defined when you create a new GraphQL schema. For production environments, remove the global authorization rule and apply rules on each model instead. diff --git a/src/pages/gen1/[platform]/build-a-backend/restapi/gen-ai/index.mdx b/src/pages/gen1/[platform]/build-a-backend/restapi/gen-ai/index.mdx index 7a15b46f8f5..9c637be4da4 100644 --- a/src/pages/gen1/[platform]/build-a-backend/restapi/gen-ai/index.mdx +++ b/src/pages/gen1/[platform]/build-a-backend/restapi/gen-ai/index.mdx @@ -41,7 +41,7 @@ With Amplify and Amazon Bedrock, you can create a generative AI application easi For this we will use React and Next.js to take advantage of the full managed hosting of Next.js server-side rendering (SSR) capabilities in Amplify Hosting. The first step is to create a new Next.js project using yarn, npm, pnpm, or Bun. ```bash -npx create-next-app@latest +npx create-next-app@14 ``` ```bash diff --git a/src/pages/gen1/[platform]/start/getting-started/setup/index.mdx b/src/pages/gen1/[platform]/start/getting-started/setup/index.mdx index a22cb3014bb..eb11648e65b 100644 --- a/src/pages/gen1/[platform]/start/getting-started/setup/index.mdx +++ b/src/pages/gen1/[platform]/start/getting-started/setup/index.mdx @@ -223,6 +223,9 @@ cd amplify-app This tutorial is built using the [Next.js App Router](https://nextjs.org/docs/app/building-your-application/routing). +**NOTE:** Amplify JS v6 supports Next.js with the version range: `>=13.5.0 <15.0.0`. +Ensure you have the correct version to integrate with Amplify. + To set up the project, you'll first create a new Next.js app with [Create Next App](https://nextjs.org/docs/api-reference/create-next-app), a simple CLI tool that enables you to quickly start building a new Next.js application, with everything set up for you. You'll then add Amplify and initialize a new project. diff --git a/src/pages/gen1/[platform]/tools/cli-legacy/relational-databases/index.mdx b/src/pages/gen1/[platform]/tools/cli-legacy/relational-databases/index.mdx index 51219f3fa79..c335921c24b 100644 --- a/src/pages/gen1/[platform]/tools/cli-legacy/relational-databases/index.mdx +++ b/src/pages/gen1/[platform]/tools/cli-legacy/relational-databases/index.mdx @@ -141,6 +141,6 @@ SELECT * FROM Customers; ![SQL Results](/images/sql-results.png) -### How does this work? +## How does this work? The `add-graphql-datasource` will add a custom stack to your project that provides a basic set of functionality for working with an existing data source. You can find the new stack in the `stacks/` directory, a set of new resolvers in the `resolvers/` directory, and will also find a few additions to your `schema.graphql`. You may edit details in the custom stack and/or resolver files without worry. You may run `add-graphql-datasource` again to update your project with changes in the database but be careful as these will overwrite any existing templates in the `stacks/` or `resolvers/` directories. When using multiple environment with the Amplify CLI, you will be asked to configure the data source once per environment. diff --git a/src/pages/gen1/[platform]/tools/cli-legacy/searchable-directive/index.mdx b/src/pages/gen1/[platform]/tools/cli-legacy/searchable-directive/index.mdx index 888301aefcf..20e3ac3c14f 100644 --- a/src/pages/gen1/[platform]/tools/cli-legacy/searchable-directive/index.mdx +++ b/src/pages/gen1/[platform]/tools/cli-legacy/searchable-directive/index.mdx @@ -38,7 +38,7 @@ export function getStaticProps(context) { The `@searchable` directive handles streaming the data of an `@model` object type to the Amazon OpenSearch Service and configures search resolvers that search that information. -> **Migration warning**: You might observe duplicate records on search operations, if you deployed your GraphQL schema using CLI version older than 4.14.1 and have thereafter updated your schema & deployed the changes with a CLI version between 4.14.1 - 4.16.1. Please use this Python [script](https://github.com/aws-amplify/amplify-category-api/blob/release-api-plugin-stable/packages/graphql-elasticsearch-transformer/scripts/ddb_to_es.py) to remove the duplicate records from your OpenSearch cluster. [This script](https://github.com/aws-amplify/amplify-category-api/blob/release-api-plugin-stable/packages/graphql-elasticsearch-transformer/scripts/ddb_to_es.py) indexes data from your DynamoDB Table to your OpenSearch Cluster. View an example of how to call the script with the following parameters [here](https://aws-amplify.github.io/docs/cli-toolchain/graphql#example-of-calling-the-script). +> **Migration warning**: You might observe duplicate records on search operations, if you deployed your GraphQL schema using CLI version older than 4.14.1 and have thereafter updated your schema & deployed the changes with a CLI version between 4.14.1 - 4.16.1. Please use this Python [script](https://github.com/aws-amplify/amplify-category-api/blob/release-api-plugin-stable/packages/graphql-elasticsearch-transformer/scripts/ddb_to_es.py) to remove the duplicate records from your OpenSearch cluster. [This script](https://github.com/aws-amplify/amplify-category-api/blob/release-api-plugin-stable/packages/graphql-elasticsearch-transformer/scripts/ddb_to_es.py) indexes data from your DynamoDB Table to your OpenSearch Cluster. [View an example of how to call the script](#backfill-your-opensearch-index-from-your-dynamodb-table). > **Billing warning**: `@searchable` incurs an additional cost depending on instance size. For more information refer to the [Amazon OpenSearch service pricing](https://aws.amazon.com/elasticsearch-service/pricing/). diff --git a/src/pages/gen1/[platform]/tools/cli-legacy/storage/index.mdx b/src/pages/gen1/[platform]/tools/cli-legacy/storage/index.mdx index b426e9839b0..087d4f38045 100644 --- a/src/pages/gen1/[platform]/tools/cli-legacy/storage/index.mdx +++ b/src/pages/gen1/[platform]/tools/cli-legacy/storage/index.mdx @@ -48,7 +48,7 @@ Note: Complex objects are not supported by DataStore-enabled GraphQL APIs. -### Basics +## Basics At a minimum the steps to add S3 Object support are as follows: diff --git a/src/pages/gen1/[platform]/tools/cli/migration/list-nullability/index.mdx b/src/pages/gen1/[platform]/tools/cli/migration/list-nullability/index.mdx index 60d16f2c934..148b05d010e 100644 --- a/src/pages/gen1/[platform]/tools/cli/migration/list-nullability/index.mdx +++ b/src/pages/gen1/[platform]/tools/cli/migration/list-nullability/index.mdx @@ -29,7 +29,7 @@ export function getStaticProps(context) { }; } -### **What is changing?** +## **What is changing?** Amplify CLI 5.1.2 has updated the codegen process to correctly set the optionality for types in models. @@ -53,11 +53,11 @@ In this example, there are four fields with different combinations of optionalit > The list component in this example is a String type, however, this applies for other types as well such as Int, Bool, and embedded types that you define yourself. -### **Why are we introducing this change?** +## **Why are we introducing this change?** This is to align the optionality of the generated Swift models as closely as possible to the type defined in the schema. -### **Who is impacted?** +## **Who is impacted?** Developers building an iOS app with Amplify DataStore or Amplify API generates Swift models by running the command `amplify codegen models`. @@ -92,11 +92,11 @@ The difference between the current and previous code: - `optionalElementRequiredList` - the list component was required and is now optional. The list was optional and is now required - `optionalElementOptionalList` - the list component was required and is now optional. -### **When do I have to upgrade?** +## **When do I have to upgrade?** This is behind a feature flag in Amplify CLI 5.1.2 and will be deprecated by November 1st, 2021. Developers with existing apps should upgrade to the latest CLI, set the feature flag, and update their app code or their schema (see recommendations following) to account for the change in optionality of the types. Developers building a new app will automatically generate code with the latest changes and no action is required. -### **Where do I make these changes?** +## **Where do I make these changes?** 1. Update Amplify CLI to the latest version diff --git a/src/pages/gen1/[platform]/tools/cli/plugins/authoring/index.mdx b/src/pages/gen1/[platform]/tools/cli/plugins/authoring/index.mdx index 59faf7c2e05..77cf0453b93 100644 --- a/src/pages/gen1/[platform]/tools/cli/plugins/authoring/index.mdx +++ b/src/pages/gen1/[platform]/tools/cli/plugins/authoring/index.mdx @@ -34,13 +34,13 @@ export function getStaticProps(context) { The Amplify CLI provides the command `amplify plugin init` (with alias `amplify plugin new`) for the development of plugins. This command first collects requirements, and then creates the skeleton of the plugin package for you to start the development. The newly created plugin is added to your local Amplify CLI plugin platform, so you can conveniently test its functionalities while it is being developed. It can be easily removed from the local plugin platform with the `amplify plugin remove` command, and added back with the `amplify plugin add` command. -### Step 1: Install Amplify CLI +## Step 1: Install Amplify CLI import all0 from "/src/fragments/cli-install-block.mdx"; -### Step 2: Initialize plugin +## Step 2: Initialize plugin ```bash amplify plugin init @@ -48,7 +48,7 @@ amplify plugin init You will be prompted to enter the plugin name, then select the plugin type, and event subscriptions. The CLI will then create a plugin package for you and add it to the local Amplify CLI plugin platform. -### Step 3: Test your plugin +## Step 3: Test your plugin The newly created plugin package is already added to the local Amplify CLI, so you can start testing it immediately. Let's say you have chosen to use the default plugin name: `my-amplify-plugin` @@ -63,11 +63,11 @@ At this point, there are only two sub commands in the plugin package, `help` and From here, you can start to develop the plugin package. See below for the detailed explanation of the package structure. -### Step 4: Publish to npm +## Step 4: Publish to npm After the completion of one development cycle and you are ready to release your plugin to the public, you can publish it to the npm: [https://docs.npmjs.com/getting-started/publishing-npm-packages](https://docs.npmjs.com/getting-started/publishing-npm-packages) -### Step 5: Install and Use +## Step 5: Install and Use Once your plugin is published to the npm, other developers can install and use it diff --git a/src/pages/gen1/[platform]/tools/cli/reference/diagnose/index.mdx b/src/pages/gen1/[platform]/tools/cli/reference/diagnose/index.mdx index f58f1e8b454..76dbcaa86a5 100644 --- a/src/pages/gen1/[platform]/tools/cli/reference/diagnose/index.mdx +++ b/src/pages/gen1/[platform]/tools/cli/reference/diagnose/index.mdx @@ -54,7 +54,7 @@ After the zip file is transmitted successfully the current project’s unique id Project Identifier: 56b5981ed6cf5caad90fb2f8aed150e2 ``` -### Automatic Report Sharing +## Automatic Report Sharing To help improve Amplify CLI you can opt in to automatically share your project configurations with Amplify CLI on failures. The is a project level setting and can be toggled per project. The project can opt out by running diff --git a/src/pages/gen1/[platform]/tools/cli/reference/usage-data/index.mdx b/src/pages/gen1/[platform]/tools/cli/reference/usage-data/index.mdx index 49ec79ddd1f..0103832c29a 100644 --- a/src/pages/gen1/[platform]/tools/cli/reference/usage-data/index.mdx +++ b/src/pages/gen1/[platform]/tools/cli/reference/usage-data/index.mdx @@ -36,7 +36,7 @@ At AWS, we develop and launch services based on what we learn from interactions Amplify CLI sends anonymized information such as system metadata, usage metrics, and errors. The data is marked for deletion in a year from the point of it being collected. Amplify CLI does **not** collect personally identifiable information such as email addresses, usernames, keys, ARNs or project information such as names, ARNs, and keys. -### Manage usage data collection for your Amplify CLI Instance +## Manage usage data collection for your Amplify CLI Instance **Disable usage data collection** diff --git a/src/pages/gen1/[platform]/tools/cli/teams/index.mdx b/src/pages/gen1/[platform]/tools/cli/teams/index.mdx index bb729b6a58b..61751d307fa 100644 --- a/src/pages/gen1/[platform]/tools/cli/teams/index.mdx +++ b/src/pages/gen1/[platform]/tools/cli/teams/index.mdx @@ -56,11 +56,11 @@ You can alternatively, have developers setup their own isolated replica of these This workflow can be used to share complete Amplify projects with people outside of your organization as well by committing the project into a Git repository. If you are doing this remove (or add to the `.gitignore` file) the **team-provider-info.json** which is located in the `amplify` directory. You can learn more about this file [here](/gen1/[platform]/tools/cli/teams/shared/#sharing-projects-outside-the-team). -### Continuous deployment and Hosting +## Continuous deployment and Hosting The Amplify CLI supports basic web application hosting with Amazon S3 and CloudFront. You can use the multi-environments feature with the Amplify Console for a fully managed web application hosting and continuous deployment solution. For more information please learn more in the [official documentation](https://docs.aws.amazon.com/amplify/latest/userguide/multi-environments.html). -### Setting up prod and dev environments +## Setting up prod and dev environments Create a Git repository for your project if you haven't already. It is recommended managing separate Git branches for different environments (try to have the same branch name as your environment name to avoid confusion). From the root of your project, execute the following commands: