From 2faf352daa173d6d6f2a9807efbf547b0a461640 Mon Sep 17 00:00:00 2001
From: Harsh <6162866+harsh62@users.noreply.github.com>
Date: Tue, 10 Mar 2026 11:32:46 -0400
Subject: [PATCH 1/5] feat: add export or view page as MD
---
.gitignore | 1 +
next-env.d.ts | 3 +-
package.json | 2 +-
public/ai/llms-full.txt | 71043 ++++++++++++++++
public/ai/llms.txt | 596 +
src/components/Layout/Layout.tsx | 15 +-
src/components/MarkdownMenu/MarkdownMenu.tsx | 164 +
.../__tests__/MarkdownMenu.test.tsx | 149 +
src/components/MarkdownMenu/index.ts | 1 +
src/styles/markdown-menu.scss | 55 +
src/styles/styles.scss | 1 +
tasks/__tests__/generate-llms-txt.test.ts | 273 +
tasks/generate-llms-txt.mjs | 383 +
tasks/postBuildTasks.mjs | 2 +
14 files changed, 72685 insertions(+), 3 deletions(-)
create mode 100644 public/ai/llms-full.txt
create mode 100644 public/ai/llms.txt
create mode 100644 src/components/MarkdownMenu/MarkdownMenu.tsx
create mode 100644 src/components/MarkdownMenu/__tests__/MarkdownMenu.test.tsx
create mode 100644 src/components/MarkdownMenu/index.ts
create mode 100644 src/styles/markdown-menu.scss
create mode 100644 tasks/__tests__/generate-llms-txt.test.ts
create mode 100644 tasks/generate-llms-txt.mjs
diff --git a/.gitignore b/.gitignore
index bc614fc0ec5..8c4c8088eab 100644
--- a/.gitignore
+++ b/.gitignore
@@ -71,6 +71,7 @@ public/**/**/nextImageExportOptimizer/
public/next-image-export-optimizer-hashes.json
src/directory/directory.json
src/directory/flatDirectory.json
+public/ai/pages/
src/references/raw-references.json
.yarn/*
diff --git a/next-env.d.ts b/next-env.d.ts
index a4a7b3f5cfa..ddb76465e52 100644
--- a/next-env.d.ts
+++ b/next-env.d.ts
@@ -1,5 +1,6 @@
///
///
+import "./client/www/next-build/dev/types/routes.d.ts";
// NOTE: This file should not be edited
-// see https://nextjs.org/docs/pages/building-your-application/configuring/typescript for more information.
+// see https://nextjs.org/docs/pages/api-reference/config/typescript for more information.
diff --git a/package.json b/package.json
index 5fbdba2acd3..83a257a949f 100644
--- a/package.json
+++ b/package.json
@@ -112,7 +112,7 @@
"refresh": "yarn clean && yarn",
"test:unit": "jest --projects jest.unit.config.js --coverage",
"test:e2e": "jest --projects e2e/jest.e2e.config.js",
- "dev": "yarn prebuild && next dev --webpack",
+ "dev": "yarn prebuild && node tasks/generate-llms-txt.mjs && next dev --webpack",
"spellcheck": "cspell \"src/**/*.mdx\" --no-progress",
"spellcheck-diff": "git diff --name-only --cached | awk \"/src.*\\.mdx/{print}\" | npx cspell --no-must-find-files --file-list stdin",
"build": "yarn prebuild && yarn next-build && yarn postbuild",
diff --git a/public/ai/llms-full.txt b/public/ai/llms-full.txt
new file mode 100644
index 00000000000..c99b3f2ba85
--- /dev/null
+++ b/public/ai/llms-full.txt
@@ -0,0 +1,71043 @@
+# AWS Amplify Gen 2 Documentation (Full)
+
+> Complete documentation export for AI coding assistants.
+> Generated: 2026-03-10
+
+## Table of Contents
+
+- [How Amplify works](#how-amplify-works)
+- [Concepts](#how-amplify-works-concepts)
+- [FAQ](#how-amplify-works-faq)
+- [Get started](#start)
+- [Quickstart](#start-quickstart)
+- [Next.js Pages Router](#start-quickstart-nextjs-pages-router)
+- [Next.js App Router](#start-quickstart-nextjs-app-router-client-components)
+- [Configure AWS for local development](#start-account-setup)
+- [Manual installation](#start-manual-installation)
+- [Connect to AWS resources](#start-connect-to-aws-resources)
+- [Kotlin Coroutines support](#start-kotlin-coroutines)
+- [Gen 2 for Gen 1 customers](#start-migrate-to-gen2)
+- [Platform setup](#start-platform-setup)
+- [Build with AI assistants](#start-mcp-server)
+- [Set up AWS MCP Server](#start-mcp-server-set-up-mcp)
+- [Guided workflows](#start-mcp-server-amplify-workflows)
+- [Build & connect backend](#build-a-backend)
+- [Authentication](#build-a-backend-auth)
+- [Set up Amplify Auth](#build-a-backend-auth-set-up-auth)
+- [Concepts](#build-a-backend-auth-concepts)
+- [Usernames](#build-a-backend-auth-concepts-usernames)
+- [Email](#build-a-backend-auth-concepts-email)
+- [Phone](#build-a-backend-auth-concepts-phone)
+- [Passwordless](#build-a-backend-auth-concepts-passwordless)
+- [User attributes](#build-a-backend-auth-concepts-user-attributes)
+- [User groups](#build-a-backend-auth-concepts-user-groups)
+- [Multi-factor authentication](#build-a-backend-auth-concepts-multi-factor-authentication)
+- [External identity providers](#build-a-backend-auth-concepts-external-identity-providers)
+- [Guest access](#build-a-backend-auth-concepts-guest-access)
+- [Tokens and credentials](#build-a-backend-auth-concepts-tokens-and-credentials)
+- [Connect your frontend](#build-a-backend-auth-connect-your-frontend)
+- [Using the Authenticator](#build-a-backend-auth-connect-your-frontend-using-the-authenticator)
+- [Sign-up](#build-a-backend-auth-connect-your-frontend-sign-up)
+- [Sign-in](#build-a-backend-auth-connect-your-frontend-sign-in)
+- [Switching authentication flows](#build-a-backend-auth-connect-your-frontend-switching-authentication-flows)
+- [Sign-out](#build-a-backend-auth-connect-your-frontend-sign-out)
+- [Manage user sessions](#build-a-backend-auth-connect-your-frontend-manage-user-sessions)
+- [Manage user attributes](#build-a-backend-auth-connect-your-frontend-manage-user-attributes)
+- [Listen to auth events](#build-a-backend-auth-connect-your-frontend-listen-to-auth-events)
+- [Delete user account](#build-a-backend-auth-connect-your-frontend-delete-user-account)
+- [Multi-step sign-in](#build-a-backend-auth-connect-your-frontend-multi-step-sign-in)
+- [Manage users](#build-a-backend-auth-manage-users)
+- [With admin actions](#build-a-backend-auth-manage-users-with-admin-actions)
+- [Manage passwords](#build-a-backend-auth-manage-users-manage-passwords)
+- [Manage WebAuthn credentials](#build-a-backend-auth-manage-users-manage-webauthn-credentials)
+- [Manage devices](#build-a-backend-auth-manage-users-manage-devices)
+- [Manage users with Amplify console](#build-a-backend-auth-manage-users-with-amplify-console)
+- [Customize auth lifecycle](#build-a-backend-auth-customize-auth-lifecycle)
+- [Custom auth flows](#build-a-backend-auth-customize-auth-lifecycle-custom-auth-flows)
+- [Email customization](#build-a-backend-auth-customize-auth-lifecycle-email-customization)
+- [Triggers](#build-a-backend-auth-customize-auth-lifecycle-triggers)
+- [Enable sign-in with web UI](#build-a-backend-auth-sign-in-with-web-ui)
+- [Uninstalling the app](#build-a-backend-auth-app-uninstall)
+- [Data usage policy information](#build-a-backend-auth-data-usage-policy)
+- [Examples](#build-a-backend-auth-examples)
+- [Microsoft Entra ID (SAML)](#build-a-backend-auth-examples-microsoft-entra-id-saml)
+- [Grant access to auth resources](#build-a-backend-auth-grant-access-to-auth-resources)
+- [Modify Amplify-generated Cognito resources with CDK](#build-a-backend-auth-modify-resources-with-cdk)
+- [Moving to production](#build-a-backend-auth-moving-to-production)
+- [Advanced workflows](#build-a-backend-auth-advanced-workflows)
+- [Use existing Cognito resources](#build-a-backend-auth-use-existing-cognito-resources)
+- [Use AWS SDK](#build-a-backend-auth-use-aws-sdk)
+- [API References](#build-a-backend-auth-reference)
+- [Data](#build-a-backend-data)
+- [Set up Amplify Data](#build-a-backend-data-set-up-data)
+- [Connect your app code to API](#build-a-backend-data-connect-to-API)
+- [Create, update, and delete application data](#build-a-backend-data-mutate-data)
+- [Read application data](#build-a-backend-data-query-data)
+- [Subscribe to real-time events](#build-a-backend-data-subscribe-data)
+- [Customize your data model](#build-a-backend-data-data-modeling)
+- [Add fields to data model](#build-a-backend-data-data-modeling-add-fields)
+- [Modeling relationships](#build-a-backend-data-data-modeling-relationships)
+- [Customize data model identifiers](#build-a-backend-data-data-modeling-identifiers)
+- [Customize secondary indexes](#build-a-backend-data-data-modeling-secondary-index)
+- [Disable Operations](#build-a-backend-data-data-modeling-disable-operations)
+- [Customize your auth rules](#build-a-backend-data-customize-authz)
+- [Public data access](#build-a-backend-data-customize-authz-public-data-access)
+- [Per-user/per-owner data access](#build-a-backend-data-customize-authz-per-user-per-owner-data-access)
+- [Multi-user data access](#build-a-backend-data-customize-authz-multi-user-data-access)
+- [Signed-in user data access](#build-a-backend-data-customize-authz-signed-in-user-data-access)
+- [User group-based data access](#build-a-backend-data-customize-authz-user-group-based-data-access)
+- [Custom data access using Lambda functions](#build-a-backend-data-customize-authz-custom-data-access-patterns)
+- [Use OpenID Connect as an authorization provider](#build-a-backend-data-customize-authz-using-oidc-authorization-provider)
+- [Configure custom identity and group claims](#build-a-backend-data-customize-authz-configure-custom-identity-and-group-claim)
+- [Grant Lambda function access to API and Data](#build-a-backend-data-customize-authz-grant-lambda-function-access-to-api)
+- [Add custom queries and mutations](#build-a-backend-data-custom-business-logic)
+- [Connect to Amazon OpenSearch for search and aggregate queries](#build-a-backend-data-custom-business-logic-search-and-aggregate-queries)
+- [Connect to Amazon EventBridge to send and receive events](#build-a-backend-data-custom-business-logic-connect-eventbridge-datasource)
+- [Connect to Amazon Polly for Text-To-Speech APIs](#build-a-backend-data-custom-business-logic-connect-amazon-polly)
+- [Connect to Amazon Bedrock for generative AI use cases](#build-a-backend-data-custom-business-logic-connect-bedrock)
+- [Connect to Amazon Rekognition for Image Analysis APIs](#build-a-backend-data-custom-business-logic-connect-amazon-rekognition)
+- [Connect to Amazon Translate for language translation APIs](#build-a-backend-data-custom-business-logic-connect-amazon-translate)
+- [Connect to an external HTTP endpoint](#build-a-backend-data-custom-business-logic-connect-http-datasource)
+- [Batch DynamoDB Operations](#build-a-backend-data-custom-business-logic-batch-ddb-operations)
+- [Working with files/attachments](#build-a-backend-data-working-with-files)
+- [Add custom real-time subscriptions](#build-a-backend-data-custom-subscription)
+- [Connect to existing data sources](#build-a-backend-data-connect-to-existing-data-sources)
+- [Connect your app to existing MySQL and PostgreSQL database](#build-a-backend-data-connect-to-existing-data-sources-connect-postgres-mysql-database)
+- [Connect to external Amazon DynamoDB data sources](#build-a-backend-data-connect-to-existing-data-sources-connect-external-ddb-table)
+- [Connect to data from Server-side Runtimes](#build-a-backend-data-connect-from-server-runtime)
+- [Next.js server runtime](#build-a-backend-data-connect-from-server-runtime-nextjs-server-runtime)
+- [Nuxt.js server runtime](#build-a-backend-data-connect-from-server-runtime-nuxtjs-server-runtime)
+- [Optimistic UI](#build-a-backend-data-optimistic-ui)
+- [Connect to AWS AppSync Events](#build-a-backend-data-connect-event-api)
+- [Modify Amplify-generated AWS resources](#build-a-backend-data-override-resources)
+- [Manage Data with Amplify console](#build-a-backend-data-manage-with-amplify-console)
+- [AWS AppSync Apollo Extensions](#build-a-backend-data-aws-appsync-apollo-extensions)
+- [Enable logging](#build-a-backend-data-enable-logging)
+- [Field-level validation](#build-a-backend-data-field-level-validation)
+- [API References](#build-a-backend-data-reference)
+- [Storage](#build-a-backend-storage)
+- [Set up Storage](#build-a-backend-storage-set-up-storage)
+- [Customize authorization rules](#build-a-backend-storage-authorization)
+- [Upload files](#build-a-backend-storage-upload-files)
+- [Download files](#build-a-backend-storage-download-files)
+- [List file properties](#build-a-backend-storage-list-files)
+- [Remove files](#build-a-backend-storage-remove-files)
+- [Copy files](#build-a-backend-storage-copy-files)
+- [Listen to storage events](#build-a-backend-storage-lambda-triggers)
+- [Extend S3 resources](#build-a-backend-storage-extend-s3-resources)
+- [Use AWS SDK for S3 APIs](#build-a-backend-storage-use-aws-sdk)
+- [Use Amplify Storage with any S3 bucket](#build-a-backend-storage-use-with-custom-s3)
+- [Data usage policy](#build-a-backend-storage-data-usage)
+- [Manage files with Amplify console](#build-a-backend-storage-manage-with-amplify-console)
+- [API References](#build-a-backend-storage-reference)
+- [Functions](#build-a-backend-functions)
+- [Set up a Function](#build-a-backend-functions-set-up-function)
+- [Environment variables and secrets](#build-a-backend-functions-environment-variables-and-secrets)
+- [Configure Functions](#build-a-backend-functions-configure-functions)
+- [Configure client library](#build-a-backend-functions-configure-client-library)
+- [Scheduling Functions](#build-a-backend-functions-scheduling-functions)
+- [Streaming logs](#build-a-backend-functions-streaming-logs)
+- [Lambda Layers](#build-a-backend-functions-add-lambda-layers)
+- [Grant access to other resources](#build-a-backend-functions-grant-access-to-other-resources)
+- [Examples](#build-a-backend-functions-examples)
+- [Email domain filtering](#build-a-backend-functions-examples-email-domain-filtering)
+- [Add user to group](#build-a-backend-functions-examples-add-user-to-group)
+- [Create a user profile record](#build-a-backend-functions-examples-create-user-profile-record)
+- [Override ID token claims](#build-a-backend-functions-examples-override-token)
+- [User attribute validation](#build-a-backend-functions-examples-user-attribute-validation)
+- [Custom message](#build-a-backend-functions-examples-custom-message)
+- [Google reCAPTCHA challenge](#build-a-backend-functions-examples-google-recaptcha-challenge)
+- [Amazon Kinesis Data Streams](#build-a-backend-functions-examples-kinesis-stream)
+- [DynamoDB Streams](#build-a-backend-functions-examples-dynamo-db-stream)
+- [S3 Upload confirmation](#build-a-backend-functions-examples-s3-upload-confirmation)
+- [Custom Auth Challenge](#build-a-backend-functions-examples-custom-auth-flows)
+- [Modify Amplify-generated Lambda resources with CDK](#build-a-backend-functions-modify-resources-with-cdk)
+- [Custom functions](#build-a-backend-functions-custom-functions)
+- [Server-Side Rendering](#build-a-backend-server-side-rendering)
+- [Next.js App Router (Server Components)](#build-a-backend-server-side-rendering-nextjs-app-router-server-components)
+- [Use Amplify categories APIs from Nuxt 3](#build-a-backend-server-side-rendering-nuxt)
+- [Add any AWS service](#build-a-backend-add-aws-services)
+- [Analytics](#build-a-backend-add-aws-services-analytics)
+- [Set up Amplify Analytics](#build-a-backend-add-aws-services-analytics-set-up-analytics)
+- [Record events](#build-a-backend-add-aws-services-analytics-record-events)
+- [Identify user](#build-a-backend-add-aws-services-analytics-identify-user)
+- [Automatically track sessions](#build-a-backend-add-aws-services-analytics-auto-track-sessions)
+- [Enable and disable analytics](#build-a-backend-add-aws-services-analytics-enable-disable)
+- [Streaming analytics data](#build-a-backend-add-aws-services-analytics-streaming-data)
+- [Storing analytics data](#build-a-backend-add-aws-services-analytics-storing-data)
+- [Personalized recommendations](#build-a-backend-add-aws-services-analytics-personalize-recommendations)
+- [Use existing AWS resources](#build-a-backend-add-aws-services-analytics-existing-resources)
+- [Use AWS SDK](#build-a-backend-add-aws-services-analytics-sdk)
+- [Data usage policy information](#build-a-backend-add-aws-services-analytics-data-usage-policy)
+- [Uninstalling the app](#build-a-backend-add-aws-services-analytics-app-uninstall)
+- [API References](#build-a-backend-add-aws-services-analytics-reference)
+- [Geo](#build-a-backend-add-aws-services-geo)
+- [Set up Amplify Geo](#build-a-backend-add-aws-services-geo-set-up-geo)
+- [Work with maps](#build-a-backend-add-aws-services-geo-maps)
+- [Configure location search](#build-a-backend-add-aws-services-geo-configure-location-search)
+- [Work with location search](#build-a-backend-add-aws-services-geo-location-search)
+- [Configure a geofence collection](#build-a-backend-add-aws-services-geo-configure-geofencing)
+- [Work with geofences](#build-a-backend-add-aws-services-geo-geofences)
+- [Use existing Amazon Location resources](#build-a-backend-add-aws-services-geo-existing-resources)
+- [Migrate from Google Maps](#build-a-backend-add-aws-services-geo-google-migration)
+- [Use Amazon Location Service SDK](#build-a-backend-add-aws-services-geo-amazon-location-sdk)
+- [In-App Messaging](#build-a-backend-add-aws-services-in-app-messaging)
+- [Set up in-app messaging](#build-a-backend-add-aws-services-in-app-messaging-set-up-in-app-messaging)
+- [Integrate your application](#build-a-backend-add-aws-services-in-app-messaging-integrate-application)
+- [Sync messages](#build-a-backend-add-aws-services-in-app-messaging-sync-messages)
+- [Display messages](#build-a-backend-add-aws-services-in-app-messaging-display-messages)
+- [Clear messages](#build-a-backend-add-aws-services-in-app-messaging-clear-messages)
+- [Identify a user](#build-a-backend-add-aws-services-in-app-messaging-identify-user)
+- [Respond to interaction events](#build-a-backend-add-aws-services-in-app-messaging-respond-interaction-events)
+- [Resolve conflicts](#build-a-backend-add-aws-services-in-app-messaging-resolve-conflicts)
+- [Create an in-app messaging campaign on AWS Console](#build-a-backend-add-aws-services-in-app-messaging-create-campaign)
+- [API References](#build-a-backend-add-aws-services-in-app-messaging-reference)
+- [API (REST)](#build-a-backend-add-aws-services-rest-api)
+- [Set up Amplify REST API](#build-a-backend-add-aws-services-rest-api-set-up-rest-api)
+- [Set up Amplify HTTP API](#build-a-backend-add-aws-services-rest-api-set-up-http-api)
+- [Define authorization rules](#build-a-backend-add-aws-services-rest-api-customize-authz)
+- [Fetch data](#build-a-backend-add-aws-services-rest-api-fetch-data)
+- [Post data](#build-a-backend-add-aws-services-rest-api-post-data)
+- [Update data](#build-a-backend-add-aws-services-rest-api-update-data)
+- [Delete data](#build-a-backend-add-aws-services-rest-api-delete-data)
+- [Test the REST API](#build-a-backend-add-aws-services-rest-api-test-api)
+- [Use existing AWS resources](#build-a-backend-add-aws-services-rest-api-existing-resources)
+- [API References](#build-a-backend-add-aws-services-rest-api-reference)
+- [AI/ML Predictions](#build-a-backend-add-aws-services-predictions)
+- [Set up Predictions](#build-a-backend-add-aws-services-predictions-set-up-predictions)
+- [Text to speech](#build-a-backend-add-aws-services-predictions-text-to-speech)
+- [Transcribe audio to text](#build-a-backend-add-aws-services-predictions-transcribe-audio)
+- [Translate language](#build-a-backend-add-aws-services-predictions-translate)
+- [Identify text](#build-a-backend-add-aws-services-predictions-identify-text)
+- [Identify entities from images](#build-a-backend-add-aws-services-predictions-identify-entity)
+- [Label objects in an image](#build-a-backend-add-aws-services-predictions-label-image)
+- [Interpret sentiment](#build-a-backend-add-aws-services-predictions-interpret-sentiment)
+- [Logging](#build-a-backend-add-aws-services-logging)
+- [Set up Logging](#build-a-backend-add-aws-services-logging-set-up-logging)
+- [Send logs](#build-a-backend-add-aws-services-logging-send-logs)
+- [Change log levels](#build-a-backend-add-aws-services-logging-change-log-levels)
+- [Flush logs](#build-a-backend-add-aws-services-logging-flush-logs)
+- [Enable and disable logging](#build-a-backend-add-aws-services-logging-enable-disable)
+- [Configure user allow list](#build-a-backend-add-aws-services-logging-configure-user)
+- [View logs](#build-a-backend-add-aws-services-logging-view-logs)
+- [Remotely change log levels](#build-a-backend-add-aws-services-logging-remote-configuration)
+- [Change local storage](#build-a-backend-add-aws-services-logging-change-local-storage)
+- [Listen to log events](#build-a-backend-add-aws-services-logging-hub-events)
+- [Use AWS SDK for logging](#build-a-backend-add-aws-services-logging-sdk)
+- [Interactions](#build-a-backend-add-aws-services-interactions)
+- [Set up Amplify Interactions](#build-a-backend-add-aws-services-interactions-set-up-interactions)
+- [Interact with bots](#build-a-backend-add-aws-services-interactions-chatbot)
+- [PubSub](#build-a-backend-add-aws-services-pubsub)
+- [Publish](#build-a-backend-add-aws-services-pubsub-publish)
+- [Set up Amplify PubSub](#build-a-backend-add-aws-services-pubsub-set-up-pubsub)
+- [Subscribe and unsubscribe](#build-a-backend-add-aws-services-pubsub-subscribe)
+- [Deletion protection and Backup resources](#build-a-backend-add-aws-services-deletion-backup-resources)
+- [Custom resources](#build-a-backend-add-aws-services-custom-resources)
+- [Tagging resources](#build-a-backend-add-aws-services-tagging-resources)
+- [Overriding resources](#build-a-backend-add-aws-services-overriding-resources)
+- [Use Amazon Q Developer with Amplify](#build-a-backend-q-developer)
+- [Troubleshooting](#build-a-backend-troubleshooting)
+- [Troubleshoot configuration errors](#build-a-backend-troubleshooting-library-not-configured)
+- [Troubleshoot CDKToolkit stack issues](#build-a-backend-troubleshooting-cdktoolkit-stack)
+- [Troubleshoot "Cannot find module $amplify/env/"](#build-a-backend-troubleshooting-cannot-find-module-amplify-env)
+- [Troubleshoot circular dependency issues](#build-a-backend-troubleshooting-circular-dependency)
+- [AI kit](#ai)
+- [Set up AI](#ai-set-up-ai)
+- [Concepts](#ai-concepts)
+- [Architecture](#ai-concepts-architecture)
+- [Models](#ai-concepts-models)
+- [Prompting](#ai-concepts-prompting)
+- [Inference Configuration](#ai-concepts-inference-configuration)
+- [Streaming](#ai-concepts-streaming)
+- [Tools](#ai-concepts-tools)
+- [Conversation](#ai-conversation)
+- [](#ai-conversation-ai-conversation)
+- [Connect your frontend](#ai-conversation-connect-your-frontend)
+- [Conversation History](#ai-conversation-history)
+- [Tools](#ai-conversation-tools)
+- [Context](#ai-conversation-context)
+- [Response components](#ai-conversation-response-components)
+- [Knowledge Base](#ai-conversation-knowledge-base)
+- [Generation](#ai-generation)
+- [Data Extraction](#ai-generation-data-extraction)
+- [Build UI](#build-ui)
+- [Connected forms](#build-ui-formbuilder)
+- [Customize form inputs](#build-ui-formbuilder-customize)
+- [Configure special inputs](#build-ui-formbuilder-special-inputs)
+- [Validate form data](#build-ui-formbuilder-validations)
+- [Manage form lifecycle](#build-ui-formbuilder-lifecycle)
+- [Figma-to-React](#build-ui-figma-to-code)
+- [Deployment](#deploy-and-host)
+- [Frontend hosting](#deploy-and-host-hosting)
+- [Cloud sandbox environments](#deploy-and-host-sandbox-environments)
+- [Use cloud sandbox in dev environment](#deploy-and-host-sandbox-environments-setup)
+- [Sandbox features](#deploy-and-host-sandbox-environments-features)
+- [Sandbox Seed](#deploy-and-host-sandbox-environments-seed)
+- [Fullstack workflows](#deploy-and-host-fullstack-branching)
+- [Fullstack branch deployments](#deploy-and-host-fullstack-branching-branch-deployments)
+- [Secrets and environment vars](#deploy-and-host-fullstack-branching-secrets-and-vars)
+- [Share resources across branches](#deploy-and-host-fullstack-branching-share-resources)
+- [Separate frontend and backend teams](#deploy-and-host-fullstack-branching-mono-and-multi-repos)
+- [Monorepo setup](#deploy-and-host-fullstack-branching-monorepos)
+- [Fullstack previews](#deploy-and-host-fullstack-branching-pr-previews)
+- [Custom pipelines](#deploy-and-host-fullstack-branching-custom-pipelines)
+- [Cross-account deployments](#deploy-and-host-fullstack-branching-cross-account-deployments)
+- [Reference](#reference)
+- [Project structure](#reference-project-structure)
+- [About amplify_outputs.json](#reference-amplify_outputs)
+- [CDK constructs](#reference-cdk-constructs)
+- [CLI commands](#reference-cli-commands)
+- [IAM policy](#reference-iam-policy)
+- [Telemetry](#reference-telemetry)
+- [API Documentation](#reference-flutter-api)
+
+---
+
+---
+title: "How Amplify works"
+section: "how-amplify-works"
+platforms: ["android", "angular", "flutter", "javascript", "nextjs", "react", "react-native", "swift", "vue"]
+gen: 2
+last-updated: "2024-05-02T03:55:55.000Z"
+url: "https://docs.amplify.aws/react/how-amplify-works/"
+---
+
+
+
+---
+
+---
+title: "Concepts"
+section: "how-amplify-works"
+platforms: ["android", "angular", "flutter", "javascript", "nextjs", "react", "react-native", "swift", "vue"]
+gen: 2
+last-updated: "2025-03-21T01:04:47.000Z"
+url: "https://docs.amplify.aws/react/how-amplify-works/concepts/"
+---
+
+AWS Amplify Gen 2 uses a TypeScript-based, code-first developer experience (DX) for defining backends. The Gen 2 DX offers a unified Amplify developer experience with hosting, backend, and UI-building capabilities and a code-first approach. Amplify empowers frontend developers to deploy cloud infrastructure by simply expressing their appβs data model, business logic, authentication, and authorization rules completely in TypeScript. Amplify automatically configures the correct cloud resources and removes the requirement to stitch together underlying AWS services.
+
+## Capabilities
+
+You can use Amplify for end-to-end fullstack development.
+
+### Build fullstack apps with TypeScript
+
+With the Gen 2 DX, you can provision backend infrastructure by authoring TypeScript. In the following diagram, the box at the bottom (outlined in pink), highlights the main difference in how you provision infrastructure compared to Gen 1. In Gen 1, you would use Studio's console or the CLI to provision infrastructure; in Gen 2, you author TypeScript code in files following a file-based convention (such as `amplify/auth/resource.ts` or `amplify/auth/data.ts`). With TypeScript types and classes for resources, you gain strict typing and IntelliSense in Visual Studio Code to prevent errors. A breaking change in the backend code immediately reflects as a type error in the co-located frontend code. The file-based convention follows the "convention over configuration" paradigmβyou know exactly where to look for resource definitions when you group them by type in separate files.
+
+
+
+### Faster local development
+
+Per-developer cloud sandbox environments are optimized for faster iterations. Each developer on a team gets an isolated cloud development environment against which they can test their changes. These cloud sandbox environments are meant for local development only, but they deploy high-fidelity AWS backends while you build. Depending on the workflow, iterative updates are now deployed up to 8X faster than Gen 1 deployments. In the diagram below, four developers are able to work on fullstack features independently without disrupting each other's environments.
+
+
+
+### Fullstack Git-based environments
+
+All shared environments (such as `production`, `staging`, `gamma`) map 1:1 to Git branches in your repository. New features can be tested in ephemeral environments with pull request previews (or feature branches) before they are merged into production. Unlike the Gen 1 experience, which requires users to configure a number of steps in the CLI or Console to set up a fullstack environment, the Gen 2 experience is zero-config. Because of our code-first approach, the Git repository is always the source of truth for the state of the fullstack appβall backend resources are defined as code for reproducibility and portability across branches. This, along with central management of environment variables and secrets, simplifies the promotion workflow from lower to upper environments.
+
+
+
+### Unified management console
+
+All branches can be managed in the new Amplify console. The Amplify Gen 2 console provides a single place for you to manage your builds, hosting settings (such as custom domains), deployed resources (such as data browser or user management), and environment variables and secrets. Even though you can access deployed resources directly in other AWS service consoles, the Amplify console will offer a first-party experience for the categories almost every app needsβdata, auth, storage, and functions. For example, with Data, Amplify offers an API playground and a data manager (coming soon) with relationship building, seed data generation, and file upload capabilities.
+
+## Build an app
+
+### Data
+
+The `@aws-amplify/backend` library offers a TypeScript-first `Data` library for setting up fully typed real-time APIs (powered by AWS AppSync GraphQL APIs) and NoSQL databases (powered by Amazon DynamoDB tables). After you generate an Amplify backend, you will have an `amplify/data/resource.ts` file, which will contain your app's data schema. The `defineData` function turns the schema into a fully functioning data backend with all the boilerplate handled automatically.
+
+
+ The schema-based approach is an evolution of the Amplify GraphQL API in Gen 1.
+ It offers several benefits, including dot completion, IntelliSense, and type
+ validation.
+
+
+A data model for a chat app may look something like this, for example:
+
+```ts
+const schema = a.schema({
+ Chat: a.model({
+ name: a.string(),
+ message: a.hasMany('Message', 'chatId'),
+ }),
+ Message: a.model({
+ text: a.string(),
+ chat: a.belongsTo('Chat', 'chatId'),
+ chatId: a.id()
+ }),
+}).authorization((allow) => allow.owner());
+```
+
+On your app's frontend, you can use the `generateClient` function, which provides a typed client instance, making it easy to integrate CRUD (create, read, update, delete) operations for your models in your application code.
+
+
+ Gen 2 automatically generates your types without the explicit codegen step
+ that was part of Gen 1.
+
+
+```ts
+// generate your data client using the Schema from your backend
+const client = generateClient();
+
+// list all messages
+const { data } = await client.models.Message.list();
+
+// create a new message
+const { errors, data: newMessage } = await client.models.Message.create({
+ text: 'My message text'
+});
+```
+
+### Auth
+
+Auth works similarly to data. You can configure the authentication settings you want for your app in `amplify/auth/resource.ts`. If you want to change the verification email's subject line, you can change out the default generated code with the following:
+
+```ts title="amplify/auth/resource.ts"
+export const auth = defineAuth({
+ loginWith: {
+ email: {
+ verificationEmailSubject: 'Welcome π Verify your email!'
+ }
+ }
+});
+```
+
+You can customize your authentication flow with customized sign-in and registration flows, multi-factor authentication (MFA), and third-party social providers. Amplify deploys an Amazon Cognito instance in your AWS account when you add auth to your app.
+
+Then, you could use the Amplify `Authenticator` component or the client libraries to add user flows.
+
+```ts
+import { withAuthenticator } from '@aws-amplify/ui-react';
+
+function App({ signOut, user }) {
+ return (
+ <>
+
Hello {user.username}
+
+ >
+ );
+}
+
+export default withAuthenticator(App);
+```
+
+### UI building
+
+Amplify makes it easy to quickly build web app user interfaces using the UI component library, Figma-to-code generation, and CRUD form-generation capabilities. [Learn more.](https://ui.docs.amplify.aws/react/components)
+
+
+
+## Connecting to AWS beyond Amplify
+
+### Add any AWS resource
+
+Gen 2 is layered on top of [AWS Cloud Development Kit (CDK)](https://docs.aws.amazon.com/cdk/api/v2/)βthe Data and Auth capabilities in `@aws-amplify/backend` wrap L3 AWS CDK constructs. As a result, extending the resources generated by Amplify does not require any special configuration. The following example adds Amazon Location Services by adding a file: `amplify/custom/maps/resource.ts`.
+
+```ts
+import { CfnOutput, Stack, StackProps } from 'aws-cdk-lib';
+import * as locations from 'aws-cdk-lib/aws-location';
+import { Construct } from 'constructs';
+
+export class LocationMapStack extends Stack {
+ constructor(scope: Construct, id: string, props?: StackProps) {
+ super(scope, id, props);
+
+ // Create the map resource
+ const map = new locations.CfnMap(this, 'LocationMap', {
+ configuration: {
+ style: 'VectorEsriStreets' // map style
+ },
+ description: 'My Location Map',
+ mapName: 'MyMap'
+ });
+
+ new CfnOutput(this, 'mapArn', {
+ value: map.attrArn,
+ exportName: 'mapArn'
+ });
+ }
+}
+```
+
+This is then included in the `amplify/backend.ts` file so it gets deployed as part of your Amplify app.
+
+```ts
+import { Backend } from '@aws-amplify/backend';
+import { auth } from './auth/resource';
+import { data } from './data/resource';
+import { LocationMapStack } from './locationMapStack/resource';
+
+const backend = new Backend({
+ auth,
+ data
+});
+
+new LocationMapStack(
+ backend.getStack('LocationMapStack'),
+ 'myLocationResource',
+ {}
+);
+```
+
+### Connect to existing resources
+
+Amplify is designed to work with your existing AWS resources and configurations. For example, you can use Amplify's pre-built authentication UI components with an existing Amazon Cognito user pool you created and configured separately. Or you can display images and files from an existing Amazon S3 bucket in your app's user interface by integrating with Amplify Storage.
+
+Amplify's libraries provide an interface to leverage your existing AWS services so that you can adopt Amplify's capabilities incrementally into your current workflows, without disrupting your existing backend infrastructure.
+
+## Next steps
+
+Now that you have a conceptual understanding of AWS Amplify's capabilities, complete the [quickstart tutorial](/[platform]/start/quickstart/) to put it into action in an app.
+
+---
+
+---
+title: "FAQ"
+section: "how-amplify-works"
+platforms: ["android", "angular", "flutter", "javascript", "nextjs", "react", "react-native", "swift", "vue"]
+gen: 2
+last-updated: "2024-06-05T19:53:40.000Z"
+url: "https://docs.amplify.aws/react/how-amplify-works/faq/"
+---
+
+**Is there a way to upgrade an existing Amplify project from Gen 1 to Gen 2?**
+
+We are still actively developing migration tooling to aid in transitioning your project from Gen 1 to Gen 2. Until then, we recommend you continue working with your Gen 1 Amplify project. Weβve put together a Gen 1 vs. Gen 2 feature support matrix [here](https://docs.amplify.aws/react/start/migrate-to-gen2/). We remain committed to supporting both Gen 1 and Gen 2 for the foreseeable future. For new projects, we recommend adopting Gen 2 to take advantage of its enhanced capabilities. Meanwhile, customers on Gen 1 will continue to receive support for high-priority bugs and essential security updates.
+
+**If I have a Gen 1 app, can I use Gen 2 in it?**
+
+Amplify Gen 1 and Gen 2 follow different architectural and tooling paradigms, which was necessary to address common customer feedback from Gen 1. You will need to use our upcoming migration tooling to move from a Gen 1 to Gen 2 app. You cannot use Amplify Gen 1 (Studio/CLI) in the same app as Gen 2.
+
+**Should I use Amplify Gen 1 or Gen 2 in new apps?**
+
+If you're building a new app, we recommend you use Amplify Gen 2.
+
+**Does Amplify Gen 2 support DataStore?**
+
+Amplify Gen 2 supports GraphQL APIs without DataStore. We will release migration support for moving DataStore Gen 1 apps to Gen 2.
+
+**What programming languages does Amplify Gen 2 support?**
+
+Amplify Gen 2 supports a wide range of programming languages for client-side development. This includes dedicated client-side libraries for JavaScript, TypeScript, Dart, Java, Kotlin, and Swift. For backend development, Amplify Gen 2 uses TypeScript.
+
+**In Gen 1, Amplify offered a set of use case categories for building applications (for example, Authentication, Analytics, API, DataStore, Geo, and Predictions). Are those same categories available in Gen 2?**
+
+Amplify Gen 2 offers built-in support for Auth, Data, Storage, and Functions. Other use cases can be implemented in Amplify Gen 2 as well using AWS Cloud Development Kit (AWS CDK) constructs which there is documentation for under the respective category name.
+
+**Can I use Gen 2 with a JavaScript frontend that doesn't use TypeScript?**
+
+Yes. Amplify Gen 2's TypeScript backend definition works with JavaScript frontends. In addition, you still get an end-to-end typed data fetching experience even with a pure JavaScript frontend. See [Generate a Data client](/react/build-a-backend/data/connect-to-API/#generate-the-amplify-data-client) for the recommended JavaScript client code.
+
+**What if we want to add a feature like AI/ML or Amazon Location Service to our application in Gen 2?**
+
+Because Amplify builds on the AWS Cloud Development Kit (AWS CDK), any AWS services supported by the CDK can be added to your app using [custom resources](/[platform]/build-a-backend/add-aws-services/custom-resources/) and L2/L1 AWS CDK constructs.
+
+**What happens once my application grows too big and I want to do more configuration with my application (add more features, other AWS services, etc.)?**
+
+You can stay with Amplify no matter how big your application grows. Amplify is layered on top of the AWS CDK and AWS CloudFormation. These provide a standardized way of interacting with AWS, so you can add any [AWS service supported by CDK to your Amplify app](/[platform]/build-a-backend/add-aws-services/custom-resources/). You can also override [Amplify-generated configuration of your resources](/[platform]/build-a-backend/add-aws-services/overriding-resources/) using the CDK. You can use any deployment pipeline you choose if you want more control over your CI.
+
+**How much does it cost to operate Amplify Gen2?**
+
+You can read all about Amplify's pricing on our [pricing page](https://aws.amazon.com/amplify/pricing/).
+
+**Which Amplify JavaScript version is compatible with Gen 2?**
+
+Amplify JavaScript version 6.2.0 and above is compatible with backends created by Amplify Gen 2.
+
+---
+
+---
+title: "Get started"
+section: "start"
+platforms: ["android", "angular", "flutter", "javascript", "nextjs", "react", "react-native", "swift", "vue"]
+gen: 2
+last-updated: "2024-03-19T21:13:52.000Z"
+url: "https://docs.amplify.aws/react/start/"
+---
+
+AWS Amplify is a collection of cloud services and libraries for fullstack application development. Amplify provides frontend libraries, UI components, backend building, and frontend hosting for building fullstack cloud apps. This tutorial will teach you how to use Amplify's new code-first developer experience to build a fullstack application with data, authentication, and frontend hosting which are all deployed to AWS. If you're completely new to AWS Amplify, you may want to read more about [how it works and the concepts behind the second generation of AWS Amplify](/[platform]/how-amplify-works/concepts/), which this tutorial will use.
+
+---
+
+---
+title: "Quickstart"
+section: "start"
+platforms: ["android", "angular", "flutter", "javascript", "nextjs", "react", "react-native", "swift", "vue"]
+gen: 2
+last-updated: "2025-11-13T16:29:27.000Z"
+url: "https://docs.amplify.aws/react/start/quickstart/"
+---
+
+
+π Welcome to AWS Amplify! In this quickstart guide, you will:
+
+1. Deploy a Vanilla JavaScript app with Vite
+2. Build and connect to a database with real-time data updates
+3. Configure authentication and authorization rules
+
+## Create project
+
+Create a new Vanilla JavaScript app with vite using the following commands, create the directory (`amplify-js-app`) and files for the app.
+
+```bash
+npm create vite@latest
+β Project name: amplify-js-app
+β Select a framework: βΊ Vanilla
+β Select a variant: βΊ TypeScript
+```
+
+Initialize npm and install dependencies and dev dependencies.
+```bash
+cd amplify-js-app
+npm install
+npm run dev
+```
+
+This runs a development server and allows you to see the output generated by the build. You can see the running app by navigating to [http://localhost:5173](http://localhost:5173).
+
+Add the following to the `index.html` file:
+
+```html title="index.html"
+
+
+
+
+
+ Todo App
+
+
+
+
+
+
+
+
+```
+
+Add the following to `style.css` file:
+
+```css title="style.css"
+body {
+ margin: 0;
+ background: linear-gradient(180deg, rgb(117, 81, 194), rgb(255, 255, 255));
+ display: flex;
+ font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
+ height: 100vh;
+ width: 100vw;
+ justify-content: center;
+ align-items: center;
+}
+
+main {
+ display: flex;
+ flex-direction: column;
+ align-items: stretch;
+}
+
+button {
+ border-radius: 8px;
+ border: 1px solid transparent;
+ padding: 0.6em 1.2em;
+ font-size: 1em;
+ font-weight: 500;
+ font-family: inherit;
+ background-color: #1a1a1a;
+ cursor: pointer;
+ transition: border-color 0.25s;
+ color: white;
+}
+button:hover {
+ border-color: #646cff;
+}
+button:focus,
+button:focus-visible {
+ outline: 4px auto -webkit-focus-ring-color;
+}
+
+ul {
+ padding-inline-start: 0;
+ margin-block-start: 0;
+ margin-block-end: 0;
+ list-style-type: none;
+ display: flex;
+ flex-direction: column;
+ margin: 8px 0;
+ border: 1px solid black;
+ gap: 1px;
+ background-color: black;
+ border-radius: 8px;
+ overflow: auto;
+}
+
+li {
+ background-color: white;
+ padding: 8px;
+}
+
+li:hover {
+ background: #dadbf9;
+}
+
+a {
+ font-weight: 800;
+ text-decoration: none;
+}
+```
+
+In `main.js` remove the boilerplate code and leave it empty. Then refresh the browser to see the changes.
+
+## Create Backend
+
+The easiest way to get started with AWS Amplify is through npm with `create-amplify` command. You can run it from your base project directory.
+
+```bash title="Terminal" showLineNumbers={false}
+npm create amplify@latest
+? Where should we create your project? (.) # press enter
+```
+
+Running this command will scaffold Amplify backend files in your current project with the following files added:
+
+```text
+βββ amplify/
+β βββ auth/
+β β βββ resource.ts
+β βββ data/
+β β βββ resource.ts
+β βββ backend.ts
+β βββ package.json
+βββ node_modules/
+βββ index.html
+βββ style.css
+βββ .gitignore
+βββ package-lock.json
+βββ package.json
+βββ tsconfig.json
+```
+
+### Set up local AWS credentials
+
+To make backend updates, we are going to require AWS credentials to deploy backend updates from our local machine.
+
+**Skip ahead to step 8**, if you already have an AWS profile with credentials on your local machine, and your AWS profile has the `AmplifyBackendDeployFullAccess` permission policy.
+
+Otherwise, **[set up local AWS credentials](/[platform]/start/account-setup/)** that grant Amplify permissions to deploy backend updates from your local machine.
+
+### Deploy cloud sandbox
+
+To deploy your backend use Amplify's per-developer cloud sandbox. This feature provides a separate backend environment for every developer on a team, ideal for local development and testing. To run your application with a sandbox environment, you can run the following command:
+
+```bash title="Terminal" showLineNumbers={false}
+npx ampx sandbox
+```
+
+Once the sandbox environment is deployed, it will create a GraphQL API, database, and auth service. All the deployed resources will be available in the `amplify_outputs.json`.
+
+## Connect frontend to backend
+
+The initial scaffolding already has a pre-configured data backend defined in the `amplify/data/resource.ts` file. The default example will create a Todo model with `content` field. Update your main.js file to create new to-do items.
+
+```typescript title="src/main.ts"
+import { generateClient } from "aws-amplify/data";
+import type { Schema } from "../amplify/data/resource";
+import './style.css';
+import { Amplify } from 'aws-amplify';
+import outputs from '../amplify_outputs.json';
+
+Amplify.configure(outputs);
+
+const client = generateClient();
+
+document.addEventListener("DOMContentLoaded", function () {
+ const todos: Array = [];
+ const todoList = document.getElementById("todoList") as HTMLUListElement;
+ const addTodoButton = document.getElementById("addTodo") as HTMLButtonElement;
+
+ addTodoButton.addEventListener("click", createTodo);
+
+ function updateUI() {
+ todoList.innerHTML = '';
+ todos.forEach(todo => {
+ const li = document.createElement('li');
+ li.textContent = todo.content ?? '';
+ todoList.appendChild(li);
+ });
+ }
+
+ function createTodo() {
+ console.log('createTodo');
+ const content = window.prompt("Todo content");
+ if (content) {
+ client.models.Todo.create({ content }).then(response => {
+ if (response.data && !response.errors) {
+ todos.push(response.data);
+ updateUI();
+ } else {
+ console.error('Error creating todo:', response.errors);
+ alert('Failed to create todo.');
+ }
+ }).catch(error => {
+ console.error('Network or other error:', error);
+ alert('Failed to create todo due to a network or other error.');
+ });
+ }
+ }
+
+ client.models.Todo.observeQuery().subscribe({
+ next: (data) => {
+ todos.splice(0, todos.length, ...data.items);
+ updateUI();
+ }
+ });
+});
+```
+
+
+
+π Welcome to AWS Amplify! In this quickstart guide, you will:
+
+1. Deploy a React and Vite app
+2. Build and connect to a database with real-time data updates
+3. Configure authentication and authorization rules
+
+## 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 React template.
+
+### 1. Create the repository
+
+Use our starter template to create a repository in your GitHub account. This template scaffolds `create-vite-app` with Amplify backend capabilities.
+
+
+
+Create repository from template
+
+
+Use the form in GitHub to finalize your repo's creation.
+
+### 2. Deploy the starter app
+
+Now that the repository has been created, deploy it with Amplify.
+
+
+
+Deploy to AWS
+
+
+Select **GitHub**. After you give Amplify access to your GitHub account via the popup window, pick the repository and `main` branch to deploy. Make no other changes and click through the flow to **Save and deploy**.
+
+### 3. View deployed app
+
+
+
+Let's take a tour of the project structure in this starter repository by opening it on GitHub. The starter application has pre-written code for a to-do list app. It gives you a real-time database with a feed of all to-do list items and the ability to add new items.
+
+```text
+βββ amplify/ # Folder containing your Amplify backend configuration
+β βββ auth/ # Definition for your auth backend
+β β βββ resource.tsx
+β βββ data/ # Definition for your data backend
+β β βββ resource.ts
+| βββ backend.ts
+β βββ tsconfig.json
+βββ src/ # React UI code
+β βββ App.tsx # UI code to sync todos in real-time
+β βββ index.css # Styling for your app
+β βββ main.tsx # Entrypoint of the Amplify client library
+βββ package.json
+βββ tsconfig.json
+```
+
+
+ When the build completes, visit the newly deployed branch by selecting "Visit deployed URL". Since the build deployed an API, database, and authentication backend, you will be able to create new to-do items.
+
+In the Amplify console, click into the deployment branch (in this case **main**) > select **Data** in the left-hand menu > **Data manager** to see the data entered in your database.
+
+## Make frontend updates
+
+Let's learn how to enhance the app functionality by creating a delete flow for to-do list items.
+
+### 4. Set up local environment
+
+Now let's set up our local development environment to add features to the frontend. Click on your deployed branch and you will land on the **Deployments** page which shows you your build history and a list of deployed backend resources.
+
+At the bottom of the page you will see a tab for **Deployed backend resources**. Click on the tab and then click the **Download amplify_outputs.json file** button.
+
+
+
+Clone the repository locally.
+
+```bash title="Terminal" showLineNumbers={false}
+git clone https://github.com//amplify-vite-react-template.git
+cd amplify-vite-react-template && npm install
+```
+
+Now move the `amplify_outputs.json` file you downloaded above to the root of your project.
+
+```text
+βββ amplify
+βββ src
+βββ amplify_outputs.json <== backend outputs file
+βββ package.json
+βββ tsconfig.json
+```
+
+
+The **amplify_outputs.json** file contains backend endpoint information, publicly-viewable API keys, authentication flow information, and more. The Amplify client library uses this outputs file to connect to your Amplify Backend. You can review how the outputs file is imported within the `main.tsx` file and then passed into the `Amplify.configure(...)` function of the Amplify client library.
+
+
+### 5. Implement delete functionality
+
+Go to the **src/App.tsx** file and add in a new `deleteTodo` functionality and pass function into the `
+
+ )
+}
+```
+
+Try out the deletion functionality now by starting the local dev server:
+
+```bash title="Terminal" showLineNumbers={false}
+npm run dev
+```
+
+This should start a local dev server at http://localhost:5173.
+
+### 6. Implement login UI
+
+The starter application already has a pre-configured auth backend defined in the **amplify/auth/resource.ts** file. We've configured it to support email and password login but you can extend it to support a variety of login mechanisms, including Google, Amazon, Sign In With Apple, and Facebook.
+
+The fastest way to get your login experience up and running is to use our Authenticator UI component. In your **src/main.tsx** file, import the Authenticator UI component and wrap your `` component.
+
+```tsx title="src/main.tsx"
+import React from 'react';
+import ReactDOM from 'react-dom/client';
+// highlight-next-line
+import { Authenticator } from '@aws-amplify/ui-react';
+import { Amplify } from 'aws-amplify';
+import App from './App.tsx';
+import outputs from '../amplify_outputs.json';
+import './index.css';
+// highlight-next-line
+import '@aws-amplify/ui-react/styles.css';
+
+Amplify.configure(outputs);
+
+ReactDOM.createRoot(document.getElementById('root')!).render(
+ // highlight-start
+
+
+
+
+
+ // highlight-end
+);
+```
+
+The Authenticator component auto-detects your auth backend settings and renders the correct UI state based on the auth backend's authentication flow.
+
+In your `src/App.tsx` file, add a button to enable users to sign out of the application. Import the [`useAuthenticator`](https://ui.docs.amplify.aws/react/connected-components/authenticator/advanced#access-auth-state) hook from the Amplify UI library to hook into the state of the Authenticator.
+
+```tsx title="src/App.tsx"
+import type { Schema } from '../amplify/data/resource';
+// highlight-next-line
+import { useAuthenticator } from '@aws-amplify/ui-react';
+import { useEffect, useState } from 'react';
+import { generateClient } from 'aws-amplify/data';
+
+const client = generateClient();
+
+function App() {
+ // highlight-next-line
+ const { signOut } = useAuthenticator();
+
+ // ...
+
+ return (
+
+ {/* ... */}
+ // highlight-next-line
+
+
+ );
+}
+
+export default App;
+```
+
+Try out your application in your localhost environment again. You should be presented with a login experience now.
+
+To get these changes to the cloud, commit them to git and push the changes upstream.
+
+```bash title="Terminal" showLineNumbers={false}
+git commit -am "added authenticator"
+git push
+```
+
+Amplify automatically deploys the latest version of your app based on your git commits. In just a few minutes, when the application rebuilds, the hosted app will be updated to support the deletion functionality.
+
+## Make backend updates
+
+Let's update our backend to implement per-user authorization rules, allowing each user to only access their own to-dos.
+
+### 7. Set up local AWS credentials
+
+To make backend updates, we are going to require AWS credentials to deploy backend updates from our local machine.
+
+**Skip ahead to step 8**, if you already have an AWS profile with credentials on your local machine, and your AWS profile has the `AmplifyBackendDeployFullAccess` permission policy.
+
+Otherwise, **[set up local AWS credentials](/[platform]/start/account-setup/)** that grant Amplify permissions to deploy backend updates from your local machine.
+
+### 8. Deploy cloud sandbox
+
+To update your backend without affecting the production branch, use Amplify's cloud sandbox. This feature provides a separate backend environment for each developer on a team, ideal for local development and testing.
+
+To start your cloud sandbox, run the following command in a **new Terminal window**:
+
+```bash title="Terminal" showLineNumbers={false}
+npx ampx sandbox
+```
+
+Once the cloud sandbox has been fully deployed (~5 min), you'll see the `amplify_outputs.json` file updated with connection information to a new isolated authentication and data backend.
+
+> **Info:** The `npx ampx sandbox` command should run concurrently to your `npm run dev`. You can think of the cloud sandbox as the "localhost-equivalent for your app backend".
+
+### 9. Implement per-user authorization
+
+The to-do items in the starter are currently shared across all users, but, in most cases, you want data to be isolated on a per-user basis.
+
+To isolate the data on a per-user basis, you can use an "owner-based authorization rule". Let's apply the owner-based authorization rule to your to-do items:
+
+```ts title="amplify/data/resource.ts"
+import { type ClientSchema, a, defineData } from '@aws-amplify/backend';
+
+const schema = a.schema({
+ Todo: a.model({
+ content: a.string(),
+ // highlight-next-line
+ }).authorization(allow => [allow.owner()]),
+});
+
+export type Schema = ClientSchema;
+
+export const data = defineData({
+ schema,
+ authorizationModes: {
+ // This tells the data client in your app (generateClient())
+ // to sign API requests with the user authentication token.
+ // highlight-next-line
+ defaultAuthorizationMode: 'userPool',
+ },
+});
+```
+
+In the application client code, let's also render the username to distinguish different users once they're logged in. Go to your **src/App.tsx** file and render the `user` property from the `useAuthenticator` hook.
+
+```tsx title="src/App.tsx"
+// ... imports
+
+function App() {
+ // highlight-next-line
+ const { user, signOut } = useAuthenticator();
+
+ // ...
+
+ return (
+
+ // highlight-next-line
+
{user?.signInDetails?.loginId}'s todos
+ {/* ... */}
+
+ )
+}
+```
+
+Now, let's go back to your local application and test out the user isolation of the to-do items.
+
+You will need to sign up new users again because now you're working with the cloud sandbox instead of your production backend.
+
+To get these changes to the cloud, commit them to git and push the changes upstream.
+
+```bash title="Terminal" showLineNumbers={false}
+git commit -am "added per-user data isolation"
+git push
+```
+
+Once your build completes in the Amplify Console, the `main` backend will update to support the changes made within the cloud sandbox. The data in the cloud sandbox is fully isolated and won't pollute your production database.
+
+
+
+π Welcome to AWS Amplify! In this quickstart guide, you will:
+
+1. Deploy a Next.js app
+2. Build and connect to a database with real-time data updates
+3. Configure authentication and authorization rules
+
+We have two Quickstart guides you can follow:
+
+
+
+
+π Welcome to AWS Amplify! In this quickstart guide, you will:
+
+1. Deploy a Vue.js app
+2. Build and connect to a database with real-time data updates
+3. Configure authentication and authorization rules
+
+## 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 Vue template.
+
+### 1. Create the repository
+
+Use our starter template to create a repository in your GitHub account. This template scaffolds `create-vite-app` with Amplify backend capabilities.
+
+
+
+Create repository from template
+
+
+Use the form in GitHub to finalize your repo's creation.
+
+### 2. Deploy the starter app
+
+Now that the repository has been created, deploy it with Amplify.
+
+
+
+Deploy to AWS
+
+
+Select **GitHub**. After you give Amplify access to your GitHub account via the popup window, pick the repository and `main` branch to deploy. Make no other changes and click through the flow to **Save and deploy**.
+
+### 3. View deployed app
+
+
+
+Let's take a tour of the project structure in this starter repository by opening it on GitHub. The starter application has pre-written code for a to-do list app. It gives you a real-time database with a feed of all to-do list items and the ability to add new items.
+
+```text
+βββ amplify/ # Folder containing your Amplify backend configuration
+β βββ auth/ # Definition for your auth backend
+β β βββ resource.tsx
+β βββ data/ # Definition for your data backend
+β β βββ resource.ts
+| βββ backend.ts
+β βββ tsconfig.json
+βββ src/ # Vue code
+β βββ assets/ # Styling for your app
+β βββ components/ # UI code to sync todos in real-time
+β βββ App.vue # UI layout
+β βββ main.tsx # Entrypoint of the Amplify client library
+βββ package.json
+βββ tsconfig.json
+```
+
+
+ When the build completes, visit the newly deployed branch by selecting "Visit deployed URL". Since the build deployed an API, database, and authentication backend, you will be able to create new to-do items.
+
+In the Amplify console, click into the deployment branch (in this case **main**) > select **Data** in the left-hand menu > **Data manager** to see the data entered in your database.
+
+## Make frontend updates
+
+Let's learn how to enhance the app functionality by creating a delete flow for to-do list items.
+
+### 4. Set up local environment
+
+Now let's set up our local development environment to add features to the frontend. Click on your deployed branch and you will land on the **Deployments** page which shows you your build history and a list of deployed backend resources.
+
+At the bottom of the page you will see a tab for **Deployed backend resources**. Click on the tab and then click the **Download amplify_outputs.json file** button.
+
+
+
+Clone the repository locally.
+
+```bash title="Terminal" showLineNumbers={false}
+git clone https://github.com//amplify-vue-template.git
+cd amplify-vue-template && npm install
+```
+
+Now move the `amplify_outputs.json` file you downloaded above to the root of your project.
+
+```text
+βββ amplify
+βββ src
+βββ amplify_outputs.json <== backend outputs file
+βββ package.json
+βββ tsconfig.json
+```
+
+
+The **amplify_outputs.json** file contains backend endpoint information, publicly-viewable API keys, authentication flow information, and more. The Amplify client library uses this outputs file to connect to your Amplify Backend. You can review how the outputs file is imported within the `main.tsx` file and then passed into the `Amplify.configure(...)` function of the Amplify client library.
+
+
+### 5. Implement delete functionality
+
+Go to the **components/Todos.vue** file and add in a new `deleteTodo` functionality and pass function into the `
+
+
+}
+```
+
+Try out the deletion functionality now by starting the local dev server:
+
+```bash title="Terminal" showLineNumbers={false}
+npm run dev
+```
+
+This should start a local dev server at http://localhost:5173.
+
+### 6. Implement login UI
+
+The starter application already has a pre-configured auth backend defined in the **amplify/auth/resource.ts** file. We've configured it to support email and password login but you can extend it to support a variety of login mechanisms, including Google, Amazon, Sign In With Apple, and Facebook.
+
+The fastest way to get your login experience up and running is to use our Authenticator UI component.
+
+```terminal showLineNumbers={false}
+npm add @aws-amplify/ui-vue
+```
+In your **src/App.vue** file, import the Authenticator UI component and wrap your `` template.
+
+```tsx title="src/App.vue"
+
+
+
+
+ // highlight-start
+
+
+
+
+
+
+ // highlight-end
+
+
+```
+
+The Authenticator component auto-detects your auth backend settings and renders the correct UI state based on the auth backend's authentication flow.
+
+Try out your application in your localhost environment again. You should be presented with a login experience now.
+
+To get these changes to the cloud, commit them to git and push the changes upstream.
+
+```bash title="Terminal" showLineNumbers={false}
+git commit -am "added authenticator"
+git push
+```
+
+Amplify automatically deploys the latest version of your app based on your git commits. In just a few minutes, when the application rebuilds, the hosted app will be updated to support the deletion functionality.
+
+## Make backend updates
+
+Let's update our backend to implement per-user authorization rules, allowing each user to only access their own to-dos.
+
+### 7. Set up local AWS credentials
+
+To make backend updates, we are going to require AWS credentials to deploy backend updates from our local machine.
+
+**Skip ahead to step 8**, if you already have an AWS profile with credentials on your local machine, and your AWS profile has the `AmplifyBackendDeployFullAccess` permission policy.
+
+Otherwise, **[set up local AWS credentials](/[platform]/start/account-setup/)** that grant Amplify permissions to deploy backend updates from your local machine.
+
+### 8. Deploy cloud sandbox
+
+To update your backend without affecting the production branch, use Amplify's cloud sandbox. This feature provides a separate backend environment for each developer on a team, ideal for local development and testing.
+
+To start your cloud sandbox, run the following command in a **new Terminal window**:
+
+```bash title="Terminal" showLineNumbers={false}
+npx ampx sandbox
+```
+
+Once the cloud sandbox has been fully deployed (~5 min), you'll see the `amplify_outputs.json` file updated with connection information to a new isolated authentication and data backend.
+
+> **Info:** The `npx ampx sandbox` command should run concurrently to your `npm run dev`. You can think of the cloud sandbox as the "localhost-equivalent for your app backend".
+
+### 9. Implement per-user authorization
+
+The to-do items in the starter are currently shared across all users, but, in most cases, you want data to be isolated on a per-user basis.
+
+To isolate the data on a per-user basis, you can use an "owner-based authorization rule". Let's apply the owner-based authorization rule to your to-do items:
+
+```ts title="amplify/data/resource.ts"
+import { type ClientSchema, a, defineData } from '@aws-amplify/backend';
+
+const schema = a.schema({
+ Todo: a.model({
+ content: a.string(),
+ // highlight-next-line
+ }).authorization(allow => [allow.owner()]),
+});
+
+export type Schema = ClientSchema;
+
+export const data = defineData({
+ schema,
+ authorizationModes: {
+ // This tells the data client in your app (generateClient())
+ // to sign API requests with the user authentication token.
+ // highlight-next-line
+ defaultAuthorizationMode: 'userPool',
+ },
+});
+```
+
+In the application client code, let's also render the username to distinguish different users once they're logged in.
+
+```tsx title="src/App.vue"
+
+
+
+
+
+ // highlight-start
+
+
Hello {{user?.signInDetails?.loginId}}'s todos
+ // highlight-end
+
+
+
+
+
+
+```
+
+Now, let's go back to your local application and test out the user isolation of the to-do items.
+
+You will need to sign up new users again because now you're working with the cloud sandbox instead of your production backend.
+
+To get these changes to the cloud, commit them to git and push the changes upstream.
+
+```bash title="Terminal" showLineNumbers={false}
+git commit -am "added per-user data isolation"
+git push
+```
+
+Once your build completes in the Amplify Console, the `main` backend will update to support the changes made within the cloud sandbox. The data in the cloud sandbox is fully isolated and won't pollute your production database.
+
+
+
+π Welcome to AWS Amplify! In this quickstart guide, you will:
+
+1. Deploy an Angular app
+2. Build and connect to a database with real-time data updates
+3. Configure authentication and authorization rules
+
+## 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 Angular template.
+
+### 1. Create the repository
+
+Use our starter template to create a repository in your GitHub account. This template scaffolds a starter Angular application with Amplify backend capabilities.
+
+
+
+Create repository from template
+
+
+Use the form in GitHub to finalize your repo's creation.
+
+### 2. Deploy the starter app
+
+Now that the repository has been created, deploy it with Amplify.
+
+
+
+Deploy to AWS
+
+
+Select **GitHub**. After you give Amplify access to your GitHub account via the popup window, pick the repository and `main` branch to deploy. Make no other changes and click through the flow to **Save and deploy**.
+
+### 3. View deployed app
+
+
+
+Let's take a tour of the project structure in this starter repository by opening it on GitHub. The starter application has pre-written code for a to-do list app. It gives you a real-time database with a feed of all to-do list items and the ability to add new items.
+
+```text
+βββ amplify/ # Folder containing your Amplify backend configuration
+β βββ auth/ # Definition for your auth backend
+β β βββ resource.tsx
+β βββ data/ # Definition for your data backend
+β β βββ resource.ts
+| βββ backend.ts
+β βββ tsconfig.json
+βββ src/app/ # Angular UI code
+β βββ todos/ # UI code to sync todos in real-time
+β βββ app.component.css # Styling for your app
+β βββ app.component.ts # Entrypoint of the Amplify client library
+βββ package.json
+βββ tsconfig.json
+```
+
+
+ When the build completes, visit the newly deployed branch by selecting "Visit deployed URL". Since the build deployed an API, database, and authentication backend, you will be able to create new to-do items.
+
+In the Amplify console, click into the deployment branch (in this case **main**) > select **Data** in the left-hand menu > **Data manager** to see the data entered in your database.
+
+## Make frontend updates
+
+Let's learn how to enhance the app functionality by creating a delete flow for to-do list items.
+
+### 4. Set up local environment
+
+Now let's set up our local development environment to add features to the frontend. Click on your deployed branch and you will land on the **Deployments** page which shows you your build history and a list of deployed backend resources.
+
+At the bottom of the page you will see a tab for **Deployed backend resources**. Click on the tab and then click the **Download amplify_outputs.json file** button.
+
+
+
+Clone the repository locally.
+
+```bash title="Terminal" showLineNumbers={false}
+git clone https://github.com//amplify-angular-template.git
+cd amplify-angular-template && npm install
+```
+
+Now move the `amplify_outputs.json` file you downloaded above to the root of your project.
+
+```text
+βββ amplify
+βββ src
+βββ amplify_outputs.json <== backend outputs file
+βββ package.json
+βββ tsconfig.json
+```
+
+
+The **amplify_outputs.json** file contains backend endpoint information, publicly-viewable API keys, authentication flow information, and more. The Amplify client library uses this outputs file to connect to your Amplify Backend. You can review how the outputs file is imported within the `app.component.ts` file and then passed into the `Amplify.configure(...)` function of the Amplify client library.
+
+
+### 5. Implement delete functionality
+
+Go to the **src/app/todos/todos.component.ts** file and add a new `deleteTodo` function.
+
+```tsx title="src/todos/todos.component.ts"
+export class TodosComponent implements OnInit {
+ // ...
+ // highlight-start
+ deleteTodo(id: string) {
+ client.models.Todo.delete({ id })
+ }
+ // highlight-end
+}
+```
+
+Call the `deleteTodo` function from the UI.
+
+```html title="src/app/todos/todos.component.html"
+...
+
+
+ {{ todo.content }}
+
+
+...
+```
+
+Try out the deletion functionality now by starting the local dev server:
+
+```bash title="Terminal" showLineNumbers={false}
+npm run start
+```
+
+This should start a local dev server at http://localhost:4200.
+
+### 6. Implement login UI
+
+The starter application already has a pre-configured auth backend defined in the **amplify/auth/resource.ts** file. We've configured it to support email and password login but you can extend it to support a variety of login mechanisms, including Google, Amazon, Sign In With Apple, and Facebook.
+
+The fastest way to get your login experience up and running is to use our Authenticator UI component.
+
+```terminal showLineNumbers={false}
+npm add @aws-amplify/ui-angular
+```
+
+In your **src/app/app.component.ts** file, import the `AmplifyAuthenticatorModule`.
+
+```ts title="src/app/app.component.ts"
+import { Component } from '@angular/core';
+import { RouterOutlet } from '@angular/router';
+import { TodosComponent } from './todos/todos.component';
+import { Amplify } from 'aws-amplify';
+import outputs from '../../amplify_outputs.json';
+// highlight-next-line
+import { AmplifyAuthenticatorModule, AuthenticatorService } from '@aws-amplify/ui-angular';
+
+Amplify.configure(outputs);
+
+@Component({
+ selector: 'app-root',
+ standalone: true,
+ templateUrl: './app.component.html',
+ styleUrl: './app.component.css',
+ // highlight-next-line
+ imports: [RouterOutlet, TodosComponent, AmplifyAuthenticatorModule],
+})
+export class AppComponent {
+ title = 'amplify-angular-template';
+ // highlight-start
+ constructor(public authenticator: AuthenticatorService) {
+ Amplify.configure(outputs);
+ }
+ // highlight-end
+}
+```
+Update the application UI and include styles.
+
+```html title="src/app/app.component.html"
+
+
+
+
+
+
+```
+
+```json title="angular.json"
+...
+ "styles": [
+ "node_modules/@aws-amplify/ui-angular/theme.css",
+ "src/styles.css"
+ ],
+...
+```
+The Authenticator component auto-detects your auth backend settings and renders the correct UI state based on the auth backend's authentication flow.
+
+Try out your application in your localhost environment again. You should be presented with a login experience now.
+
+To get these changes to the cloud, commit them to git and push the changes upstream.
+
+```bash title="Terminal" showLineNumbers={false}
+git commit -am "added authenticator"
+git push
+```
+
+Amplify automatically deploys the latest version of your app based on your git commits. In just a few minutes, when the application rebuilds, the hosted app will be updated to support the deletion functionality.
+
+## Make backend updates
+
+Let's update our backend to implement per-user authorization rules, allowing each user to only access their own to-dos.
+
+### 7. Set up local AWS credentials
+
+To make backend updates, we are going to require AWS credentials to deploy backend updates from our local machine.
+
+**Skip ahead to step 8**, if you already have an AWS profile with credentials on your local machine, and your AWS profile has the `AmplifyBackendDeployFullAccess` permission policy.
+
+Otherwise, **[set up local AWS credentials](/[platform]/start/account-setup/)** that grant Amplify permissions to deploy backend updates from your local machine.
+
+### 8. Deploy cloud sandbox
+
+To update your backend without affecting the production branch, use Amplify's cloud sandbox. This feature provides a separate backend environment for each developer on a team, ideal for local development and testing.
+
+To start your cloud sandbox, run the following command in a **new Terminal window**:
+
+```bash title="Terminal" showLineNumbers={false}
+npx ampx sandbox
+```
+
+Once the cloud sandbox has been fully deployed (~5 min), you'll see the `amplify_outputs.json` file updated with connection information to a new isolated authentication and data backend.
+
+> **Info:** The `npx ampx sandbox` command should run concurrently to your `npm run dev`. You can think of the cloud sandbox as the "localhost-equivalent for your app backend".
+
+### 9. Implement per-user authorization
+
+The to-do items in the starter are currently shared across all users, but, in most cases, you want data to be isolated on a per-user basis.
+
+To isolate the data on a per-user basis, you can use an "owner-based authorization rule". Let's apply the owner-based authorization rule to your to-do items:
+
+```ts title="amplify/data/resource.ts"
+import { type ClientSchema, a, defineData } from '@aws-amplify/backend';
+
+const schema = a.schema({
+ Todo: a.model({
+ content: a.string(),
+ })
+ // highlight-next-line
+ .authorization(allow => [allow.owner()]),
+});
+
+export type Schema = ClientSchema;
+
+export const data = defineData({
+ schema,
+ authorizationModes: {
+ // This tells the data client in your app (generateClient())
+ // to sign API requests with the user authentication token.
+ // highlight-next-line
+ defaultAuthorizationMode: 'userPool',
+ },
+});
+```
+
+In the application client code, let's also render the username to distinguish different users once they're logged in.
+
+```html title="src/app/app.component.html"
+
+
+
Hello {{user?.signInDetails?.loginId}}'s todos
+
+
+
+
+```
+
+Now, let's go back to your local application and test out the user isolation of the to-do items.
+
+You will need to sign up new users again because now you're working with the cloud sandbox instead of your production backend.
+
+To get these changes to the cloud, commit them to git and push the changes upstream.
+
+```bash title="Terminal" showLineNumbers={false}
+git commit -am "added per-user data isolation"
+git push
+```
+
+Once your build completes in the Amplify Console, the `main` backend will update to support the changes made within the cloud sandbox. The data in the cloud sandbox is fully isolated and won't pollute your production database.
+
+
+
+## Prerequisites
+
+Before you get started, make sure you have the following installed:
+
+- [Node.js](https://nodejs.org/) v18.17 or later
+- [npm](https://www.npmjs.com/) v9 or later
+- [git](https://git-scm.com/) v2.14.1 or later
+- You will also need to [create an AWS Account](https://portal.aws.amazon.com/billing/signup). Note that AWS Amplify is part of the [AWS Free Tier](https://aws.amazon.com/amplify/pricing/).
+- Configure your AWS account to use with Amplify [instructions](/[platform]/start/account-setup/).
+- A stable version of [Flutter](https://docs.flutter.dev/get-started/install).
+
+> **Info:** You can follow the [official documentation](https://flutter.dev/docs/get-started/install) to install Flutter on your machine and check the [editor documentation](https://docs.flutter.dev/get-started/editor) for setting up your editor.
+
+Once you have installed Flutter, you can create a new Flutter project using the following command:
+
+> **Info:** In this Quickstart guide, you will build the application for web. However, if you want to run the application on other platforms, be sure to follow the required setup [guide here](/[platform]/start/platform-setup/).
+
+```bash title="Terminal" showLineNumbers={false}
+flutter create my_amplify_app
+```
+
+## Create Backend
+
+The easiest way to get started with AWS Amplify is through npm with `create-amplify` command. You can run it from your base project directory. First, go to the base project directory with the following command:
+
+```bash title="Terminal" showLineNumbers={false}
+cd my_amplify_app
+```
+
+After that, run the following to create an Amplify project:
+
+```bash title="Terminal" showLineNumbers={false}
+npm create amplify@latest -y
+```
+
+Running this command will scaffold Amplify backend files in your current project with the following files added:
+
+```text
+βββ amplify/
+β βββ auth/
+β β βββ resource.ts
+β βββ data/
+β β βββ resource.ts
+β βββ backend.ts
+β βββ package.json
+βββ node_modules/
+βββ .gitignore
+βββ package-lock.json
+βββ package.json
+βββ tsconfig.json
+```
+
+To deploy your backend use Amplify's per-developer cloud sandbox. This feature provides a separate backend environment for every developer on a team, ideal for local development and testing. To run your application with a sandbox environment, you can run the following command:
+
+
+```bash title="Terminal" showLineNumbers={false}
+npx ampx sandbox
+
+```
+
+
+```bash title="Terminal" showLineNumbers={false}
+npx ampx sandbox --outputs-format dart --outputs-out-dir lib
+```
+
+
+## Adding Authentication
+
+The initial scaffolding already has a pre-configured auth backend defined in the `amplify/auth/resource.ts` file. We've configured it to support email and password login but you can extend it to support a variety of login mechanisms, including Google, Amazon, Sign In With Apple, and Facebook.
+
+The fastest way to get your login experience up and running is to use our Authenticator UI component available in the Amplify UI library.
+
+To use the Authenticator, you need to add the following dependencies to your project:
+
+```yaml title="pubspec.yaml"
+dependencies:
+ amplify_flutter: ^2.0.0
+ amplify_auth_cognito: ^2.0.0
+ amplify_authenticator: ^2.0.0
+```
+
+You will add:
+
+- `amplify_flutter` to connect your application with the Amplify resources.
+- `amplify_auth_cognito` to connect your application with the Amplify Cognito resources.
+- `amplify_authenticator` to use the Amplify UI components.
+
+After adding the dependencies, you need to run the following command to install the dependencies:
+
+```bash title="Terminal" showLineNumbers={false}
+flutter pub get
+```
+
+Lastly update your main.dart file to use the Amplify UI components:
+
+```dart title="main.dart"
+import 'package:amplify_auth_cognito/amplify_auth_cognito.dart';
+import 'package:amplify_authenticator/amplify_authenticator.dart';
+import 'package:amplify_flutter/amplify_flutter.dart';
+import 'package:flutter/material.dart';
+
+import 'amplify_outputs.dart';
+
+Future main() async {
+ try {
+ WidgetsFlutterBinding.ensureInitialized();
+ await _configureAmplify();
+ runApp(const MyApp());
+ } on AmplifyException catch (e) {
+ runApp(Text("Error configuring Amplify: ${e.message}"));
+ }
+}
+
+Future _configureAmplify() async {
+ try {
+ await Amplify.addPlugin(AmplifyAuthCognito());
+ await Amplify.configure(amplifyConfig);
+ safePrint('Successfully configured');
+ } on Exception catch (e) {
+ safePrint('Error configuring Amplify: $e');
+ }
+}
+
+class MyApp extends StatelessWidget {
+ const MyApp({super.key});
+ @override
+ Widget build(BuildContext context) {
+ return Authenticator(
+ child: MaterialApp(
+ builder: Authenticator.builder(),
+ home: const Scaffold(
+ body: Center(
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ SignOutButton(),
+ Text('TODO Application'),
+ ],
+ ),
+ ),
+ ),
+ ),
+ );
+ }
+}
+```
+
+The Authenticator component auto-detects your auth backend settings and renders the correct UI state based on the auth backend's authentication flow.
+
+Run your application in your local environment again. You should be presented with a login experience now.
+
+## Adding Data
+
+The initial scaffolding already has a pre-configured data backend defined in the `amplify/data/resource.ts` file. The default example will create a Todo model with `content` field.
+
+Let's modify this to add the following:
+- A boolean `isDone` field.
+- An authorization rules specifying owners, authenticated via your Auth resource can "create", "read", "update", and "delete" their own records.
+- Update the `defaultAuthorizationMode` to sign API requests with the user authentication token.
+
+```typescript
+import { type ClientSchema, a, defineData } from "@aws-amplify/backend";
+
+const schema = a.schema({
+ Todo: a
+ .model({
+ content: a.string(),
+ isDone: a.boolean(),
+ })
+ .authorization(allow => [allow.owner()]),
+});
+
+export type Schema = ClientSchema;
+
+export const data = defineData({
+ schema,
+ authorizationModes: {
+ defaultAuthorizationMode: "userPool",
+ },
+});
+```
+Next, let's implement UI to create, list, and delete the to-do items.
+
+Amplify can automatically generate code for interacting with the backend API. Run the command in the terminal to generate dart model classes from the Data schema under `lib/models`:
+
+```bash title="Terminal" showLineNumbers={false}
+npx ampx generate graphql-client-code --format modelgen --model-target dart --out lib/models
+```
+
+Once you are done, add the API dependencies to your project. You will add `amplify_api` to connect your application with the Amplify API.
+
+```yaml title="pubspec.yaml"
+dependencies:
+ amplify_api: ^2.0.0
+```
+
+After adding the dependencies, update the `_configureAmplify` method in your `main.dart` file to use the Amplify API:
+
+```dart title="main.dart"
+Future _configureAmplify() async {
+ try {
+ await Amplify.addPlugins(
+ [
+ AmplifyAuthCognito(),
+ AmplifyAPI(
+ options: APIPluginOptions(
+ modelProvider: ModelProvider.instance,
+ ),
+ ),
+ ],
+ );
+ await Amplify.configure(amplifyConfig);
+ safePrint('Successfully configured');
+ } on Exception catch (e) {
+ safePrint('Error configuring Amplify: $e');
+ }
+}
+```
+
+Next create a new widget called `TodoScreen` and add the following code to the end of the **main.dart** file:
+
+```dart title="main.dart"
+
+class TodoScreen extends StatefulWidget {
+ const TodoScreen({super.key});
+
+ @override
+ State createState() => _TodoScreenState();
+}
+
+class _TodoScreenState extends State {
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ floatingActionButton: FloatingActionButton.extended(
+ label: const Text('Add Random Todo'),
+ onPressed: () async {
+ final newTodo = Todo(
+ id: uuid(),
+ content: "Random Todo ${DateTime.now().toIso8601String()}",
+ isDone: false,
+ );
+ final request = ModelMutations.create(newTodo);
+ final response = await Amplify.API.mutate(request: request).response;
+ if (response.hasErrors) {
+ safePrint('Creating Todo failed.');
+ } else {
+ safePrint('Creating Todo successful.');
+ }
+ },
+ ),
+ body: const Placeholder(),
+ );
+ }
+}
+```
+
+This will create a random Todo every time a user clicks on the floating action button. You can see the `ModelMutations.create` method is used to create a new Todo.
+
+And update the `MyApp` widget in your **main.dart** file like the following:
+
+```dart title="main.dart"
+class MyApp extends StatelessWidget {
+ const MyApp({super.key});
+ @override
+ Widget build(BuildContext context) {
+ return Authenticator(
+ child: MaterialApp(
+ builder: Authenticator.builder(),
+ home: const SafeArea(
+ child: Scaffold(
+ body: Column(
+ children: [
+ SignOutButton(),
+ Expanded(child: TodoScreen()),
+ ],
+ ),
+ ),
+ ),
+ ),
+ );
+ }
+}
+```
+
+Next add a `_todos` list in `_TodoScreenState` to add the results from the API and call the refresh function:
+
+```dart title="main.dart"
+List _todos = [];
+
+@override
+void initState() {
+ super.initState();
+ _refreshTodos();
+}
+```
+
+and create a new function called `_refreshTodos`:
+
+```dart title="main.dart"
+Future _refreshTodos() async {
+ try {
+ final request = ModelQueries.list(Todo.classType);
+ final response = await Amplify.API.query(request: request).response;
+
+ final todos = response.data?.items;
+ if (response.hasErrors) {
+ safePrint('errors: ${response.errors}');
+ return;
+ }
+ setState(() {
+ _todos = todos!.whereType().toList();
+ });
+ } on ApiException catch (e) {
+ safePrint('Query failed: $e');
+ }
+}
+```
+
+and update the `build` function like the following:
+
+```dart title="main.dart"
+@override
+Widget build(BuildContext context) {
+ return Scaffold(
+ floatingActionButton: FloatingActionButton.extended(
+ label: const Text('Add Random Todo'),
+ onPressed: () async {
+ final newTodo = Todo(
+ id: uuid(),
+ content: "Random Todo ${DateTime.now().toIso8601String()}",
+ isDone: false,
+ );
+ final request = ModelMutations.create(newTodo);
+ final response = await Amplify.API.mutate(request: request).response;
+ if (response.hasErrors) {
+ safePrint('Creating Todo failed.');
+ } else {
+ safePrint('Creating Todo successful.');
+ }
+ _refreshTodos();
+ },
+ ),
+ body: _todos.isEmpty == true
+ ? const Center(
+ child: Text(
+ "The list is empty.\nAdd some items by clicking the floating action button.",
+ textAlign: TextAlign.center,
+ ),
+ )
+ : ListView.builder(
+ itemCount: _todos.length,
+ itemBuilder: (context, index) {
+ final todo = _todos[index];
+ return Dismissible(
+ key: UniqueKey(),
+ confirmDismiss: (direction) async {
+ return false;
+ },
+ child: CheckboxListTile.adaptive(
+ value: todo.isDone,
+ title: Text(todo.content!),
+ onChanged: (isChecked) async {},
+ ),
+ );
+ },
+ ),
+ );
+}
+```
+
+Now let's add the update and delete functionality.
+
+For update, add the following code to the `onChanged` method of the `CheckboxListTile.adaptive` widget:
+
+```dart title="main.dart"
+final request = ModelMutations.update(
+ todo.copyWith(isDone: isChecked!),
+);
+final response =
+ await Amplify.API.mutate(request: request).response;
+if (response.hasErrors) {
+ safePrint('Updating Todo failed. ${response.errors}');
+} else {
+ safePrint('Updating Todo successful.');
+ await _refreshTodos();
+}
+```
+
+This will call the `ModelMutations.update` method to update the Todo with a copied/updated version of the todo item. So now the checkbox will get an update as well.
+
+For delete functionality, add the following code to the `confirmDismiss` method of the `Dismissible` widget:
+
+```dart title="main.dart"
+if (direction == DismissDirection.endToStart) {
+ final request = ModelMutations.delete(todo);
+ final response =
+ await Amplify.API.mutate(request: request).response;
+ if (response.hasErrors) {
+ safePrint('Updating Todo failed. ${response.errors}');
+ } else {
+ safePrint('Updating Todo successful.');
+ await _refreshTodos();
+ return true;
+ }
+}
+return false;
+```
+
+This will delete the Todo item when the user swipes the item from right to left. Now if you run the application you should see the following flow.
+
+You can terminate the sandbox environment now to clean up the project.
+
+### Publishing changes to cloud
+
+Publishing changes to the cloud requires a remote git repository. Amplify offers fullstack branch deployments that allow you to automatically deploy infrastructure and application code changes from feature branches. To learn more, visit the [fullstack branch deployments guide](/[platform]/deploy-and-host/fullstack-branching/branch-deployments).
+
+
+
+## Prerequisites
+
+Before you get started, make sure you have the following installed:
+
+- [Node.js](https://nodejs.org/) v18.17 or later
+- [npm](https://www.npmjs.com/) v9 or later
+- [git](https://git-scm.com/) v2.14.1 or later
+- You will also need to [create an AWS Account](https://portal.aws.amazon.com/billing/signup). Note that AWS Amplify is part of the [AWS Free Tier](https://aws.amazon.com/amplify/pricing/).
+- Configure your AWS account to use with Amplify [instructions](/[platform]/start/account-setup/).
+- You need to have [Xcode and Developer Tooling](https://developer.apple.com/xcode/) installed on your machine.
+
+
+Open Xcode and select **Create New Project...**
+
+
+
+In the next step select the **App** template under **iOS**. Click on next.
+
+
+
+Next steps are:
+
+- Adding a _Product Name_ (e.g. MyAmplifyApp)
+- Select a _Team_ (e.g. None)
+- Select a _Organization Identifier_ (e.g. com.example)
+- Select **SwiftUI** an _Interface_.
+- Press **Next**
+
+
+
+Now you should have your project created.
+
+
+
+
+## Create Backend
+
+The easiest way to get started with AWS Amplify is through npm with `create-amplify` command. You can run it from your base project directory.
+
+```bash title="Terminal" showLineNumbers={false}
+cd my_amplify_app
+npm create amplify@latest
+? Where should we create your project? (.) # press enter
+```
+
+Running this command will scaffold Amplify backend files in your current project with the following files added:
+
+```text
+βββ amplify/
+β βββ auth/
+β β βββ resource.ts
+β βββ data/
+β β βββ resource.ts
+β βββ backend.ts
+β βββ package.json
+βββ node_modules/
+βββ .gitignore
+βββ package-lock.json
+βββ package.json
+βββ tsconfig.json
+```
+
+To deploy your backend use Amplify's per-developer cloud sandbox. This feature provides a separate backend environment for every developer on a team, ideal for local development and testing. To run your application with a sandbox environment, you can run the following command:
+
+```bash title="Terminal" showLineNumbers={false}
+npx ampx sandbox
+```
+
+Once the sandbox environment is deployed, it will create an `amplify_outputs.json`. However, Xcode won't be able to recognize them. For recognizing the files, you need to drag and drop the generated files to your project.
+
+## Adding Authentication
+
+The initial scaffolding already has a pre-configured auth backend defined in the `amplify/auth/resource`.ts file. We've configured it to support email and password login but you can extend it to support a variety of login mechanisms, including Google, Amazon, Sign In With Apple, and Facebook.
+
+The fastest way to get your login experience up and running is to use our Authenticator UI component available in the Amplify UI library.
+
+To use the Authenticator, open your project in Xcode and select **File > Add Packages...** and add the following dependencies:
+
+
+
+- Amplify Library for Swift: Enter its GitHub URL (https://github.com/aws-amplify/amplify-swift), select **Up to Next Major Version** and click **Add Package Dependencies...** and select the following libraries:
+
+ - Amplify
+ - AWSCognitoAuthPlugin
+
+
+
+- Amplify UI Swift - Authenticator: Enter its GitHub URL (https://github.com/aws-amplify/amplify-ui-swift-authenticator), select **Up to Next Major Version** and click **Add Package Dependencies...** and select the following libraries:
+ - Authenticator
+
+
+
+Now update the `MyAmplifyAppApp` class with the following code:
+
+```swift
+import Amplify
+import Authenticator
+import AWSCognitoAuthPlugin
+import SwiftUI
+
+@main
+struct MyApp: App {
+ init() {
+ do {
+ try Amplify.add(plugin: AWSCognitoAuthPlugin())
+ try Amplify.configure(with: .amplifyOutputs)
+ } catch {
+ print("Unable to configure Amplify \(error)")
+ }
+ }
+
+ var body: some Scene {
+ WindowGroup {
+ ContentView()
+ }
+ }
+}
+```
+
+Update `ContentView` with the following code:
+```swift
+import Amplify
+import Authenticator
+
+struct ContentView: View {
+ var body: some View {
+ Authenticator { state in
+ VStack {
+ Button("Sign out") {
+ Task {
+ await state.signOut()
+ }
+ }
+ }
+ }
+ }
+}
+```
+
+The Authenticator component auto-detects your auth backend settings and renders the correct UI state based on the auth backend's authentication flow.
+
+Run your application in your local environment again. You should be presented with a login experience now.
+
+
+
+## Adding Data
+
+The initial scaffolding already has a pre-configured data backend defined in the `amplify/data/resource.ts` file. The default example will create a Todo model with `content` field.
+
+Let's modify this to add the following:
+- A boolean `isDone` field.
+- An authorization rules specifying owners, authenticated via your Auth resource can "create", "read", "update", and "delete" their own records.
+- Update the `defaultAuthorizationMode` to sign API requests with the user authentication token.
+
+```typescript
+import { type ClientSchema, a, defineData } from '@aws-amplify/backend';
+
+const schema = a.schema({
+ Todo: a
+ .model({
+ content: a.string(),
+ isDone: a.boolean().required()
+ })
+ .authorization((allow) => [allow.owner()])
+});
+
+export type Schema = ClientSchema;
+
+export const data = defineData({
+ schema,
+ authorizationModes: {
+ defaultAuthorizationMode: 'userPool'
+ }
+});
+```
+Next, let's implement UI to create, list, and delete the to-do items.
+
+Amplify can automatically generate code for interacting with the backend API. The command below generates model classes from the Data schema:
+
+```bash title="Terminal" showLineNumbers={false}
+npx ampx generate graphql-client-code --format modelgen --model-target swift
+```
+
+Move the generated files to your project. You can do this by dragging and dropping the files to your project.
+
+
+
+Once you are done, add the API dependencies to your project. Select **File > Add Package Dependencies...** and add the `AWSAPIPlugin`.
+
+
+
+After adding the dependencies, update the `import` part of your `MyAmplifyAppApp.swift` file with the following code:
+
+```swift title="MyAmplifyAppApp.swift"
+import Amplify
+import AWSCognitoAuthPlugin
+import AWSAPIPlugin
+```
+
+Then, update the `init()` part of your `MyAmplifyAppApp.swift` file with the following code:
+
+```swift title="MyAmplifyAppApp.swift"
+init() {
+ do {
+ try Amplify.add(plugin: AWSCognitoAuthPlugin())
+ try Amplify.add(plugin: AWSAPIPlugin(modelRegistration: AmplifyModels()))
+ try Amplify.configure(with: .amplifyOutputs)
+ } catch {
+ print("Unable to configure Amplify \(error)")
+ }
+}
+```
+
+Create a new file called `TodoViewModel.swift` and the `createTodo` function with the following code:
+
+```swift title="TodoViewModel.swift"
+import Amplify
+import SwiftUI
+
+@MainActor
+class TodoViewModel: ObservableObject {
+ func createTodo() async {
+ let creationTime = Temporal.DateTime.now()
+ let todo = Todo(
+ content: "Random Todo \(creationTime.iso8601String)",
+ isDone: false,
+ createdAt: creationTime,
+ updatedAt: creationTime
+ )
+ do {
+ let result = try await Amplify.API.mutate(request: .create(todo))
+ switch result {
+ case .success(let todo):
+ print("Successfully created todo: \(todo)")
+ todos.append(todo)
+ case .failure(let error):
+ print("Got failed result with \(error.errorDescription)")
+ }
+ } catch let error as APIError {
+ print("Failed to create todo: ", error)
+ } catch {
+ print("Unexpected error: \(error)")
+ }
+ }
+}
+
+```
+
+The code above will create a random todo with the current time.
+
+Next, update the `listTodos` function in the `TodoViewModel.swift` for listing to-do items:
+
+```swift title="TodoViewModel.swift"
+@MainActor
+class TodoViewModel: ObservableObject {
+ @Published var todos: [Todo] = []
+
+ func createTodo() {
+ /// ...
+ }
+
+ func listTodos() async {
+ let request = GraphQLRequest.list(Todo.self)
+ do {
+ let result = try await Amplify.API.query(request: request)
+ switch result {
+ case .success(let todos):
+ print("Successfully retrieved list of todos: \(todos)")
+ self.todos = todos.elements
+ case .failure(let error):
+ print("Got failed result with \(error.errorDescription)")
+ }
+ } catch let error as APIError {
+ print("Failed to query list of todos: ", error)
+ } catch {
+ print("Unexpected error: \(error)")
+ }
+ }
+}
+```
+
+This will assign the value of the fetched todos into a Published object.
+
+Now let's update the UI code to observe the todos. Update the `VStack` in the `ContentView.swift` file with the following code:
+
+```swift title="ContentView.swift"
+struct ContentView: View {
+
+ // Create an observable object instance.
+ @StateObject var vm = TodoViewModel()
+
+ var body: some View {
+ Authenticator { state in
+ VStack {
+ Button("Sign out") {
+ Task {
+ await state.signOut()
+ }
+ }
+ Button(action: {
+ Task { await vm.createTodo() }
+ }) {
+ HStack {
+ Text("Add a New Todo")
+ Image(systemName: "plus")
+ }
+ }
+ .accessibilityLabel("New Todo")
+ }
+ }
+ }
+}
+```
+
+> **Info:** Throughout the Swift implementation, the async/await pattern has been used and
+> for using it easily, we take advantage of the Task structure. For more
+> information about the Task structure, you can check the
+> [documentation](https://developer.apple.com/documentation/swift/task).
+
+The code will create a todo and update the todo list each time a todo is created.
+
+Next step is to update and delete the todos. For that, create `updateTodo` and `deleteTodo` functions in the `TodoViewModel.swift` file with the following code:
+
+```swift title="TodoViewModel.swift"
+@MainActor
+class TodoViewModel: ObservableObject {
+ @Published var todos: [Todo] = []
+
+ func createTodo() {
+ // ...
+ }
+
+ func listTodos() {
+ // ...
+ }
+
+ func deleteTodos(indexSet: IndexSet) async {
+ for index in indexSet {
+ do {
+ let todo = todos[index]
+ let result = try await Amplify.API.mutate(request: .delete(todo))
+ switch result {
+ case .success(let todo):
+ print("Successfully deleted todo: \(todo)")
+ todos.remove(at: index)
+ case .failure(let error):
+ print("Got failed result with \(error.errorDescription)")
+ }
+ } catch let error as APIError {
+ print("Failed to deleted todo: ", error)
+ } catch {
+ print("Unexpected error: \(error)")
+ }
+ }
+ }
+
+ func updateTodo(todo: Todo) async {
+ do {
+ let result = try await Amplify.API.mutate(request: .update(todo))
+ switch result {
+ case .success(let todo):
+ print("Successfully updated todo: \(todo)")
+ case .failure(let error):
+ print("Got failed result with \(error.errorDescription)")
+ }
+ } catch let error as APIError {
+ print("Failed to updated todo: ", error)
+ } catch {
+ print("Unexpected error: \(error)")
+ }
+ }
+}
+
+```
+
+Update the `List` in the `ContentView.swift` file with code to fetch the todos when the View is displayed and to call `deleteTodos(indexSet:)` when the user left-swipe a todo.
+
+```swift title="ContentView.swift"
+struct ContentView: View {
+ @StateObject var vm = TodoViewModel()
+
+ var body: some View {
+ Authenticator { state in
+ VStack {
+ // ... Sign out Button
+ List {
+ ForEach($vm.todos, id: \.id) { todo in
+ TodoRow(vm: vm, todo: todo)
+ }
+ .onDelete { indexSet in
+ Task { await vm.deleteTodos(indexSet: indexSet) }
+ }
+ }
+ .task {
+ await vm.listTodos()
+ }
+ // ... Add new Todo button
+ }
+ }
+ }
+}
+```
+
+Lastly, create a new file called `TodoRow.swift` with the following code:
+
+```swift title="TodoRow.swift"
+import SwiftUI
+
+struct TodoRow: View {
+ @ObservedObject var vm: TodoViewModel
+ @Binding var todo: Todo
+
+ var body: some View {
+ Toggle(isOn: $todo.isDone) {
+ Text(todo.content ?? "")
+ }
+ .toggleStyle(.switch)
+ .onChange(of: todo.isDone) { _, newValue in
+ var updatedTodo = todo
+ updatedTodo.isDone = newValue
+ Task { await vm.updateTodo(todo: updatedTodo) }
+ }
+ }
+}
+
+#Preview {
+ @State var todo = Todo(content: "Hello Todo World 20240706T15:23:42.256Z", isDone: false)
+ return TodoRow(vm: TodoViewModel(), todo: $todo)
+}
+```
+
+This will update the UI to show a toggle to update the todo `isDone` and a swipe to delete the todo. Now if you run the application you should see the following flow.
+
+
+
+You can terminate the sandbox environment now to clean up the project.
+
+## Publishing changes to cloud
+
+Publishing changes to the cloud requires a remote git repository. Amplify offers fullstack branch deployments that allow you to automatically deploy infrastructure and application code changes from feature branches. To learn more, visit the [fullstack branch deployments guide](/[platform]/deploy-and-host/fullstack-branching/branch-deployments).
+
+
+
+π Welcome to AWS Amplify! In this quickstart guide, you will:
+1. deploy an Amplify backend database and authentication
+2. connect to the backend from an Android app
+3. make backend updates
+
+## Deploy Amplify backend to AWS
+
+To get started faster, we've created a starter "To-do" Amplify backend. First, create a repository in your GitHub account using our starter template.
+
+### 1. Create repository
+
+Use our starter template to create a repository in your GitHub account. This template scaffolds an Amplify Backend with Auth and Data capabilities.
+
+
+Create repository from template
+
+
+### 2. Deploy starter
+
+Now that the repository has been created, deploy this to Amplify's CI/CD pipeline.
+
+
+
+Deploy to AWS
+
+
+Select **GitHub**, pick the starter repository, and hit "Save and Deploy".
+
+### 3: View deployed backend
+
+
+
+Let's take a tour of the project structure in this starter repository. The starter application already has pre-written code to give you a real-time database with a feed of all to-do items and the ability to add new items.
+
+```text
+βββ amplify/ # Folder containing your Amplify backend configuration
+β βββ auth/ # Definition for your auth backend
+β β βββ resource.ts
+β βββ data/ # Definition for your data backend
+β β βββ resource.ts
+| βββ backend.ts
+β βββ package.json
+```
+
+
+ When the build completes, visit the newly deployed branch by selecting the branch name and then looking at the **Deployed backend resources** section under deployments.
+
+## Make app updates
+
+Let's learn how to enhance the app functionality by creating a delete flow for to-do list items.
+
+### 4. Set up local environment
+
+
+
+**Open Android Studio.** Select **+ Create New Project.**
+
+
+
+In **Select a Project Template**, select **Empty Activity** or **Empty Compose Activity**. Press **Next**.
+
+
+
+- Enter _MyAmplifyApp_ in the **Name** field
+- Select either _Java_ or _Kotlin_ from the **Language** dropdown menu
+- Select _API 24: Android 7.0 (Nougat)_ from the **Minimum SDK** dropdown menu
+- Press **Finish**
+
+
+
+
+
+On the **Deployed backend resources**, choose **Download outputs file** to download the `amplify_outputs.json` file that contains identifiers for all the deployed backend resources.
+
+
+
+Now move the `amplify_outputs.json` file you downloaded above to `app/src/main/res/raw` in your Android project. You will now be able to connect to this backend.
+
+
+The **amplify_outputs.json** file contains backend endpoint information, publicly-viewable API keys, authentication flow information, and more. The Amplify client library uses this outputs file to connect to your Amplify Backend.
+
+
+### 5. Install dependencies
+
+Amplify uses some modern Java APIs that require desugaring to be added for earlier versions of Android. In your app/build.gradle.kts add the following lines:
+```kotlin title="app/build.gradle.kts"
+android {
+ compileOptions {
+ // Support for modern Java features
+ isCoreLibraryDesugaringEnabled = true
+ }
+}
+
+dependencies {
+ coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:ANDROID_DESUGAR_VERSION")
+}
+```
+
+### 6. Implement login UI
+
+The deployed backend application already has a pre-configured auth backend defined in the `amplify/auth/resource.ts` file.
+
+The fastest way to get your login experience up and running is to use our Authenticator UI component. To use the Authenticator UI component, you need to add the following dependencies to your app/build.gradle.kts file:
+
+> **Warning:** Be sure to have compileSdk version as 34 or higher.
+
+```kotlin title="app/build.gradle.kts"
+dependencies {
+ implementation("com.amplifyframework.ui:authenticator:ANDROID_AUTHENTICATOR_VERSION")
+ coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:ANDROID_DESUGAR_VERSION")
+}
+```
+
+Afterwards create a `MyAmplifyApp` class that extends `Application` and add the following code:
+
+```kotlin title="MyAmplifyApp.kt"
+import android.app.Application
+import android.util.Log
+import com.amplifyframework.AmplifyException
+import com.amplifyframework.auth.cognito.AWSCognitoAuthPlugin
+import com.amplifyframework.core.Amplify
+import com.amplifyframework.core.configuration.AmplifyOutputs
+
+class MyAmplifyApp: Application() {
+ override fun onCreate() {
+ super.onCreate()
+
+ try {
+ Amplify.addPlugin(AWSCognitoAuthPlugin())
+ Amplify.configure(AmplifyOutputs(R.raw.amplify_outputs), applicationContext)
+ Log.i("MyAmplifyApp", "Initialized Amplify")
+ } catch (error: AmplifyException) {
+ Log.e("MyAmplifyApp", "Could not initialize Amplify", error)
+ }
+ }
+}
+```
+
+Next call this class in your `AndroidManifest.xml` file:
+
+```xml title="AndroidManifest.xml"
+
+```
+
+Update `MainActivity.kt` to use the Android Authenticator component.
+
+```kotlin title="MainActivity.kt"
+import android.os.Bundle
+..
+//highlight-start
+import com.amplifyframework.ui.authenticator.ui.Authenticator
+import androidx.compose.foundation.layout.Column
+import androidx.compose.material3.Button
+import com.amplifyframework.core.Amplify
+//highlight-end
+
+class MainActivity : ComponentActivity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContent {
+ MyAmplifyAppTheme {
+ // A surface container using the 'background' color from the theme
+ Surface(
+ modifier = Modifier.fillMaxSize(),
+ color = MaterialTheme.colorScheme.background
+ )
+ //highlight-start
+ {
+ Authenticator { state ->
+ Column {
+ Text(
+ text = "Hello ${state.user.username}!",
+ )
+ Button(onClick = {
+ Amplify.Auth.signOut { }
+ }) {
+ Text(text = "Sign Out")
+ }
+ }
+ }
+ }
+ //highlight-end
+ }
+ }
+ }
+}
+```
+
+Now if you run the application on the Android emulator, you should see the authentication flow working.
+
+
+
+### 7. Read and write data
+
+The initial scaffolding already has a pre-configured data backend defined in the `amplify/data/resource.ts` file. The default example will create a Todo model with `content` field.
+
+Amplify can automatically generate code for interacting with the backend API. The command below generates model classes from the Data schema:
+
+
+In the command below, replace the APP-ID with your Amplify app ID. Find this in the Amplify Console.
+
+
+
+```bash title="Terminal" showLineNumbers={false}
+cd my-android-app
+npx @aws-amplify/backend-cli generate graphql-client-code --format modelgen --model-target java --out app/src/main/java --app-id --branch main
+```
+
+Once you are done, add the following dependencies to your project:
+
+```kotlin title="build.gradle.kts"
+dependencies {
+ // Amplify API dependencies
+ // highlight-start
+ implementation("com.amplifyframework:aws-api:ANDROID_VERSION")
+ // highlight-end
+ // ... other dependencies
+}
+```
+
+After adding the dependencies, open the `MyAmplifyApp` class and add the following line before the `configure` call:
+
+```kotlin title="MyAmplifyApp.kt"
+
+// highlight-next-line
+import com.amplifyframework.api.aws.AWSApiPlugin
+
+..
+// highlight-next-line
+Amplify.addPlugin(AWSApiPlugin())
+```
+
+Update the `MainActivity` class with the following code to create new to-do items. The `onClick` function will create a new Todo item.
+
+```kt title="MainActivity"
+
+class MainActivity : ComponentActivity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContent {
+ MyAmplifyAppTheme {
+ // A surface container using the 'background' color from the theme
+ Surface(
+ modifier = Modifier.fillMaxSize(),
+ color = MaterialTheme.colorScheme.background
+ ) {
+ Authenticator { state ->
+ Column {
+ Text(
+ text = "Hello ${state.user.username}!",
+ )
+ // highlight-start
+ Button(onClick = {
+ val todo = Todo.builder()
+ .content("My first todo")
+ .build()
+
+ Amplify.API.mutate(
+ ModelMutation.create(todo),
+ { Log.i("MyAmplifyApp", "Added Todo with id: ${it.data.id}")},
+ { Log.e("MyAmplifyApp", "Create failed", it)},
+ )
+ }) {
+ Text(text = "Create Todo")
+ }
+ // highlight-end
+ Button(onClick = {
+ Amplify.Auth.signOut { }
+ }) {
+ Text(text = "Sign Out")
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+```
+
+Now it is time to add a logic to view the added items.
+
+```kt title="MainActivity.kt"
+@Composable
+fun TodoList() {
+ var todoList by remember { mutableStateOf(emptyList()) }
+
+ LaunchedEffect(Unit) {
+ // API request to list all Todos
+ Amplify.API.query(
+ ModelQuery.list(Todo::class.java),
+ { todoList = it.data.items.toList() },
+ { Log.e("MyAmplifyApp", "Failed to query.", it) }
+ )
+ }
+
+ LazyColumn {
+ items(todoList) { todo ->
+ Row {
+ // Render your activity item here
+ Text(text = todo.content)
+ }
+ }
+ }
+}
+```
+
+Now call `TodoList()` from the `onCreate()` function:
+
+```kt title="MainActivity.kt"
+setContent {
+ MyAmplifyAppTheme {
+ // A surface container using the 'background' color from the theme
+ Surface(
+ modifier = Modifier.fillMaxSize(),
+ color = MaterialTheme.colorScheme.background
+ ) {
+ Authenticator { state ->
+ Column {
+ Text(
+ text = "Hello ${state.user.username}!",
+ )
+ ....
+ //highlight-next-line
+ TodoList()
+```
+
+### 8. Enable real-time data
+
+If you build and rerun the application, you should see the todo that was created in the previous build. But notice how when you click on the "create Todo" button, it doesn't add any new todos to the list below until the next time your app relaunches. To solve this, let's add real-time updates to the todo list.
+
+To add real-time updates, you can use the subscription feature of Amplify Data. It allows to subscribe to `onCreate`, `onUpdate`, and `onDelete` events of the application. In our example, let's append the list every time a new todo is added.
+
+```kt title="MainActivity.kt"
+@Composable
+fun TodoList() {
+ var todoList by remember { mutableStateOf(emptyList()) }
+
+ LaunchedEffect(Unit) {
+ Amplify.API.query(
+ ModelQuery.list(Todo::class.java),
+ { todoList = it.data.items.toList() },
+ { Log.e("MyAmplifyApp", "Failed to query.", it) }
+ )
+ // highlight-start
+ Amplify.API.subscribe(
+ ModelSubscription.onCreate(Todo::class.java),
+ { Log.i("ApiQuickStart", "Subscription established") },
+ {
+ Log.i("ApiQuickStart", "Todo create subscription received: ${it.data}")
+ todoList = todoList + it.data
+ },
+ { Log.e("ApiQuickStart", "Subscription failed", it) },
+ { Log.i("ApiQuickStart", "Subscription completed") }
+ )
+ // highlight-end
+ }
+
+ LazyColumn {
+ items(todoList) { todo ->
+ Row {
+ // Render your activity item here
+ Text(text = todo.content)
+ }
+ }
+ }
+}
+```
+
+## Make backend updates
+
+Let's update our backend to implement per-user authorization rules, allowing each user to only access their own to-dos.
+
+### 9. Implement per-user authorization
+
+First, clone the deployed repository.
+
+```bash title="Terminal" showLineNumbers={false}
+git clone https://github.com//amplify-backend-template.git
+cd amplify-backend-template
+npm install
+```
+The backend to-do model is configured to share data across all users, but, in most cases, you want data to be isolated on a per-user basis.
+
+To isolate the data on a per-user basis, you can use an "owner-based authorization rule". Let's apply the owner-based authorization rule to your to-do items:
+
+```ts title="amplify/data/resource.ts"
+import { type ClientSchema, a, defineData } from '@aws-amplify/backend';
+
+const schema = a.schema({
+ Todo: a.model({
+ content: a.string(),
+ // highlight-next-line
+ }).authorization(allow => [allow.owner()]),
+});
+
+export type Schema = ClientSchema;
+
+export const data = defineData({
+ schema,
+ authorizationModes: {
+ // This tells the data client in your app (generateClient())
+ // to sign API requests with the user authentication token.
+ // highlight-next-line
+ defaultAuthorizationMode: 'userPool',
+ },
+});
+```
+Commit this change to your git repository. Amplify's CI/CD system will automatically pick up the changes and build and deploy the updates.
+
+```bash title="Terminal" showLineNumbers={false}
+git commit -am "added per-user data isolation"
+git push
+```
+### 10. Test in app
+
+Now, let's go back to your Android application and test out the user isolation of the to-do items. Fetch the latest `amplify_outputs.json` and model files by re-running the following command in your Android Studio terminal.
+
+
+In the command below, replace the APP-ID with your Amplify app ID. Find this in the Amplify Console.
+
+
+
+
+```bash showLineNumbers={false}
+npx @aws-amplify/backend-cli generate graphql-client-code --format modelgen --model-target java --out app/src/main/java --app-id --branch main
+```
+
+Also update your `amplify_outputs` file with the latest outputs information.
+
+```bash showLineNumbers={false}
+npx @aws-amplify/backend-cli generate outputs --out-dir app/src/main/res/raw --app-id --branch main
+```
+
+
+
+## Prerequisites
+
+Before you get started, make sure you have the following installed:
+
+- [Node.js](https://nodejs.org/) v18.17 or later
+- [npm](https://www.npmjs.com/) v9 or later
+- [git](https://git-scm.com/) v2.14.1 or later
+- You will also need to [create an AWS Account](https://portal.aws.amazon.com/billing/signup). Note that AWS Amplify is part of the [AWS Free Tier](https://aws.amazon.com/amplify/pricing/).
+- Configure your AWS account to use with Amplify [instructions](/[platform]/start/account-setup/).
+
+This Quickstart guide will walk you through how to build a Todo application for Android or iOS using [Expo](https://expo.dev/)'s TypeScript template.
+
+> **Warning:** **Warning:** React Native for Web is not officially supported yet, but we are working towards official support. We are tracking the progress in [issue #13918 on GitHub](https://github.com/aws-amplify/amplify-js/issues/13918)
+
+
+
+Amplify now requires native modules not available through the Expo SDK. As a result, Expo Go is no longer supported but you should still be able to use Expo. [Learn more about dropping support for Expo Go in Amplify v6](/gen1/react-native/build-a-backend/troubleshooting/migrate-from-javascript-v5-to-v6/).
+
+
+
+```bash title="Terminal" showLineNumbers={false}
+npx create-expo-app my_amplify_app -t expo-template-blank-typescript
+cd my_amplify_app
+```
+
+> **Warning:** For calling native libraries and platform dependencies, you need to have run the prebuild command for generating the folders for depending platforms.
+>
+> ```bash title="Terminal" showLineNumbers={false}
+npx expo prebuild
+```
+
+## Create Backend
+
+The easiest way to get started with AWS Amplify is through npm with `create-amplify` command. You can run it from your base project directory.
+
+```bash title="Terminal" showLineNumbers={false}
+cd my_amplify_app
+npm create amplify@latest
+? Where should we create your project? (.) # press enter
+```
+
+Running this command will scaffold Amplify backend files in your current project with the following files added:
+
+```text
+βββ amplify/
+β βββ auth/
+β β βββ resource.ts
+β βββ data/
+β β βββ resource.ts
+β βββ backend.ts
+β βββ package.json
+βββ node_modules/
+βββ .gitignore
+βββ package-lock.json
+βββ package.json
+βββ tsconfig.json
+```
+
+To deploy your backend use Amplify's per-developer cloud sandbox. This feature provides a separate backend environment for every developer on a team, ideal for local development and testing. To run your application with a sandbox environment, you can run the following command:
+
+```bash title="Terminal" showLineNumbers={false}
+npx ampx sandbox
+```
+
+### Adding Authentication
+
+The initial scaffolding already has a pre-configured auth backend defined in the `amplify/auth/resource`.ts file. We've configured it to support email and password login but you can extend it to support a variety of login mechanisms, including Google, Amazon, Sign In With Apple, and Facebook.
+
+The fastest way to get your login experience up and running is to use our Authenticator UI component available in the Amplify UI library.
+
+To use the Authenticator, you need to add the following dependencies to your project:
+
+```bash title="Terminal" showLineNumbers={false}
+npm add \
+ @aws-amplify/ui-react-native \
+ @aws-amplify/react-native \
+ aws-amplify \
+ @react-native-community/netinfo \
+ @react-native-async-storage/async-storage \
+ react-native-safe-area-context@^4.2.5 \
+ react-native-get-random-values \
+ react-native-url-polyfill
+```
+
+Then install the iOS cocoapods for targeting iOS by running:
+
+```bash title="Terminal" showLineNumbers={false}
+npx pod-install
+```
+
+Next, update the `App.tsx` file with the following:
+
+```typescript
+import React from "react";
+import { Button, View, StyleSheet } from "react-native";
+
+import { Amplify } from "aws-amplify";
+import { Authenticator, useAuthenticator } from "@aws-amplify/ui-react-native";
+
+import outputs from "./amplify_outputs.json";
+
+Amplify.configure(outputs);
+
+const SignOutButton = () => {
+ const { signOut } = useAuthenticator();
+
+ return (
+
+
+
+ );
+};
+
+const App = () => {
+ return (
+
+
+
+
+
+ );
+};
+
+const styles = StyleSheet.create({
+ signOutButton: {
+ alignSelf: "flex-end",
+ },
+});
+
+export default App;
+```
+
+The Authenticator component auto-detects your auth backend settings and renders the correct UI state based on the auth backend's authentication flow.
+
+Run your application in your local environment again. You should be presented with a login experience now.
+
+## Adding Data
+
+The initial scaffolding already has a pre-configured data backend defined in the `amplify/data/resource.ts` file. The default example will create a Todo model with `content` field.
+
+Let's modify this to add the following:
+- A boolean `isDone` field.
+- An authorization rules specifying owners, authenticated via your Auth resource can "create", "read", "update", and "delete" their own records.
+- Update the `defaultAuthorizationMode` to sign API requests with the user authentication token.
+
+```typescript
+import { type ClientSchema, a, defineData } from '@aws-amplify/backend';
+
+const schema = a.schema({
+ Todo: a
+ .model({
+ content: a.string(),
+ isDone: a.boolean()
+ })
+ .authorization(allow => [allow.owner()])
+});
+
+export type Schema = ClientSchema;
+
+export const data = defineData({
+ schema,
+ authorizationModes: {
+ defaultAuthorizationMode: 'userPool'
+ }
+});
+```
+
+Next, let's implement UI to create, list, and delete the to-do items. Create a `src` folder, and within the folder, create a new file called `TodoList.tsx`. This page will contain information about creating, reading, updating, and deleting Todo items.
+
+Copy and paste the following code into the file:
+
+```typescript
+import { useState, useEffect } from "react";
+import { View, Button, Text, StyleSheet, FlatList } from "react-native";
+
+import { generateClient } from "aws-amplify/data";
+import type { Schema } from "../amplify/data/resource";
+import { GraphQLError } from "graphql";
+const client = generateClient();
+
+const TodoList = () => {
+ const dateTimeNow = new Date();
+ const [todos, setTodos] = useState([]);
+ const [errors, setErrors] = useState();
+
+ useEffect(() => {
+ const sub = client.models.Todo.observeQuery().subscribe({
+ next: ({ items }) => {
+ setTodos([...items]);
+ },
+ });
+
+ return () => sub.unsubscribe();
+ }, []);
+
+ const createTodo = async () => {
+ try {
+ await client.models.Todo.create({
+ content: `${dateTimeNow.getUTCMilliseconds()}`,
+ });
+ } catch (error: unknown) {
+ if (error instanceof GraphQLError) {
+ setErrors(error);
+ } else {
+ throw error;
+ }
+ }
+ };
+
+ if (errors) {
+ return {errors.message};
+ }
+
+ const renderItem = ({ item }: { item: Schema["Todo"]["type"] }) => (
+
+ );
+ return (
+
+ item.id}
+ ItemSeparatorComponent={() => (
+
+ )}
+ ListEmptyComponent={() => The todo list is empty.}
+ style={styles.listContainer}
+ >
+
+
+ );
+};
+
+const TodoItem = (todo: Schema["Todo"]["type"]) => (
+
+
+ {todo.content}
+
+
+);
+
+const styles = StyleSheet.create({
+ todoItemContainer: { flexDirection: "row", alignItems: "center", padding: 8 },
+ todoItemText: { flex: 1, textAlign: "center" },
+ listContainer: { flex: 1, alignSelf: "stretch", padding:8 },
+ listItemSeparator: { backgroundColor: "lightgrey", height: 2 },
+});
+
+export default TodoList;
+```
+
+With the code above, you can create a random todo item and display todo items in a list. You can mark them as done, update the list, or revert that operation. You can also delete the items. Each change in the list is listened to with the subscription and immediately shown on the screen.
+
+If we take a closer look at the code:
+- `generateClient` generates the necessary files and folders for models.
+- `TodoList` component includes the subscription, creation operations, and a list to hold created items.
+- `TodoItem` holds the information about each todo item.
+
+Lastly, update the `App` component in `App.tsx` as follows:
+
+```typescript
+const App = () => {
+ return (
+
+
+
+
+
+
+
+
+ );
+};
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ padding: 8,
+ },
+ signOutButton: {
+ alignSelf: "flex-end",
+ },
+});
+```
+
+If you run the application now, you should see the following behavior:
+
+You can terminate the sandbox environment now to clean up the project.
+
+### Publishing changes to cloud
+
+Publishing changes to the cloud requires a remote git repository. Amplify offers fullstack branch deployments that allow you to automatically deploy infrastructure and application code changes from feature branches. To learn more, visit the [fullstack branch deployments guide](/[platform]/deploy-and-host/fullstack-branching/branch-deployments).
+
+
+
+## π₯³ Success
+
+That's it! You have successfully built a fullstack app on AWS Amplify. If you want to learn more about how to work with Amplify, here's the conceptual guide for [how Amplify works](/[platform]/how-amplify-works/concepts/).
+
+
+---
+
+---
+title: "Next.js Pages Router"
+section: "start/quickstart"
+platforms: ["nextjs"]
+gen: 2
+last-updated: "2024-11-12T21:56:50.000Z"
+url: "https://docs.amplify.aws/react/start/quickstart/nextjs-pages-router/"
+---
+
+## Pre-requisites
+
+This Quickstart guide will walk you through how to build a task list application with TypeScript, Next.js **Pages Router with Client Components**, and React. Before you begin, make sure you have the following installed:
+
+- [Node.js](https://nodejs.org/) v14.x or later
+- [npm](https://www.npmjs.com/) v6.14.4 or later
+- [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/pages/getting-started), and [TypeScript](https://www.typescriptlang.org/docs/handbook/typescript-from-scratch.html) tutorials first.
+
+## 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 (Pages) template.
+
+### 1. Create the repository
+
+Use our starter template to create a repository in your GitHub account. This template scaffolds `create-next-app` with Amplify backend capabilities.
+
+
+
+Create repository from template
+
+
+Use the form in GitHub to finalize your repo's creation.
+
+### 2. Deploy the starter app
+
+Now that the repository has been created, deploy it with Amplify.
+
+
+
+Deploy to AWS
+
+
+Select **Start with an existing app** > **GitHub**. After you give Amplify access to your GitHub account via the popup window, pick the repository and `main` branch to deploy. Make no other changes and click through the flow to **Save and deploy**.
+
+### 3. View deployed app
+
+
+
+Let's take a tour of the project structure in this starter repository by opening it on GitHub. The starter application has pre-written code for a to-do list app. It gives you a real-time database with a feed of all to-do list items and the ability to add new items.
+
+```text
+βββ amplify/ # Folder containing your Amplify backend configuration
+β βββ auth/ # Definition for your auth backend
+β β βββ resource.tsx
+β βββ data/ # Definition for your data backend
+β β βββ resource.ts
+| βββ backend.ts
+β βββ tsconfig.json
+βββ src/ # React UI code
+β βββ App.tsx # UI code to sync todos in real-time
+β βββ index.css # Styling for your app
+β βββ main.tsx # Entrypoint of the Amplify client library
+βββ package.json
+βββ tsconfig.json
+```
+
+
+ When the build completes, visit the newly deployed branch by selecting "View deployed URL". Since the build deployed an API, database, and authentication backend, you will be able to create new to-do items.
+
+In the Amplify console, click into the deployment branch (in this case **main**) > select **Data** in the left-hand menu > **Data manager** to see the data entered in your database.
+
+## Make frontend updates
+
+Let's learn how to enhance the app functionality by creating a delete flow for to-do list items.
+
+### 4. Set up local environment
+
+Now let's set up our local development environment to add features to the frontend. Click on your deployed branch and you will land on the **Deployments** page which shows you your build history and a list of deployed backend resources.
+
+At the bottom of the page you will see a tab for **Deployed backend resources**. Click on the tab and then click the **Download amplify_outputs.json file** button.
+
+
+
+Clone the repository locally.
+
+```bash title="Terminal" showLineNumbers={false}
+git clone https://github.com//amplify-next-template.git
+cd amplify-next-template && npm install
+```
+
+Now move the `amplify_outputs.json` file you downloaded above to the root of your project.
+
+```text
+βββ amplify
+βββ src
+βββ amplify_outputs.json <== backend outputs file
+βββ package.json
+βββ tsconfig.json
+```
+
+
+The **amplify_outputs.json** file contains backend endpoint information, publicly-viewable API keys, authentication flow information, and more. The Amplify client library uses this outputs file to connect to your Amplify Backend. You can review how the outputs file is imported within the `main.tsx` file and then passed into the `Amplify.configure(...)` function of the Amplify client library.
+
+
+### 5. Implement delete functionality
+
+Go to the **pages/index.tsx** file and add in a new `deleteTodo` functionality and pass function into the `
+
+ )
+}
+```
+See the complete amplify/data/resources.ts
+
+Open the `amplify/data/resource.ts` file in your text editor, and you will see a default data model generated for you.
+
+```ts showLineNumbers title="amplify/data/resource.ts"
+import { type ClientSchema, a, defineData } from '@aws-amplify/backend';
+
+const schema = a.schema({
+ Todo: a
+ .model({
+ content: a.string()
+ })
+ .authorization(allow => [allow.owner(), allow.publicApiKey().to(['read'])])
+});
+
+export type Schema = ClientSchema;
+
+export const data = defineData({
+ schema,
+ authorizationModes: {
+ defaultAuthorizationMode: 'apiKey',
+ // API Key is used for allow.publicApiKey() rules
+ apiKeyAuthorizationMode: {
+ expiresInDays: 30
+ }
+ }
+});
+```
+
+ The schema generated by Amplify is for a to-do app. A schema is a blueprint
+ for how our app's data will be organized. Within the schema, we will define
+ models that will correspond to a database tableβ`Todo` in the above code.
+ Finally, we will define fields, which are attributes that each data instance
+ will haveβin the generated code, the field is `content`. Each
+ field will have a type attached to itβin the above examples, we are stating
+ that the `content` field is a string.
+
+
+Try out the deletion functionality now by starting the local dev server:
+
+```bash title="Terminal" showLineNumbers={false}
+npm run dev
+```
+
+This should start a local dev server at http://localhost:3000.
+
+### 6. Implement login UI
+
+The starter application already has a pre-configured auth backend defined in the **amplify/auth/resource.ts** file. We've configured it to support email and password login but you can extend it to support a variety of login mechanisms, including Google, Amazon, Sign In With Apple, and Facebook.
+
+The fastest way to get your login experience up and running is to use our Authenticator UI component. In your **pages/_app.tsx** file, import the Authenticator UI component and wrap your `` component.
+
+```tsx title="pages/_app.tsx"
+import type { AppProps } from "next/app";
+// highlight-start
+import { Authenticator } from '@aws-amplify/ui-react'
+import '@aws-amplify/ui-react/styles.css'
+// highlight-end
+import "@/styles/app.css";
+import { Amplify } from "aws-amplify";
+import outputs from "@/amplify_outputs.json";
+
+Amplify.configure(outputs);
+
+export default function App({ Component, pageProps }: AppProps) {
+ return(
+ // highlight-start
+
+ ;
+
+ // highlight-end
+ )
+}
+```
+See the complete amplify/auth/resources.ts
+
+```ts title="amplify/auth/resource.ts"
+import { defineAuth } from '@aws-amplify/backend';
+
+/**
+ * Define and configure your auth resource
+ * When used alongside data, it is automatically configured as an auth provider for data
+ * @see https://docs.amplify.aws/gen2/build-a-backend/auth
+ */
+export const auth = defineAuth({
+ loginWith: {
+ email: true,
+ // add social providers
+ externalProviders: {
+ /**
+ * first, create your secrets using `ampx sandbox secret`
+ * then, import `secret` from `@aws-amplify/backend`
+ * @see https://docs.amplify.aws/gen2/deploy-and-host/sandbox-environments/features/#setting-secrets
+ */
+ // loginWithAmazon: {
+ // clientId: secret('LOGINWITHAMAZON_CLIENT_ID'),
+ // clientSecret: secret('LOGINWITHAMAZON_CLIENT_SECRET'),
+ // }
+ }
+ },
+ /**
+ * enable multifactor authentication
+ * @see https://docs.amplify.aws/gen2/build-a-backend/auth/manage-mfa
+ */
+ // multifactor: {
+ // mode: 'OPTIONAL',
+ // sms: {
+ // smsMessage: (code) => `Your verification code is ${code}`,
+ // },
+ // },
+ userAttributes: {
+ /** request additional attributes for your app's users */
+ // profilePicture: {
+ // mutable: true,
+ // required: false,
+ // },
+ }
+});
+```
+
+
+The Authenticator component auto-detects your auth backend settings and renders the correct UI state based on the auth backend's authentication flow.
+
+In your **pages/index.tsx** file, add a button to enable users to sign out of the application. Import the [`useAuthenticator`](https://ui.docs.amplify.aws/react/connected-components/authenticator/advanced#access-auth-state) hook from the Amplify UI library to hook into the state of the Authenticator.
+
+```tsx title="pages/index.tsx"
+import type { Schema } from "@/amplify/data/resource";
+// highlight-next-line
+import { useAuthenticator } from "@aws-amplify/ui-react";
+import { useState, useEffect } from "react";
+import { generateClient } from "aws-amplify/data";
+
+const client = generateClient();
+
+export default function HomePage() {
+
+ // highlight-start
+ const { signOut } = useAuthenticator();
+ // highlight-end
+
+ // ...
+
+ return (
+
+ {/* ... */}
+ // highlight-next-line
+ Sign out
+
+ );
+}
+```
+
+Try out your application in your localhost environment again. You should be presented with a login experience now.
+
+To get these changes to the cloud, commit them to git and push the changes upstream.
+
+```bash title="Terminal" showLineNumbers={false}
+git commit -am "added authenticator"
+git push
+```
+
+Amplify automatically deploys the latest version of your app based on your git commits. In just a few minutes, when the application rebuilds, the hosted app will be updated to support the deletion functionality.
+
+## Make backend updates
+
+Let's update our backend to implement per-user authorization rules, allowing each user to only access their own to-dos.
+
+### 7. Set up local AWS credentials
+
+To make backend updates, we are going to require AWS credentials to deploy backend updates from our local machine.
+
+**Skip ahead to step 8**, if you already have an AWS profile with credentials on your local machine, and your AWS profile has the `AmplifyBackendDeployFullAccess` permission policy.
+
+Otherwise, **[set up local AWS credentials](/[platform]/start/account-setup/)** that grant Amplify permissions to deploy backend updates from your local machine.
+
+### 8. Deploy cloud sandbox
+
+To update your backend without affecting the production branch, use Amplify's cloud sandbox. This feature provides a separate backend environment for each developer on a team, ideal for local development and testing.
+
+To start your cloud sandbox, run the following command in a **new Terminal window**:
+
+```bash title="Terminal" showLineNumbers={false}
+npx ampx sandbox
+```
+
+Once the cloud sandbox has been fully deployed (~5 min), you'll see the `amplify_outputs.json` file updated with connection information to a new isolated authentication and data backend.
+
+> **Info:** The `npx ampx sandbox` command should run concurrently to your `npm run dev`. You can think of the cloud sandbox as the "localhost-equivalent for your app backend".
+
+### 9. Implement per-user authorization
+
+The to-do items in the starter are currently shared across all users, but, in most cases, you want data to be isolated on a per-user basis.
+
+To isolate the data on a per-user basis, you can use an "owner-based authorization rule". Let's apply the owner-based authorization rule to your to-do items:
+
+```ts title="amplify/data/resource.ts"
+import { type ClientSchema, a, defineData } from '@aws-amplify/backend';
+
+const schema = a.schema({
+ Todo: a.model({
+ content: a.string(),
+ // highlight-next-line
+ }).authorization(allow => [allow.owner()]),
+});
+
+export type Schema = ClientSchema;
+
+export const data = defineData({
+ schema,
+ authorizationModes: {
+ // This tells the data client in your app (generateClient())
+ // to sign API requests with the user authentication token.
+ // highlight-next-line
+ defaultAuthorizationMode: 'userPool',
+ },
+});
+```
+
+In the application client code, let's also render the username to distinguish different users once they're logged in. Go to your **pages/index.tsx** file and render the `user` property from the `useAuthenticator` hook.
+
+```tsx title="pages/index.tsx"
+// ... imports
+
+function HomePage() {
+ // highlight-next-line
+ const { user, signOut } = useAuthenticator();
+
+ // ...
+
+ return (
+
+ // highlight-next-line
+
{user?.signInDetails?.loginId}'s todos
+ {/* ... */}
+
+ )
+}
+```
+
+Now, let's go back to your local application and test out the user isolation of the to-do items.
+
+You will need to sign up new users again because now you're working with the cloud sandbox instead of your production backend.
+
+To get these changes to the cloud, commit them to git and push the changes upstream.
+
+```bash title="Terminal" showLineNumbers={false}
+git commit -am "added per-user data isolation"
+git push
+```
+
+Once your build completes in the Amplify Console, the `main` backend will update to support the changes made within the cloud sandbox. The data in the cloud sandbox is fully isolated and won't pollute your production database.
+
+## π₯³ Success
+
+That's it! You have successfully built a fullstack app on AWS Amplify. If you want to learn more about how to work with Amplify, here's the conceptual guide for [how Amplify works](/[platform]/how-amplify-works/concepts/).
+
+---
+
+---
+title: "Next.js App Router"
+section: "start/quickstart"
+platforms: ["nextjs"]
+gen: 2
+last-updated: "2025-07-24T13:26:03.000Z"
+url: "https://docs.amplify.aws/react/start/quickstart/nextjs-app-router-client-components/"
+---
+
+## Pre-requisites
+
+This Quickstart guide will walk you through how to build a task list application with TypeScript, Next.js **App Router with Client Components**, and React. Before you begin, make sure you have the following installed:
+
+- [Node.js](https://nodejs.org/) v14.x or later
+- [npm](https://www.npmjs.com/) v6.14.4 or later
+- [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/app/getting-started), and [TypeScript](https://www.typescriptlang.org/docs/handbook/typescript-from-scratch.html) tutorials first.
+
+## 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.
+
+### 1. Create the repository
+
+Use our starter template to create a repository in your GitHub account. This template scaffolds `create-next-app` with Amplify backend capabilities.
+
+
+
+Create repository from template
+
+
+Use the form in GitHub to finalize your repo's creation.
+
+### 2. Deploy the starter app
+
+Now that the repository has been created, deploy it with Amplify.
+
+
+
+Deploy to AWS
+
+
+Select **Start with an existing app** > **GitHub**. After you give Amplify access to your GitHub account via the popup window, pick the repository and `main` branch to deploy. Make no other changes and click through the flow to **Save and deploy**.
+
+### 3. View deployed app
+
+
+
+Let's take a tour of the project structure in this starter repository by opening it on GitHub. The starter application has pre-written code for a to-do list app. It gives you a real-time database with a feed of all to-do list items and the ability to add new items.
+
+```text
+βββ amplify/ # Folder containing your Amplify backend configuration
+β βββ auth/ # Definition for your auth backend
+β β βββ resource.tsx
+β βββ data/ # Definition for your data backend
+β β βββ resource.ts
+| βββ backend.ts
+β βββ tsconfig.json
+βββ src/ # React UI code
+β βββ App.tsx # UI code to sync todos in real-time
+β βββ index.css # Styling for your app
+β βββ main.tsx # Entrypoint of the Amplify client library
+βββ package.json
+βββ tsconfig.json
+```
+
+
+ When the build completes, visit the newly deployed branch by selecting "View deployed URL". Since the build deployed an API, database, and authentication backend, you will be able to create new to-do items.
+
+In the Amplify console, click into the deployment branch (in this case **main**) > select **Data** in the left-hand menu > **Data manager** to see the data entered in your database.
+
+## Make frontend updates
+
+Let's learn how to enhance the app functionality by creating a delete flow for to-do list items.
+
+### 4. Set up local environment
+
+Now let's set up our local development environment to add features to the frontend. Click on your deployed branch and you will land on the **Deployments** page which shows you your build history and a list of deployed backend resources.
+
+At the bottom of the page you will see a tab for **Deployed backend resources**. Click on the tab and then click the **Download amplify_outputs.json file** button.
+
+
+
+Clone the repository locally.
+
+```bash title="Terminal" showLineNumbers={false}
+git clone https://github.com//amplify-next-template.git
+cd amplify-next-template && npm install
+```
+
+Now move the `amplify_outputs.json` file you downloaded above to the root of your project.
+
+```text
+βββ amplify
+βββ src
+βββ amplify_outputs.json <== backend outputs file
+βββ package.json
+βββ tsconfig.json
+```
+
+
+The **amplify_outputs.json** file contains backend endpoint information, publicly-viewable API keys, authentication flow information, and more. The Amplify client library uses this outputs file to connect to your Amplify Backend. You can review how the outputs file is imported within the `main.tsx` file and then passed into the `Amplify.configure(...)` function of the Amplify client library.
+
+
+### 5. Implement delete functionality
+
+Go to the **app/page.tsx** file and add in a new `deleteTodo` functionality and pass function into the `
+
+ )
+}
+```
+See the complete amplify/data/resources.ts
+
+Open the `amplify/data/resource.ts` file in your text editor, and you will see a default data model generated for you.
+
+```ts showLineNumbers title="amplify/data/resource.ts"
+import { type ClientSchema, a, defineData } from '@aws-amplify/backend';
+
+const schema = a.schema({
+ Todo: a
+ .model({
+ content: a.string()
+ })
+ .authorization(allow => [allow.owner(), allow.publicApiKey().to(['read'])])
+});
+
+export type Schema = ClientSchema;
+
+export const data = defineData({
+ schema,
+ authorizationModes: {
+ defaultAuthorizationMode: 'apiKey',
+ // API Key is used for allow.publicApiKey() rules
+ apiKeyAuthorizationMode: {
+ expiresInDays: 30
+ }
+ }
+});
+```
+
+ The schema generated by Amplify is for a to-do app. A schema is a blueprint
+ for how our app's data will be organized. Within the schema, we will define
+ models that will correspond to a database tableβ`Todo` in the above code.
+ Finally, we will define fields, which are attributes that each data instance
+ will haveβin the generated code, the field is `content`. Each
+ field will have a type attached to itβin the above examples, we are stating
+ that the `content` field is a string.
+
+
+Try out the deletion functionality now by starting the local dev server:
+
+```bash title="Terminal" showLineNumbers={false}
+npm run dev
+```
+
+This should start a local dev server at http://localhost:3000.
+
+### 6. Implement login UI
+
+The starter application already has a pre-configured auth backend defined in the **amplify/auth/resource.ts** file. We've configured it to support email and password login but you can extend it to support a variety of login mechanisms, including Google, Amazon, Sign In With Apple, and Facebook.
+
+The fastest way to get your login experience up and running is to use our Authenticator UI component. To properly integrate it with Next.js App Router, we'll create a client component wrapper and use it in the layout.
+
+First, create an AuthenticatorWrapper.tsx file in your app directory:
+
+```tsx title="app/AuthenticatorWrapper.tsx"
+"use client"
+
+import { Authenticator } from "@aws-amplify/ui-react";
+
+export default function AuthenticatorWrapper({
+ children,
+}: {
+ children: React.ReactNode;
+}) {
+ return {children};
+}
+```
+
+Next, update your app/layout.tsx file to import and use the AuthenticatorWrapper component:
+
+```tsx title="app/layout.tsx"
+
+import React from "react";
+import { Amplify } from "aws-amplify";
+import "./app.css";
+// highlight-start
+import AuthenticatorWrapper from "./AuthenticatorWrapper";
+import "@aws-amplify/ui-react/styles.css";
+// highlight-end
+import outputs from "@/amplify_outputs.json";
+
+Amplify.configure(outputs);
+
+export default function RootLayout({
+ children,
+}: {
+ children: React.ReactNode;
+}) {
+ return (
+ // highlight-start
+
+
+
+ {children}
+
+
+
+ // highlight-end
+ );
+}
+```
+
+The Authenticator component auto-detects your auth backend settings and renders the correct UI state based on the auth backend's authentication flow.
+
+In your **app/page.tsx** file, add a button to enable users to sign out of the application. Import the [`useAuthenticator`](https://ui.docs.amplify.aws/react/connected-components/authenticator/advanced#access-auth-state) hook from the Amplify UI library to hook into the state of the Authenticator.
+
+```tsx title="app/page.tsx"
+import type { Schema } from "@/amplify/data/resource";
+// highlight-next-line
+import { useAuthenticator } from "@aws-amplify/ui-react";
+import { useState, useEffect } from "react";
+import { generateClient } from "aws-amplify/data";
+
+const client = generateClient();
+
+export default function HomePage() {
+
+ // highlight-start
+ const { signOut } = useAuthenticator();
+ // highlight-end
+
+ // ...
+
+ return (
+
+ {/* ... */}
+ // highlight-next-line
+ Sign out
+
+ );
+}
+```
+
+Try out your application in your localhost environment again. You should be presented with a login experience now.
+
+To get these changes to the cloud, commit them to git and push the changes upstream.
+
+```bash title="Terminal" showLineNumbers={false}
+git commit -am "added authenticator"
+git push
+```
+
+Amplify automatically deploys the latest version of your app based on your git commits. In just a few minutes, when the application rebuilds, the hosted app will be updated to support the deletion functionality.
+
+## Make backend updates
+
+Let's update our backend to implement per-user authorization rules, allowing each user to only access their own to-dos.
+
+### 7. Set up local AWS credentials
+
+To make backend updates, we are going to require AWS credentials to deploy backend updates from our local machine.
+
+**Skip ahead to step 8**, if you already have an AWS profile with credentials on your local machine, and your AWS profile has the `AmplifyBackendDeployFullAccess` permission policy.
+
+Otherwise, **[set up local AWS credentials](/[platform]/start/account-setup/)** that grant Amplify permissions to deploy backend updates from your local machine.
+
+### 8. Deploy cloud sandbox
+
+To update your backend without affecting the production branch, use Amplify's cloud sandbox. This feature provides a separate backend environment for each developer on a team, ideal for local development and testing.
+
+To start your cloud sandbox, run the following command in a **new Terminal window**:
+
+```bash title="Terminal" showLineNumbers={false}
+npx ampx sandbox
+```
+
+Once the cloud sandbox has been fully deployed (~5 min), you'll see the `amplify_outputs.json` file updated with connection information to a new isolated authentication and data backend.
+
+> **Info:** The `npx ampx sandbox` command should run concurrently to your `npm run dev`. You can think of the cloud sandbox as the "localhost-equivalent for your app backend".
+
+### 9. Implement per-user authorization
+
+The to-do items in the starter are currently shared across all users, but, in most cases, you want data to be isolated on a per-user basis.
+
+To isolate the data on a per-user basis, you can use an "owner-based authorization rule". Let's apply the owner-based authorization rule to your to-do items:
+
+```ts title="amplify/data/resource.ts"
+import { type ClientSchema, a, defineData } from '@aws-amplify/backend';
+
+const schema = a.schema({
+ Todo: a.model({
+ content: a.string(),
+ // highlight-next-line
+ }).authorization(allow => [allow.owner()]),
+});
+
+export type Schema = ClientSchema;
+
+export const data = defineData({
+ schema,
+ authorizationModes: {
+ // This tells the data client in your app (generateClient())
+ // to sign API requests with the user authentication token.
+ // highlight-next-line
+ defaultAuthorizationMode: 'userPool',
+ },
+});
+```
+
+In the application client code, let's also render the username to distinguish different users once they're logged in. Go to your **app/page.tsx** file and render the `user` property from the `useAuthenticator` hook.
+
+```tsx title="app/page.tsx"
+// ... imports
+
+function HomePage() {
+ // highlight-next-line
+ const { user, signOut } = useAuthenticator();
+
+ // ...
+
+ return (
+
+ // highlight-next-line
+
{user?.signInDetails?.loginId}'s todos
+ {/* ... */}
+
+ )
+}
+```
+
+Now, let's go back to your local application and test out the user isolation of the to-do items.
+
+You will need to sign up new users again because now you're working with the cloud sandbox instead of your production backend.
+
+To get these changes to the cloud, commit them to git and push the changes upstream.
+
+```bash title="Terminal" showLineNumbers={false}
+git commit -am "added per-user data isolation"
+git push
+```
+
+Once your build completes in the Amplify Console, the `main` backend will update to support the changes made within the cloud sandbox. The data in the cloud sandbox is fully isolated and won't pollute your production database.
+
+## π₯³ Success
+
+That's it! You have successfully built a fullstack app on AWS Amplify. If you want to learn more about how to work with Amplify, here's the conceptual guide for [how Amplify works](/[platform]/how-amplify-works/concepts/).
+
+---
+
+---
+title: "Configure AWS for local development"
+section: "start"
+platforms: ["android", "angular", "flutter", "javascript", "nextjs", "react", "react-native", "swift", "vue"]
+gen: 2
+last-updated: "2025-01-24T20:22:12.000Z"
+url: "https://docs.amplify.aws/react/start/account-setup/"
+---
+
+> **Info:** **Note**: If you already have an AWS account and profile configured locally, you do not need to follow this guide. Please add the`AmplifyBackendDeployFullAccess` IAM role to your configured AWS profile.
+
+This guide will help you set up Temporary credentials with [IAM Identity Center](https://docs.aws.amazon.com/singlesignon/latest/userguide/what-is.html) and [AWS Organizations](https://docs.aws.amazon.com/organizations/latest/userguide/orgs_introduction.html), which will enable you to define Single-sign on (SSO), users, groups, permission sets, and more for your team. AWS Organizations can grow to house multiple AWS accounts. Users within the organization can traverse the AWS account(s) as their permission set allows.
+
+Amplify leverages the standard local credentials chain provider to simplify access to AWS services. While this guide highlights IAM Identity Center, you can explore additional methods for [authenticating with AWS locally](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-quickstart.html#getting-started-prereqs-keys).
+
+IAM Identity Center terminology
+
+IAM Identity Center enables users to sign in using a single user identity to access all their assigned AWS accounts, business applications, and custom applications in the AWS Cloud. This single sign-on capability reduces the complexity of managing multiple credentials and improves security by centralizing user authentication.
+
+### Users
+
+Users refers to the location where user identities and group information are stored and managed. IAM Identity Center can integrate with external identity sources like Microsoft Active Directory or use a built-in identity store provided by AWS.
+
+### Permission Set
+
+A collection of permissions that can be assigned to users or groups. Permission sets define what actions users are allowed to perform in your AWS accounts. They are similar to IAM policies but are used within the context of IAM Identity Center to manage access across multiple accounts.
+
+### AWS Organization
+
+AWS Organizations and IAM Identity Center work together to streamline management across multiple AWS accounts. AWS Organizations manages account structures and policies, while IAM Identity Center integrates with it to enable single sign-on and align permissions with organizational roles. This synergy ensures secure and consistent access control, simplifying user and permission management.
+
+### Local Profiles
+
+Credentials are typically resolved through the use of [AWS profiles](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-files.html#cli-configure-files-using-profiles). Profiles can contain permanent credentials or SSO metadata, and can be set for use with Amplify by using the same techniques as the AWS CLI:
+
+- with the `--profile` flag
+- with the `AWS_PROFILE` environment variable
+
+### Temporary credentials
+
+An alternative to permanent credentials, enable you to define permissions for a _session_. Sessions are created when you [_assume_ an IAM role](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use.html) or sign in using AWS IAM Identity Center. These sessions come with an additional "session token" that is used to validate the temporary credentials and must be included on requests to AWS. As you are working locally, this will be presented as an additional environment variable.
+
+You can use temporary security credentials to make programmatic requests for AWS resources using the AWS CLI or AWS API (through the AWS SDKs). The temporary credentials provide the same permissions as long-term security credentials, such as IAM user credentials. However, there are a few differences, which are covered in the [AWS Identity and Access Management documentation](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_use-resources.html).
+
+
+
+## Set up Identity Center
+
+Follow the steps below if **you have never set up AWS profiles before**.
+
+If you already have a profile, attach the [`AmplifyBackendDeployFullAccess`](https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AmplifyBackendDeployFullAccess.html) managed policy to your [IAM user](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_users_change-permissions.html#users_change_permissions-add-console).
+
+### 1. Create user with Amplify permissions
+
+Sign in to the AWS Console to access [IAM Identity Center page](https://console.aws.amazon.com/singlesignon/home) and choose **Enable**.
+
+
+
+A dialog will open, prompting you to "Choose how to configure IAM Identity Center in your AWS environment." Select **Enable with AWS Organizations** and choose **Continue**.
+
+
+
+Next, we are going to automate a number of steps that simulate the operations of setting up a user in the IAM Identity Center console. To get started open CloudShell, located in the console footer.
+
+Paste the following command in the CloudShell terminal and enter an email address you would like to associate with this AWS account:
+
+```bash title="CloudShell" showLineNumbers={false}
+read -p "Enter email address: " user_email # hit enter
+```
+
+```console showLineNumbers={false}
+Enter email address:
+```
+
+Now, run the following command
+
+```bash title="CloudShell"
+response=$(aws sso-admin list-instances)
+ssoId=$(echo $response | jq '.Instances[0].IdentityStoreId' -r)
+ssoArn=$(echo $response | jq '.Instances[0].InstanceArn' -r)
+email_json=$(jq -n --arg email "$user_email" '{"Type":"Work","Value":$email}')
+response=$(aws identitystore create-user --identity-store-id $ssoId --user-name amplify-admin --display-name 'Amplify Admin' --name Formatted=string,FamilyName=Admin,GivenName=Amplify --emails "$email_json")
+userId=$(echo $response | jq '.UserId' -r)
+response=$(aws sso-admin create-permission-set --name amplify-policy --instance-arn=$ssoArn --session-duration PT12H)
+permissionSetArn=$(echo $response | jq '.PermissionSet.PermissionSetArn' -r)
+aws sso-admin attach-managed-policy-to-permission-set --instance-arn $ssoArn --permission-set-arn $permissionSetArn --managed-policy-arn arn:aws:iam::aws:policy/service-role/AmplifyBackendDeployFullAccess
+accountId=$(aws sts get-caller-identity | jq '.Account' -r)
+aws sso-admin create-account-assignment --instance-arn $ssoArn --target-id $accountId --target-type AWS_ACCOUNT --permission-set-arn $permissionSetArn --principal-type USER --principal-id $userId
+# Hit enter
+```
+
+To validate that this worked, run the following command in the CloudShell. If something failed in this process, please **[report an issue](https://github.com/aws-amplify/amplify-backend/issues)**. Keep this information readily available for [the next step](#2-set-up-local-aws-profile).
+
+```bash title="CloudShell" showLineNumbers={false}
+// highlight-next-line
+printf "\n\nStart session url: https://$ssoId.awsapps.com/start\nRegion: $AWS_REGION\nUsername: amplify-admin\n\n"
+
+# you should see
+Start session url: https://d-XXXXXXXXXX.awsapps.com/start
+Region: us-east-1
+Username: amplify-admin
+```
+
+Prefer a manual set up?
+
+- After the AWS Organization is created and IAM Identity Center is enabled, you are presented with a dashboard. In the navigation pane, select **Permission sets**.
+
+ 
+
+- Select **Create permission set**.
+- When prompted for the permission set type, choose **Custom permission set**. Then choose **Next**. Expand **AWS Managed Policies (set)** and search for _amplify_. Select **AmplifyBackendDeployFullAccess** and choose **Next**.
+
+ 
+
+- Name the permission set _amplify-policy_ and optionally change the session duration. Choose **Next**.
+
+ 
+
+- Review the permission set and choose **Create**.
+- Once the permission set is created, you will return to the IAM Identity Center dashboard. You are now ready to create your first user. Using the navigation pane, select **Users**.
+- Enter the user details, then choose **Next**.
+
+ 
+
+- Optionally create and add the user to a group, and choose **Next**.
+- Review the user information and select **Add user**. The user will then need to verify their email using the email specified during user creation.
+- Once the new user is created, you will return to the IAM Identity Center dashboard. The next step is to grant the user access to an AWS account. For this demo, we will use the AWS account we used to create the Organization, but you can create a new AWS account under your organization for use with Amplify. Select the checkbox next to the management account and choose **Assign users or groups**.
+
+ 
+
+- When prompted to assign a user or group, select the **Users** tab, select the user created in step 13, and choose **Next**.
+
+ 
+
+- Assign the permission set created in step 9 and choose **Next**.
+- Review the assignment information and choose **Submit**.
+- Now you are ready to sign in to the access portal. Navigate back to the IAM Identity Center dashboard. Within the **Settings summary** pane, copy the URL for your **AWS access portal URL**.
+
+ 
+
+- Navigate to the copied URL and sign in as your user, _amplify-admin_. After signing in, you should have access to an AWS account.
+
+ 
+
+
+
+### 2. Create password for user
+
+Now create a password for the user that we need for the next step. In the IdC console, navigate to _Users > amplify_admin > Reset password > Send an email to the user with instructions for resetting the password_.
+
+Check your email (make sure you also check your spam folder). Click on the _Reset password_ link and choose a password of your choice. When signing in make sure to use _amplify-admin_ as the _Username_.
+
+
+
+## Finish local setup
+
+Now, set up an AWS profile that is linked to the user you just created on your local machine. There are a few options for [getting IAM Identity Center user credentials](https://docs.aws.amazon.com/singlesignon/latest/userguide/howtogetcredentials.html), but we will use the AWS CLI configuration wizard.
+
+### 3. Install the AWS CLI
+
+Install the [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html).
+
+#### [Mac]
+In your browser, download the macOS pkg file:
+
+[Install on Mac](https://awscli.amazonaws.com/AWSCLIV2.pkg)
+
+#### [Windows]
+In your browser, Download and run the AWS CLI MSI installer for Windows (64-bit):
+
+[Install on Windows](https://awscli.amazonaws.com/AWSCLIV2.msi)
+
+To install the AWS CLI, run the following commands.
+
+#### [Linux]
+
+```bash showLineNumbers={false}
+curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
+unzip awscliv2.zip
+./aws/install -i /usr/local/aws-cli -b /usr/local/bin
+```
+
+### 4. Set up local AWS profile
+
+Open your terminal, you are ready to configure an AWS profile that uses the SSO user. Use the information from CloudShell to populate the information below.
+
+```console title="Terminal" showLineNumbers={false}
+//highlight-next-line
+aws configure sso
+
+| SSO session name (Recommended): amplify-admin
+| SSO start URL:
+| SSO region:
+| SSO registration scopes [sso:account:access]:
+| Attempting to automatically open the SSO authorization page in your default browser.
+| If the browser does not open or you wish to use a different device to authorize this request, open the following URL:
+|
+| https://device.sso.us-east-2.amazonaws.com/
+|
+| Then enter the code:
+|
+| SOME-CODE
+
+## browser opens
+```
+
+After you provide this information, the browser will automatically open asking you to sign in with the username and password you just created and configure a multi-factor device to authenticate.
+
+Now return to the terminal and enter the following information:
+
+```console title="Terminal" showLineNumbers={false}
+The only AWS account available to you is:
+Using the account ID
+The only role available to you is: amplify-policy
+Using the role name "amplify-policy"
+CLI default client Region [us-east-1]:
+CLI default output format [None]:
+```
+
+**Make sure to set the profile name to `default`**. Alternatively, remember the auto-generated profile name; you will need this later.
+
+```console title="Terminal" showLineNumbers={false}
+CLI profile name [amplify-policy-]: default
+To use this profile, specify the profile name using --profile, as shown:
+
+aws s3 ls --profile default
+```
+
+If you inspect `~/.aws/config`, you should now see the SSO profile:
+
+```ini title="~/.aws/config"
+[profile default]
+sso_session = amplify-admin
+sso_account_id =
+sso_role_name = AdministratorAccess
+region =
+[sso-session amplify-admin]
+sso_start_url = https://xxxxxx.awsapps.com/start#
+sso_region =
+sso_registration_scopes = sso:account:access
+```
+
+### 5. Bootstrap your AWS account
+
+Now you are ready to use this AWS profile with AWS Amplify. Open your Amplify project and start the sandbox. If you have multiple local profiles or named your profile something other than `default`, you can specify a profile with `--profile`.
+
+```bash title="Terminal" showLineNumbers={false}
+// highlight-next-line
+npx ampx sandbox
+
+# OR
+
+// highlight-next-line
+npx ampx sandbox --profile
+
+```
+
+Before you can start deploying resources in the cloud sandbox environment, Amplify will need to complete a one-time bootstrap setup for the account and AWS Region before it can start deploying resources.
+
+What is bootstrapping?
+
+Bootstrapping is the process of provisioning resources for the AWS CDK before you can deploy AWS CDK apps into an AWS environment. These resources include an Amazon S3 bucket for storing files and IAM roles that grant permissions needed to perform deployments. The required resources are defined in an AWS CloudFormation stack, called the bootstrap stack, which is usually named `CDKToolkit`. Like any AWS CloudFormation stack, it appears in the AWS CloudFormation console once it is deployed. You can learn more about this process in the [CDK documentation](https://docs.aws.amazon.com/cdk/v2/guide/bootstrapping.html).
+
+
+
+```bash title="Terminal" showLineNumbers={false}
+npx ampx sandbox --profile amplify-admin
+The region us-east-1 has not been bootstrapped. Sign in to the AWS console as a Root user or Admin to complete the bootstrap process, then restart the sandbox.
+If this is not the region you are expecting to bootstrap, check for any AWS environment variables that may be set in your shell or use --profile to specify a profile with the correct region.
+```
+
+During the first-time setup, `npx ampx sandbox` will ask you to sign in to the AWS Management Console. You must sign in as the account **root user** or as a user that has **AdministratorAccess** permissions. Once signed in, you will be redirected to the Amplify console. On the **Create new app** page, choose **Initialize setup now**. It may take a few minutes for the bootstrapping process to complete.
+
+
+
+## Success
+
+You have successfully completed the bootstrapping process and you can now return to the terminal to create a new Amplify sandbox environment:
+
+```bash showLineNumbers={false}
+npx ampx sandbox --profile
+```
+
+---
+
+---
+title: "Manual installation"
+section: "start"
+platforms: ["android", "angular", "flutter", "javascript", "nextjs", "react", "react-native", "swift", "vue"]
+gen: 2
+last-updated: "2024-10-28T20:46:05.000Z"
+url: "https://docs.amplify.aws/react/start/manual-installation/"
+---
+
+To get started with AWS Amplify we recommend that you use our [quickstart](/[platform]/start/quickstart) starter template. However, for some use cases, it may be preferable to start from scratch, either with a brand new directory or an existing frontend app. In that case we recommend to use [npm](https://npmjs.com) with [`create-amplify`](https://www.npmjs.com/package/create-amplify).
+
+```bash title="Terminal" showLineNumbers={false}
+npm create amplify@latest
+```
+
+```console title="Terminal" showLineNumbers={false}
+? Where should we create your project? (.) # press enter
+```
+
+Running this command will scaffold a lightweight Amplify project in your current project with the following files:
+
+```text
+βββ amplify/
+β βββ auth/
+β β βββ resource.ts
+β βββ data/
+β β βββ resource.ts
+β βββ backend.ts
+β βββ tsconfig.json
+β βββ package.json
+βββ node_modules/
+βββ .gitignore
+βββ package-lock.json
+βββ package.json
+βββ tsconfig.json
+```
+
+ If needed, you can manually install AWS Amplify without using `create-amplify` or the starter template. This guide will walk you through how to initialize your project, install dependencies, and author your first backend.
+
+## Manual setup
+
+First, if your frontend framework of choice doesn't have it already, create your project's `package.json` with `npm init -y`. Then, install the Amplify dependencies for building a backend:
+
+```bash title="Terminal" showLineNumbers={false}
+npm add --save-dev @aws-amplify/backend@latest @aws-amplify/backend-cli@latest typescript
+```
+
+> **Info:** **Note**: TypeScript is not a requirement but is recommended for an optimal experience.
+
+Next, create the entry point for your backend, `amplify/backend.ts`, with the following code:
+
+```ts
+import { defineBackend } from '@aws-amplify/backend';
+
+defineBackend({});
+```
+
+Now you can run `npx ampx sandbox` to create your first backend!
+
+> **Warning:** Amplify Gen 2 requires your backend to be configured for use with [ECMAScript modules (ESM)](https://nodejs.org/api/esm.html). If you encounter the following error during `ampx sandbox`, consider modifying your `package.json` with `"type": "module"`:
+>
+> ```text
+The current file is a CommonJS module whose imports will produce 'require' calls; however, the referenced file is an ECMAScript module and cannot be imported with 'require'. Consider writing a dynamic 'import("@aws-amplify/backend")' call instead.
+```
+>
+> Or, you can create a local file in the Amplify backend directory, `amplify/package.json`:
+>
+> ```json
+{
+ "type": "module"
+}
+```
+
+You can use `define*` functions to _define_ your resources. For example, you can define authentication:
+
+```ts title="amplify/auth/resource.ts"
+import { defineAuth } from '@aws-amplify/backend';
+
+export const auth = defineAuth({
+ loginWith: {
+ email: true
+ }
+});
+```
+
+Or define your data resource:
+
+```ts title="amplify/data/resource.ts"
+import { a, defineData, type ClientSchema } from '@aws-amplify/backend';
+
+const schema = a.schema({
+ Todo: a.model({
+ content: a.string(),
+ isDone: a.boolean()
+ })
+ .authorization(allow => [allow.publicApiKey()])
+});
+
+export type Schema = ClientSchema;
+export const data = defineData({
+ schema
+});
+```
+
+Each of these newly defined resources are then imported and set in the backend definition:
+
+```ts title="amplify/backend.ts"
+import { defineBackend } from '@aws-amplify/backend';
+import { auth } from './auth/resource';
+import { data } from './data/resource';
+
+defineBackend({
+ auth,
+ data
+});
+```
+
+## Upgrade existing projects
+
+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 @aws-amplify/backend-cli
+```
+
+## Next steps
+
+We recommend the following next steps:
+
+- [Learn more about defining authentication](/[platform]/build-a-backend/auth)
+- [Learn more about defining data](/[platform]/build-a-backend/data)
+- [Get started with cloud sandbox](/[platform]/deploy-and-host/sandbox-environments)
+- [Deploy and host your first app](/[platform]/deploy-and-host/fullstack-branching)
+
+---
+
+---
+title: "Connect to AWS resources"
+section: "start"
+platforms: ["android", "angular", "flutter", "javascript", "nextjs", "react", "react-native", "swift", "vue"]
+gen: 2
+last-updated: "2024-08-07T21:03:28.000Z"
+url: "https://docs.amplify.aws/react/start/connect-to-aws-resources/"
+---
+
+export async function getStaticPaths() {
+ return getCustomStaticPath(meta.platforms);
+}
+
+Amplify client libraries provide you with the flexibility to directly connect your application to AWS resources such as AWS AppSync, Amazon Cognito, Amazon S3, and more.
+
+To get started, client libraries must be _configured_. This is typically done by using the [`amplify_outputs.json` file](/[platform]/reference/amplify_outputs) generated by the Amplify backend tooling, however using the client libraries does not require backend resources to be created by Amplify.
+
+
+For JavaScript-based applications, the client library can be configured by using the generated outputs file:
+
+```ts title="src/main.ts"
+import { Amplify } from "aws-amplify"
+import outputs from "../amplify_outputs.json"
+
+Amplify.configure(outputs)
+```
+
+Or by configuring the library directly by passing a [`ResourcesConfig`](https://aws-amplify.github.io/amplify-js/api/interfaces/aws_amplify.index.ResourcesConfig.html) object. For example, to configure the client library for use with Amazon Cognito, specify the `Auth` configuration:
+
+```ts title="src/main.ts"
+import { Amplify } from "aws-amplify"
+
+Amplify.configure({
+ Auth: {
+ Cognito: {
+ userPoolId: "",
+ userPoolClientId: "",
+ identityPoolId: "",
+ loginWith: {
+ email: true,
+ },
+ signUpVerificationMethod: "code",
+ userAttributes: {
+ email: {
+ required: true,
+ },
+ },
+ allowGuestAccess: true,
+ passwordFormat: {
+ minLength: 8,
+ requireLowercase: true,
+ requireUppercase: true,
+ requireNumbers: true,
+ requireSpecialCharacters: true,
+ },
+ },
+ },
+})
+```
+
+By configuring the client library, Amplify automates the communication with the underlying AWS resources, and provides a friendly API to author your business logic. In the snippet below, the `signIn` function does not require passing information from your Cognito resource to initiate the sign-in flow.
+
+```ts title="src/main.ts"
+import { signIn } from "aws-amplify/auth"
+
+await signIn({
+ username: "john.doe@example.com",
+ password: "hunter2",
+})
+```
+
+
+For mobile platforms, the client library can be configured by creating an `amplify_outputs.json` file in your project's directory. To get started, create the file and specify your resource configuration:
+
+```json title="amplify_outputs.json"
+{
+ "$schema": "https://raw.githubusercontent.com/aws-amplify/amplify-backend/main/packages/client-config/src/client-config-schema/schema_v1.json",
+ "version": "1",
+ "auth": {
+ "user_pool_id": "",
+ "aws_region": "",
+ "user_pool_client_id": "",
+ "identity_pool_id": "",
+ "mfa_methods": [],
+ "standard_required_attributes": [
+ "email"
+ ],
+ "username_attributes": [
+ "email"
+ ],
+ "user_verification_types": [
+ "email"
+ ],
+ "mfa_configuration": "NONE",
+ "password_policy": {
+ "min_length": 8,
+ "require_lowercase": true,
+ "require_numbers": true,
+ "require_symbols": true,
+ "require_uppercase": true
+ },
+ "unauthenticated_identities_enabled": true
+ }
+}
+```
+
+
+For more information about how to use the Amplify client libraries with existing AWS resources, visit the guides:
+
+
+
+[Connect to Cognito](/[platform]/build-a-backend/auth/use-existing-cognito-resources/)
+
+Connect to Cognito resources using Amplify Auth's client library
+
+
+
+---
+
+---
+title: "Kotlin Coroutines support"
+section: "start"
+platforms: ["android"]
+gen: 2
+last-updated: "2024-05-06T19:20:38.000Z"
+url: "https://docs.amplify.aws/react/start/kotlin-coroutines/"
+---
+
+Amplify provides an optional and separate API surface which is entirely focused on using Kotlin's [coroutines](https://developer.android.com/kotlin/coroutines) and [flows](https://developer.android.com/kotlin/flow).
+
+To use it, import **`Amplify`** facade from `core-kotlin` instead of from `core`. See the Installation notes below for more details.
+
+With the Coroutines APIs, most Amplify functions are expressed as `suspend` functions. Suspending functions can be launched using one of the [lifecycle-aware coroutine scopes](https://developer.android.com/topic/libraries/architecture/coroutines#lifecyclescope) in the Android Architecture components:
+
+```kotlin
+import com.amplifyframework.kotlin.core.Amplify
+// ...
+
+val post = Post.builder()
+ .title("My First Post")
+ .build()
+
+lifecycleScope.launch {
+ try {
+ Amplify.DataStore.save(post) // This is suspending function!
+ Log.i("AmplifyKotlinDemo", "Saved a post")
+ } catch (failure: DataStoreException) {
+ Log.e("AmplifyKotlinDemo", "Save failed", failure)
+ }
+}
+```
+
+Coroutines can greatly improve the readability of dependent, asynchronous calls. Moreover, you can use scopes, dispatchers, and other Kotlin coroutine primitives to get more control over your execution context.
+
+Let's consider what happens when you have three dependent operations. You want to save a `Post`, then an `Editor`, and finally a `PostEditor`. With Amplify's coroutines interface, you can write these operations sequentially:
+
+```kotlin
+lifecycleScope.launch {
+ try {
+ listOf(post, editor, postEditor)
+ .forEach { Amplify.DataStore.save(it) }
+ Log.i("AmplifyKotlinDemo", "Post, Editor, and PostEditor saved")
+ } catch (failure: DataStoreException) {
+ Log.e("AmplifyKotlinDemo", "An item failed to save", failure)
+ }
+}
+```
+
+In Amplify's vanilla APIs, this would have created a large block of code with three nested callbacks.
+
+## Installation
+
+Amplify's coroutine support is included in an optional module, `core-kotlin`.
+
+1. Under **Gradle Scripts**, open **build.gradle.kts (Module :app)**, and add the following line in `dependencies`:
+
+ ```kotlin title="app/build.gradle.kts"
+ dependencies {
+ // Add the below line in `dependencies`
+ implementation("com.amplifyframework:core-kotlin:ANDROID_VERSION")
+ }
+ ```
+
+2. Wherever you use the **`Amplify`** facade, import `com.amplifyframework.kotlin.core.Amplify` instead of `com.amplifyframework.core.Amplify`:
+
+ ```kotlin
+ import com.amplifyframework.kotlin.core.Amplify
+ ```
+
+## Usage
+
+Amplify tries to map the behavior of your callback-based APIs to Kotlin primitives in an intuitive way. Functions whose callbacks emit a single value (or error) are now expressed as suspending functions, returning the value instead. Functions whose callbacks emit a stream of values will now return Kotlin `Flow`s, instead.
+
+## Special cases
+
+Some APIs return an operation which can be cancelled. Examples include realtime subscriptions to an API, and uploading/downloading objects from Storage.
+
+### API subscriptions
+
+The API category's `subscribe()` function uses both a suspend function _and_ a Flow. The function suspends until the API subscription is established. Then, it starts emitting values over the Flow.
+
+```kotlin
+lifecycleScope.async {
+ try {
+ Amplify.API.subscribe(request) // Suspends until subscription established
+ .catch { Log.e("AmplifyKotlinDemo", "Error on subscription", it) }
+ .collect { Log.i("AmplifyKotlinDemo", "Data on subscription = $it") }
+ } catch (error: ApiException) {
+ Log.e("AmplifyKotlinDemo", "Failed to establish subscription", error)
+ }
+}
+```
+
+### Storage upload & download operations
+
+The Storage category's `downloadFile()` and `uploadFile()` functions are bit more complex. These APIs allow you to observe transfer progress, and also to obtain a result. Progress results are delivered over a Flow, returned from the `progress()` function. Completion events are delivered by a suspending `result()` function.
+
+```kotlin
+// Download
+val download = Amplify.Storage.downloadFile(StoragePath.fromString("public/example.txt"), localFile)
+
+lifecycleScope.async {
+ download
+ .progress()
+ .collect { Log.i("AmplifyKotlinDemo", "Download progress = $it") }
+}
+
+lifecycleScope.async {
+ try {
+ val result = download.result()
+ Log.i("AmplifyKotlinDemo", "Download finished! ${result.file.path}")
+ } catch (failure: StorageException) {
+ Log.e("AmplifyKotlinDemo", "Download failed", failure)
+ }
+}
+
+// Upload
+val upload = Amplify.Storage.uploadFile(StoragePath.fromString("public/example.txt"), localFile)
+
+lifecycleScope.async {
+ upload
+ .progress()
+ .collect { Log.i("AmplifyKotlinDemo", "Upload progress = $it") }
+}
+lifecycleScope.async {
+ try {
+ val result = upload.result()
+ Log.i("AmplifyKotlinDemo", "Upload finished! ${result.path}")
+ } catch (failure: StorageException) {
+ Log.e("AmplifyKotlinDemo", "Upload failed", failure)
+ }
+}
+```
+
+---
+
+---
+title: "Gen 2 for Gen 1 customers"
+section: "start"
+platforms: ["android", "angular", "flutter", "javascript", "nextjs", "react", "react-native", "swift", "vue"]
+gen: 2
+last-updated: "2025-06-24T18:00:35.000Z"
+url: "https://docs.amplify.aws/react/start/migrate-to-gen2/"
+---
+
+## Migrating from Gen 1 to Gen 2
+
+We are actively developing migration tooling to aid in transitioning your project from Gen 1 to Gen 2. Until then, we recommend you continue working with your Gen 1 Amplify project. We remain committed to supporting both Gen 1 and Gen 2 for the foreseeable future. For new projects, we recommend adopting Gen 2 to take advantage of its [enhanced capabilities](/[platform]/how-amplify-works/concepts/). Meanwhile, customers on Gen 1 will continue to receive support for high-priority bugs and essential security updates.
+
+## Gen 1 vs. Gen 2 feature matrix
+
+The tables below present a feature matrix for Gen 1 customers who are considering Gen 2 for their apps. This will help determine the support availability for various features.
+
+### Auth
+
+| Feature | Gen 1 | Gen 2 |
+|---|---|---|
+| Configure username | Yes | [Yes with CDK](/[platform]/build-a-backend/auth/modify-resources-with-cdk/) |
+| Configure email | Yes | Yes |
+| Configure phone number | Yes | Yes |
+| Facebook | Yes | Yes |
+| Google | Yes | Yes |
+| Amazon | Yes | Yes |
+| Sign-in with Apple | Yes | Yes |
+| Add user pool groups | Yes | Yes |
+| User pool group preference | Yes | Yes |
+| Email verification link redirect | Yes | Yes |
+| Sign-up attributes | Yes | Yes |
+| Auth trigger support | Yes | Yes |
+| Auth trigger templates: Add Google reCaptcha Challenge | Yes | Yes |
+| Auth trigger templates: Add user to Group | Yes | Yes |
+| Auth trigger templates: Email Domain Filtering (denylist) | Yes | Yes |
+| Auth trigger templates: Email Domain Filtering (allowlist) | Yes | Yes |
+| Auth trigger templates: Override ID Token Claims | Yes | Yes |
+| Auth trigger templates: Custom Auth Challenge Flow| Yes | No |
+| Configure default password policy | Yes | [Yes with CDK](/[platform]/build-a-backend/auth/modify-resources-with-cdk/) |
+| Configure read/write capabilities for attributes | Yes | [Yes with CDK](/[platform]/build-a-backend/auth/modify-resources-with-cdk/) |
+| Oauth flow: Configure authorization v implicit grant | Yes | [Yes with CDK](/[platform]/build-a-backend/auth/modify-resources-with-cdk/) |
+| Admin queries | Yes | [Yes with CDK](/[platform]/build-a-backend/auth/modify-resources-with-cdk/) |
+| MFA login (on/off/optional) | Yes | Yes |
+| MFA: SMS | Yes | Yes |
+| MFA: TOTP | Yes | Yes |
+| Zero-config Authenticator support | Yes | Yes |
+| User management in console | Yes | Yes |
+| Configure Oauth scopes | Yes | Yes |
+| Email verification - code | Yes | Yes |
+| Email Verification - Link | Yes | Yes |
+| Oauth flow: Configure redirect URIs | Yes | Yes |
+| Ability to set a friendly name for User Pool | Yes | Yes |
+| Unauthenticated logins | Yes | Yes |
+| Custom attributes | Yes | [Yes with CDK](/[platform]/build-a-backend/auth/modify-resources-with-cdk/) |
+| Oauth flow: Configure domain name prefix | Yes | [Yes with CDK](/[platform]/build-a-backend/auth/modify-resources-with-cdk/) |
+| Auth configuration in console | Yes | No |
+| First class OIDC support | No | Yes |
+| First class SAML support | No | Yes |
+| Import auth | Yes | No |
+
+### Data
+
+| Feature | Gen 1 | Gen2 |
+|---|---|---|
+| model | Yes | Yes |
+| primaryKey | Yes | Yes |
+| secondaryKey (name, sortKeyFields, query) | Yes | Yes |
+| hasOne | Yes | Yes |
+| hasMany | Yes | Yes |
+| belongsTo | Yes | Yes |
+| manyToMany | Yes | No |
+| default | Yes | Yes |
+| **auth - model level** | | |
+| auth - public - apiKey | Yes | Yes |
+| auth - public - iam | Yes | Yes |
+| auth - owner - userPools | Yes | Yes |
+| auth - owner - ownerField - userPools | Yes | Yes |
+| auth - owner - ownerField as array - userPools | Yes | Yes |
+| auth - owner - oidc | Yes | Yes |
+| auth - owner - ownerField - oidc | Yes | Yes |
+| auth - owner - ownerField as array - oidc | Yes | Yes |
+| auth - private - userPools | Yes | Yes |
+| auth - private - oidc | Yes | Yes |
+| auth - private - iam | Yes | Yes |
+| auth - group - userPools | Yes | Yes |
+| auth - group - dynamic - userPools | Yes | Yes |
+| auth - group - oidc | Yes | Yes |
+| auth - group - dynamic - oidc | Yes | Yes |
+| auth - custom - function | Yes | Yes |
+| **auth - field level** | | |
+| auth - public - apiKey | Yes | Yes |
+| auth - public - iam | Yes | Yes |
+| auth - owner - userPools | Yes | Yes |
+| auth - owner - ownerField - userPools | Yes | Yes |
+| auth - owner - ownerField as array - userPools | Yes | Yes |
+| auth - owner - oidc | Yes | Yes |
+| auth - owner - ownerField - oidc | Yes | Yes |
+| auth - owner - ownerField as array - oidc | Yes | Yes |
+| auth - private - userPools | Yes | Yes |
+| auth - private - oidc | Yes | Yes |
+| auth - private - iam | Yes | Yes |
+| auth - group - userPools | Yes | Yes |
+| auth - group - dynamic - userPools | Yes | Yes |
+| auth - group - oidc | Yes | Yes |
+| auth - group - dynamic - oidc | Yes | Yes |
+| auth - custom - function | Yes | Yes |
+| **other directives** | | |
+| searchable | Yes | No but we offer a guide using Zero-ETL DynamoDB-to-OpenSearch |
+| predictions | Yes | No but we offer a guide with AI service integrations |
+| **Custom Mutations, Queries, Subscriptions** | Yes | Yes |
+| VTL handler | Yes | Yes with CDK |
+| JavaScript resolver handler | No | Yes |
+| function handler | Yes | Yes |
+| http handler | Yes | Yes - we support custom data sources including `http` |
+| **Other configurations** | | |
+| DataStore support | Yes | No but we'll offer a migration guide soon |
+| Visual configuration | Yes | No - Gen 2 is code-first by design |
+| @model queries, mutations, subscriptions, and timestamps modifiers | Yes | No |
+| Custom GraphQL Transformer plugins | Yes | No |
+| MySQL and PostgreSQL support | No | Yes |
+| In-IDE end-to-end type safety | No | Yes |
+| @hasOne, @hasMany, and @belongsTo on required fields | Yes | No |
+| fields argument on @hasOne, @hasMany, and @belongsTo | Yes | No |
+
+### Storage
+
+| Feature | Gen 1 | Gen 2 |
+|---|---|---|
+| Ability to provision S3 bucket | Yes | Yes |
+| Auth and Guest access | Yes | [Yes](/[platform]/build-a-backend/storage/authorization/#for-gen-1-public-protected-and-private-access-pattern) |
+| Auth - Configure CRUD access | Yes | Yes |
+| Configure Cognito Group CRUD access | Yes | Yes |
+| Guest - Configure CRUD access | Yes | Yes |
+| Lambda trigger for S3 bucket | Yes | Yes |
+| Import an S3 bucket | Yes | Yes |
+| File browser in console | Yes | Yes |
+| Ability to override/custom | Yes | Yes |
+| S3 Lambda triggers | Yes | Yes |
+| Locally test | Yes | Yes - with sandbox environments |
+| Visual configuration | Yes | No - Gen 2 is code-first by design |
+| File Browser in console | Yes | Yes |
+| Import S3 buckets | Yes | No |
+
+### Functions
+
+| Feature | Gen 1 | Gen 2 |
+|---|---|---|
+| Function runtime: TypeScript | No | Yes |
+| Function resource access permissions: auth | Yes | Yes |
+| Function resource access permissions: function | Yes | Yes |
+| Function resource access permissions: API | Yes | Yes |
+| Function resource access permissions CRUD operations | Yes | Yes |
+| Function resource access permissions: custom | No | Yes |
+| Environment variables | Yes | Yes |
+| Secrets | Yes | Yes |
+| Cron jobs | Yes | Yes |
+| Configure memory size | Yes | Yes |
+| Function build options for Node.js | Yes | Yes |
+| Function templates: AWS AppSync - GraphQL API request (with IAM) | Yes | Yes |
+| Function templates: CRUD function for DynamoDB (Integration with API Gateway) | Yes | Yes |
+| Function templates: GraphQL Lambda Authorizer | Yes | Yes |
+| Function templates: Hello World | Yes | Yes |
+| Function templates: Lambda trigger | Yes | Yes |
+| Function logs in console | Yes | Yes |
+| Function resource access permissions: geo | Yes | [Yes with CDK](/[platform]/build-a-backend/functions/grant-access-to-other-resources/#using-cdk) |
+| Function resource access permissions: analytics | Yes | [Yes with CDK](/[platform]/build-a-backend/functions/grant-access-to-other-resources/#using-cdk) |
+| Function runtime: .NET 6 | Yes | [Yes with CDK](/[platform]/build-a-backend/functions/custom-functions/) |
+| Function runtime: Go | Yes | [Yes with CDK](/[platform]/build-a-backend/functions/custom-functions/) |
+| Function runtime: Java | Yes | [Yes with CDK](/[platform]/build-a-backend/functions/custom-functions/) |
+| Function runtime: JavaScript | Yes | [Yes with CDK](/[platform]/build-a-backend/functions/custom-functions/) |
+| Function runtime: Python | Yes | [Yes with CDK](/[platform]/build-a-backend/functions/custom-functions/) |
+| Lambda layers | Yes | No |
+
+### Other categories
+
+
+[Amplify JS Auth API documentation](/[platform]/build-a-backend/auth/connect-your-frontend/)
+
+| Feature | Gen 1 | Gen 2 |
+|---|---|---|
+| REST API| Yes| No
+| Analytics| Yes| [Yes with custom CDK](/[platform]/build-a-backend/add-aws-services/analytics/)
+| Geo| Yes| [Yes with custom CDK](/[platform]/build-a-backend/add-aws-services/geo/)
+| Predictions | Yes| No
+| Interactions| Yes| No
+
+
+
+| Feature | Gen 1 | Gen 2 |
+|---|---|---|
+| REST API| Yes| Yes with custom CDK
+| Analytics| Yes| [Yes with custom CDK](/[platform]/build-a-backend/add-aws-services/analytics/)
+| Geo| No| No
+| Predictions | No| No
+| Interactions| No| No
+
+
+
+| Feature | Gen 1 | Gen 2 |
+|---|---|---|
+| REST API| Yes| [Yes with custom CDK](/[platform]/build-a-backend/add-aws-services/rest-api/)
+| Analytics| Yes| [Yes with custom CDK](/[platform]/build-a-backend/add-aws-services/analytics/)
+| Geo| Yes| [Yes with custom CDK](/[platform]/build-a-backend/add-aws-services/geo/)
+| Predictions | Yes| [Yes with custom CDK](/[platform]/build-a-backend/add-aws-services/predictions/)
+| Interactions| Yes| [Yes with custom CDK](/[platform]/build-a-backend/add-aws-services/interactions/)
+
+
+---
+
+---
+title: "Platform setup"
+section: "start"
+platforms: ["flutter"]
+gen: 2
+last-updated: "2025-12-29T21:54:06.000Z"
+url: "https://docs.amplify.aws/react/start/platform-setup/"
+---
+
+## iOS
+
+Amplify requires a minimum deployment target of 13.0 and Xcode 15.0 or higher when targeting iOS. Follow the steps below to update the minimum deployment target.
+
+Open `ios/Podfile` and update the target iOS platform to 13.0 or higher.
+
+> **Info:** If there is no file located at `ios/Podfile`, add `amplify_flutter` to your `pubspec.yaml` and run `pub get`. This will automatically create the file.
+
+```diff title="ios/Podfile"
+- # Uncomment this line to define a global platform for your project
+- # platform :ios, '12.0'
++ platform :ios, '13.0'
+```
+
+Open your project in Xcode and select Runner, Targets -> Runner and then the "General" tab. Under the "Minimum Deployments" section, update the iOS version to 13.0 or higher.
+
+
+
+Select Runner, Project -> Runner and then the "Build Settings" tab. Update "iOS Deployment Target" to 13.0 or higher.
+
+
+
+## Android
+
+Amplify Flutter supports API level 24+ (Android 7.0+), and requires Gradle 8+, Kotlin 1.9+, and Java 17+ when targeting Android. Follow the steps below to apply these changes in your app.
+
+> **Warning:** The steps below are intended for Flutter apps created with Flutter version 3.16+. If your app was created prior to version 3.16, please follow the guide [here](https://docs.flutter.dev/release/breaking-changes/flutter-gradle-plugin-apply) to migrate to Gradle's declarative plugins block before following the steps below.
+
+#### [Gradle Kotlin]
+1. Open `android/settings.gradle.kts` and update the Android Gradle plugin and kotlin versions:
+
+```diff title="android/settings.gradle.kts"
+plugins {
+ id("dev.flutter.flutter-plugin-loader") version "1.0.0"
+- id("com.android.application") version "8.7.0" apply false
+- id("org.jetbrains.kotlin.android") version "1.8.22" apply false
++ id("com.android.application") version "8.12.1" apply false
++ id("org.jetbrains.kotlin.android") version "2.2.0" apply false
+}
+```
+
+2. Open `android/gradle/wrapper/gradle-wrapper.properties` and update the Gradle `distributionUrl`.
+
+```diff title="android/gradle/wrapper/gradle-wrapper.properties"
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+-distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip
++distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-all.zip
+```
+
+3. Open `android/app/build.gradle.kts` and update the Java version and minimum Android SDK version.
+
+```diff title="android/app/build.gradle.kts"
+android {
+ namespace = "com.example.myapp"
+ compileSdk = flutter.compileSdkVersion
+ ndkVersion = flutter.ndkVersion
+ compileOptions {
+- sourceCompatibility = JavaVersion.VERSION_1_8
+- targetCompatibility = JavaVersion.VERSION_1_8
++ sourceCompatibility = JavaVersion.VERSION_17
++ targetCompatibility = JavaVersion.VERSION_17
+ }
+
+ kotlinOptions {
+- jvmTarget = JavaVersion.VERSION_11.toString()
++ jvmTarget = JavaVersion.VERSION_17.toString()
+ }
+
+ defaultConfig {
+ // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
+ applicationId = "com.example.myapp"
+ // You can update the following values to match your application needs.
+ // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
+- minSdk = flutter.minSdkVersion
++ minSdk = 24
+ targetSdk = flutter.targetSdkVersion
+ versionCode = flutterVersionCode.toInteger()
+ versionName = flutterVersionName
+ }
+
+ buildTypes {
+ release {
+ // TODO: Add your own signing config for the release build.
+ // Signing with the debug keys for now, so `flutter run --release` works.
+ signingConfig = signingConfigs.debug
+ }
+ }
+}
+```
+
+#### [Gradle Groovy]
+1. Open `android/settings.gradle` and update the Android Gradle plugin and kotlin versions:
+
+```diff title="android/settings.gradle"
+plugins {
+ id "dev.flutter.flutter-plugin-loader" version "1.0.0"
+- id "com.android.application" version "7.3.0" apply false
+- id "org.jetbrains.kotlin.android" version "1.7.10" apply false
++ id "com.android.application" version "8.12.1" apply false
++ id "org.jetbrains.kotlin.android" version "2.2.0" apply false
+}
+```
+
+2. Open `android/gradle/wrapper/gradle-wrapper.properties` and update the Gradle `distributionUrl`.
+
+```diff title="android/gradle/wrapper/gradle-wrapper.properties"
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+-distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-all.zip
++distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-all.zip
+```
+
+3. Open `android/app/build.gradle` and update the Java version and minimum Android SDK version.
+
+```diff title="android/app/build.gradle"
+android {
+ namespace = "com.example.myapp"
+ compileSdk = flutter.compileSdkVersion
+ ndkVersion = flutter.ndkVersion
+ compileOptions {
+- sourceCompatibility = JavaVersion.VERSION_11
+- targetCompatibility = JavaVersion.VERSION_11
++ sourceCompatibility = JavaVersion.VERSION_17
++ targetCompatibility = JavaVersion.VERSION_17
+ }
+
+ defaultConfig {
+ // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
+ applicationId = "com.example.myapp"
+ // You can update the following values to match your application needs.
+ // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
+- minSdk = flutter.minSdkVersion
++ minSdk = 24
+ targetSdk = flutter.targetSdkVersion
+ versionCode = flutterVersionCode.toInteger()
+ versionName = flutterVersionName
+ }
+
+ buildTypes {
+ release {
+ // TODO: Add your own signing config for the release build.
+ // Signing with the debug keys for now, so `flutter run --release` works.
+ signingConfig = signingConfigs.debug
+ }
+ }
+}
+```
+
+> **Info:** If you would like to use a higher version of Gradle or Android Gradle plugin see the compatibility matrix [here](https://developer.android.com/build/releases/gradle-plugin#updating-gradle).
+
+### Network Permissions for Release Builds
+
+Flutter apps have access to make network requests by default in debug mode. This permission needs to be added when building in release mode. To do this, open `android/app/src/main/AndroidManifest.xml` and make the following addition.
+
+```xml title="android/app/src/main/AndroidManifest.xml"
+
+// highlight-start
+
+// highlight-end
+...
+
+```
+
+## Web
+
+There are no Amplify specific requirements or setup instructions when targeting web. You will need to use a browser supported by Flutter. See the following Flutter docs for more info:
+
+- [Supported deployment platforms](https://docs.flutter.dev/reference/supported-platforms)
+- [FAQ: Which web browsers are supported by Flutter?](https://docs.flutter.dev/development/platform-integration/web/faq#which-web-browsers-are-supported-by-flutter)
+
+## macOS
+
+Amplify requires a minimum deployment target of 10.15 and Xcode 15.0 or higher when targeting macOS. Additionally, you will need to enable networking, keychain entitlements, and code signing.
+
+### Update Minimum Version
+
+Open `macos/Podfile` and update the target macOS platform to 10.15 or higher.
+
+> **Info:** If there is no file located at `macos/Podfile`, add `amplify_flutter` to your `pubspec.yaml` and run `pub get`. This will automatically create the file.
+
+```diff title="ios/Podfile"
+- platform :osx, '10.14'
++ platform :osx, '10.15'
+```
+
+Open your project in Xcode and select Runner, Targets -> Runner and then the "General" tab. Under the "Minimum Deployments" section, update the macOS version to 10.15 or higher.
+
+
+
+Select Runner, Project -> Runner and then the "Info" tab. Update "macOS Deployment Target" to 10.15 or higher.
+
+
+
+### Enable Network Calls
+
+Open your project in Xcode and select Runner, Targets -> Runner and then the "Signing and Capabilities" tab. Under "App Sandbox" select "Outgoing Connections (Client)".
+
+
+
+For more info on the Networking entitlement, see Apple's documentation on [com.apple.security.network.client](https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_security_network_client).
+
+### Enable Keychain Sharing
+
+> **Info:** This capability is required because Amplify uses the Data Protection Keychain on macOS as a platform best practice.
+> See [TN3137: macOS keychain APIs and implementations](https://developer.apple.com/documentation/technotes/tn3137-on-mac-keychains)
+> for more information on how Keychain works on macOS and the Keychain Sharing entitlement.
+
+Open your project in Xcode and select Runner, Targets -> Runner and then the "Signing and Capabilities" tab.
+
+1. Click the "+ icon".
+
+
+
+2. Search for "Keychain Sharing" in the subsequent modal, and add it.
+
+
+
+3. Scroll down to "Keychain Sharing" in the "Signing and Capabilities" and click the "+" icon. By default, your bundle ID will be used.
+
+
+
+4. Finally, add a development team and enable signing.
+
+
+
+## Windows
+
+There are no Amplify specific requirements or setup instructions when targeting Windows. You will need to use a Windows version supported by Flutter. See the following Flutter docs for more info:
+
+- [Supported deployment platforms](https://docs.flutter.dev/reference/supported-platforms)
+
+## Linux
+
+Amplify Flutter depends on the [libsecret](https://wiki.gnome.org/Projects/Libsecret) library when targeting Linux.
+
+### Local Development
+
+To run and debug an app that depends on Amplify Flutter, you must install `libsecret-1-dev`. Run the following commands to install `libsecret-1-dev`. this will also install dependencies of `libsecret-1-dev`, such as `libglib2.0-dev`.
+
+> **Info:** The command below is intended for Ubuntu. The command may vary on other Linux distributions.
+
+```terminal
+sudo apt-get update
+sudo apt-get install -y libsecret-1-dev
+```
+
+### Packaging Your App
+
+To include the required dependencies when packaging your app with Snapcraft, include them in your `snapcraft.yaml` file. For more info, see [Flutter's documentation on releasing to the Snap Store](https://docs.flutter.dev/deployment/linux).
+
+```yaml
+parts:
+ my-app:
+ plugin: flutter
+ source: .
+ flutter-target: lib/main.dart
+ build-packages:
+ - libsecret-1-dev
+ stage-packages:
+ - libsecret-1-0
+```
+
+---
+
+---
+title: "Build with AI assistants"
+section: "start"
+platforms: ["angular", "javascript", "nextjs", "react", "react-native", "vue"]
+gen: 2
+last-updated: "2025-12-11T15:26:24.000Z"
+url: "https://docs.amplify.aws/react/start/mcp-server/"
+---
+
+AWS MCP Server brings the power of AI coding assistants to your Amplify development workflow. Using the [Model Context Protocol (MCP)](https://modelcontextprotocol.io/)βan open protocol that enables AI tools to access external data and capabilitiesβyou can build, deploy, and manage fullstack Amplify applications faster than ever.
+
+Whether you're using Amazon Kiro, Cursor, Claude Desktop, or another MCP-compatible AI coding assistant, AWS MCP Server provides the context and tools your AI needs to help you build production-ready Amplify applications.
+
+## Why use AWS MCP Server?
+
+Building fullstack applications with Amplify involves many moving parts: authentication, data modeling, storage, serverless functions, and deployment. AWS MCP Server helps your AI coding assistant understand these components and guide you through implementing them correctly.
+
+Instead of copying and pasting from documentation or debugging configuration issues, you can describe what you want to build in natural language. Your AI assistant uses AWS MCP Server to access the right information and execute AWS operations on your behalf.
+
+## Core capabilities
+
+AWS MCP Server provides three core capabilities that enhance your AI-assisted development experience:
+
+### 1. Pre-built workflows
+
+Pre-built workflows (called "Agent SOPs" in AWS terminology) are step-by-step guides that help your AI assistant complete complex Amplify tasks following best practices. These workflows cover common scenarios like:
+
+- **Backend Implementation**: Setting up authentication, data models, storage, serverless functions, and AI features
+- **Frontend Integration**: Connecting your frontend framework to Amplify backend services
+- **Deployment Guide**: Configuring sandbox environments, production deployments, and CI/CD pipelines
+
+When you ask your AI assistant to help with one of these tasks, it follows the pre-built workflow to ensure you get a production-ready implementation.
+
+### 2. Documentation access
+
+AWS MCP Server gives your AI assistant direct access to the latest Amplify documentation. This means your assistant can provide accurate, up-to-date guidance without you needing to search through docs yourself.
+
+The documentation access includes:
+- API references and code examples
+- Configuration options and best practices
+- Troubleshooting guides and common patterns
+
+### 3. AWS API execution
+
+With proper authentication, AWS MCP Server can execute AWS operations directly from your AI assistant. This enables workflows like:
+
+- Creating and configuring Amplify backends
+- Deploying applications to AWS
+- Managing AWS resources
+
+All operations respect your IAM permissions, so your AI assistant can only perform actions you're authorized to do.
+
+## Getting started
+
+Ready to supercharge your Amplify development with AI? Follow these guides to get started:
+
+---
+
+---
+title: "Set up AWS MCP Server"
+section: "start/mcp-server"
+platforms: ["angular", "javascript", "nextjs", "react", "react-native", "vue"]
+gen: 2
+last-updated: "2025-12-11T15:26:24.000Z"
+url: "https://docs.amplify.aws/react/start/mcp-server/set-up-mcp/"
+---
+
+Follow the [AWS MCP Server setup guide](https://docs.aws.amazon.com/aws-mcp/latest/userguide/getting-started-aws-mcp-server.html) to configure AWS MCP Server with your AI coding assistant. The guide covers:
+
+- Installing prerequisites (AWS CLI, uv package manager)
+- Configuring your MCP client (Amazon Kiro, Cursor, Claude Desktop, and others)
+- Setting up AWS credentials and IAM permissions
+- Testing your connection
+
+## Amplify-specific setup tips
+
+Once you have AWS MCP Server configured, here are some tips for Amplify development:
+
+### AWS credentials for Amplify
+
+If you haven't set up AWS credentials for Amplify development yet, follow the [Configure AWS for local development](/[platform]/start/account-setup/) guide. This ensures you have the right permissions for both AWS MCP Server and Amplify CLI operations.
+
+### IAM permissions
+
+The base AWS MCP Server permissions allow your AI assistant to access the guided workflows and documentation. For Amplify development, your credentials also need permissions to create and manage Amplify resources.
+
+If you're using the `AmplifyBackendDeployFullAccess` managed policy for Amplify development, you likely have sufficient permissions. If you encounter permission errors, check with your AWS administrator.
+
+### Verify Amplify workflows are available
+
+After setup, verify that the Amplify workflows are accessible by asking your AI assistant:
+
+```
+Which guided workflows are available for Amplify development?
+```
+
+Your assistant should describe the Backend Implementation, Frontend Integration, and Deployment Guide workflows.
+
+## Next steps
+
+Now that you have AWS MCP Server configured, learn about the [guided workflows](/[platform]/start/mcp-server/amplify-workflows/) available to accelerate your Amplify development.
+
+---
+
+---
+title: "Guided workflows"
+section: "start/mcp-server"
+platforms: ["angular", "javascript", "nextjs", "react", "react-native", "vue"]
+gen: 2
+last-updated: "2025-12-11T15:26:24.000Z"
+url: "https://docs.amplify.aws/react/start/mcp-server/amplify-workflows/"
+---
+
+AWS MCP Server includes pre-built workflows (called "Agent SOPs" in AWS terminology) that guide your AI coding assistant through complex Amplify development tasks. These workflows encode best practices and ensure consistent, production-ready implementations.
+
+This page describes the three main workflows available and shows you how to use them effectively.
+
+## Available workflows
+
+AWS MCP Server provides three pre-built workflows designed for different stages of Amplify development. These workflows work with both new and existing projects.
+
+| Workflow | Purpose |
+| --- | --- |
+| **Backend Implementation** | Add or modify authentication, data models, storage, functions, and AI features in new or existing backends |
+| **Frontend Integration** | Add Amplify to an existing frontend app or enhance an app that already uses Amplify |
+| **Deployment Guide** | Configure sandbox environments, production deployments, and CI/CD for any Amplify project |
+
+## Backend Implementation workflow
+
+The Backend Implementation workflow helps you add or modify Amplify backend features following best practices. Whether you're starting fresh or adding features to an existing Amplify backend, this workflow guides you through the implementation.
+
+### Supported features
+
+Authentication (Auth)
+
+The workflow guides you through setting up Amplify Auth, including:
+
+- Configuring sign-up and sign-in flows
+- Setting up multi-factor authentication (MFA)
+- Configuring social sign-in providers (Google, Facebook, Apple, Amazon)
+- Customizing authentication UI components
+- Implementing password policies and account recovery
+
+**Example prompt:**
+```
+Guide me through setting up Amplify authentication with email sign-in and Google social login.
+```
+
+
+
+Data modeling (Data)
+
+The workflow helps you design and implement your data layer:
+
+- Creating GraphQL schemas with proper relationships
+- Setting up authorization rules for data access
+- Configuring real-time subscriptions
+- Implementing optimistic UI updates
+- Setting up conflict resolution for offline scenarios
+
+**Example prompt:**
+```
+Help me create a data model following Amplify best practices for a blog with posts,
+comments, and user profiles. Posts should only be editable by their authors.
+```
+
+
+
+File storage (Storage)
+
+The workflow guides storage implementation:
+
+- Configuring S3 buckets with proper access controls
+- Setting up file upload and download functionality
+- Implementing access levels (public, protected, private)
+- Configuring file validation and size limits
+
+**Example prompt:**
+```
+Walk me through adding file storage so users can upload profile pictures with a 5MB limit.
+```
+
+
+
+Serverless functions (Functions)
+
+The workflow helps you create and deploy Lambda functions:
+
+- Setting up function triggers (API, scheduled, event-driven)
+- Configuring environment variables and secrets
+- Implementing function layers for shared code
+- Setting up proper IAM permissions
+
+**Example prompt:**
+```
+Guide me through creating a Lambda function that sends a welcome email when a new user signs up.
+```
+
+
+
+AI features (AI)
+
+The workflow guides AI/ML feature integration:
+
+- Setting up Amazon Bedrock for generative AI
+- Implementing text generation and summarization
+- Adding image analysis capabilities
+- Configuring conversation flows
+
+**Example prompt:**
+```
+Help me add an AI summarization feature following Amplify best practices for generative AI.
+```
+
+
+
+## Frontend Integration workflow
+
+The Frontend Integration workflow helps you add Amplify to your frontend application or enhance an existing Amplify integration. Whether you have an existing React, Vue, Angular, or mobile app that needs Amplify, or you're adding new features to an app that already uses Amplify, this workflow provides framework-specific patterns and best practices.
+
+### Framework patterns
+
+The workflow adapts its guidance based on your frontend framework:
+
+React and Next.js
+
+- Setting up the Amplify client library
+- Using React hooks for authentication state
+- Implementing data fetching with proper loading states
+- Configuring server-side rendering (SSR) for Next.js
+- Using Amplify UI components
+
+**Example prompt:**
+```
+Help me connect my React app to Amplify following best practices. I need a sign-in page and protected routes.
+```
+
+
+
+Vue and Angular
+
+- Configuring Amplify with framework-specific patterns
+- Implementing authentication guards and state management
+- Setting up data binding with Amplify Data
+- Using framework-appropriate UI components
+
+**Example prompt:**
+```
+Guide me through setting up Amplify in my Vue app with a protected dashboard route.
+```
+
+
+
+React Native
+
+- Configuring Amplify for mobile development
+- Implementing secure storage for tokens
+- Setting up push notifications
+- Handling offline scenarios with DataStore
+
+**Example prompt:**
+```
+Walk me through adding offline support to my React Native app following Amplify best practices.
+```
+
+
+
+Flutter
+
+- Setting up Amplify Flutter packages
+- Implementing authentication flows
+- Configuring API and storage access
+- Using Amplify UI components for Flutter
+
+**Example prompt:**
+```
+Help me set up authentication in my Flutter app using the Amplify Authenticator widget.
+```
+
+
+
+Swift (iOS)
+
+- Configuring Amplify Swift packages
+- Implementing async/await patterns for Amplify operations
+- Setting up Combine publishers for real-time updates
+- Using SwiftUI with Amplify
+
+**Example prompt:**
+```
+Guide me through adding real-time data sync to my SwiftUI app following Amplify best practices.
+```
+
+
+
+Android (Kotlin)
+
+- Setting up Amplify Android libraries
+- Implementing coroutines for async operations
+- Configuring Jetpack Compose with Amplify
+- Handling Android lifecycle with Amplify
+
+**Example prompt:**
+```
+Walk me through connecting my Kotlin Android app to Amplify with user authentication.
+```
+
+
+
+## Deployment Guide workflow
+
+The Deployment Guide workflow helps you deploy your Amplify application through different stages, from local development to production. This works for new projects as well as existing applications that need deployment configuration or CI/CD setup.
+
+### Sandbox environments
+
+The workflow guides you through setting up personal cloud sandbox environments for development:
+
+- Creating isolated sandbox environments
+- Configuring hot-reload for backend changes
+- Managing sandbox lifecycle
+- Sharing sandbox configurations with team members
+
+**Example prompt:**
+```
+Guide me through setting up an Amplify sandbox environment for testing backend changes.
+```
+
+### Production deployment
+
+The workflow helps you deploy to production:
+
+- Configuring production-ready settings
+- Setting up custom domains
+- Implementing environment variables for different stages
+- Configuring monitoring and logging
+
+**Example prompt:**
+```
+Walk me through deploying my Amplify app to production with a custom domain.
+```
+
+### CI/CD integration
+
+The workflow guides continuous integration and deployment setup:
+
+- Configuring Amplify Hosting for automatic deployments
+- Setting up branch-based deployments (preview, staging, production)
+- Implementing pull request previews
+- Configuring build settings and environment variables
+
+**Example prompt:**
+```
+Help me set up CI/CD following Amplify best practices so my app deploys automatically when I push to main.
+```
+
+## Practical example: Building a fullstack app
+
+Here's an example of how you might use AWS MCP Server to build a complete Amplify application. This demonstrates how the pre-built workflows guide your AI assistant through each step.
+
+### Step 1: Set up the backend
+
+Start by describing your application to your AI assistant:
+
+```
+Help me build a task management app following Amplify best practices. Users should be able to:
+- Sign up and sign in with email
+- Create, edit, and delete their own tasks
+- Mark tasks as complete
+- See their tasks in real-time across devices
+```
+
+Your AI assistant uses the **Backend Implementation workflow** to:
+1. Configure authentication with email sign-in
+2. Create a Task data model with proper authorization rules
+3. Set up real-time subscriptions for task updates
+
+### Step 2: Connect the frontend
+
+Next, ask your assistant to connect your frontend:
+
+```
+Guide me through connecting my React app to the Amplify backend. I need a sign-in page
+and a dashboard that shows the user's tasks with real-time updates.
+```
+
+Your AI assistant uses the **Frontend Integration workflow** to:
+1. Install and configure Amplify libraries
+2. Set up the Authenticator component
+3. Create data fetching hooks for tasks
+4. Implement real-time updates in the UI
+
+### Step 3: Deploy the application
+
+Finally, deploy your application:
+
+```
+Walk me through setting up Amplify deployment so the app deploys automatically when I push
+to GitHub. I also want preview deployments for pull requests.
+```
+
+Your AI assistant uses the **Deployment Guide workflow** to:
+1. Connect your GitHub repository to Amplify Hosting
+2. Configure branch-based deployments
+3. Set up pull request previews
+4. Configure production environment settings
+
+## Tips for effective prompts
+
+To get the best results from AWS MCP Server, keep these tips in mind:
+
+> **Info:** **Be specific about your requirements.** Instead of "add authentication," try "add authentication with email sign-in, Google social login, and MFA."
+
+- **Describe the user experience** you want, not just the technical implementation
+- **Mention your framework** so the workflow can provide framework-specific guidance
+- **Ask follow-up questions** if you need clarification on any step
+- **Request explanations** if you want to understand why certain patterns are recommended
+
+### Optional: Steering files for teams
+
+For guaranteed consistency across all developers, you can add steering files that instruct the AI to always use the workflows.
+
+Amazon Kiro (IDE/CLI)
+
+Create a steering file at `.kiro/steering/amplify.md`:
+
+```markdown title=".kiro/steering/amplify.md"
+# Amplify Development Guidelines
+
+When working on Amplify projects, use the AWS MCP Server guided workflows:
+
+- For backend features (auth, data, storage, functions, AI), call `retrieve_agent_sop` with `amplify-backend-implementation`
+- For frontend integration, call `retrieve_agent_sop` with `amplify-frontend-integration`
+- For deployment tasks, call `retrieve_agent_sop` with `amplify-deployment-guide`
+```
+
+
+
+Claude (Code/Desktop)
+
+Add to your `CLAUDE.md` file in the project root:
+
+```markdown title="CLAUDE.md"
+# Amplify Development Guidelines
+
+When working on Amplify projects, use the AWS MCP Server guided workflows:
+
+- For backend features (auth, data, storage, functions, AI), call `retrieve_agent_sop` with `amplify-backend-implementation`
+- For frontend integration, call `retrieve_agent_sop` with `amplify-frontend-integration`
+- For deployment tasks, call `retrieve_agent_sop` with `amplify-deployment-guide`
+```
+
+
+
+Cursor
+
+Create a rules file at `.cursor/rules/amplify.mdc`:
+
+```markdown title=".cursor/rules/amplify.mdc"
+---
+description: Amplify development guidelines
+globs:
+ - "amplify/**"
+ - "src/**"
+---
+
+# Amplify Development Guidelines
+
+When working on Amplify projects, use the AWS MCP Server guided workflows:
+
+- For backend features (auth, data, storage, functions, AI), call `retrieve_agent_sop` with `amplify-backend-implementation`
+- For frontend integration, call `retrieve_agent_sop` with `amplify-frontend-integration`
+- For deployment tasks, call `retrieve_agent_sop` with `amplify-deployment-guide`
+```
+
+
+
+## Next steps
+
+Now that you understand the pre-built workflows, try using them in your next Amplify project:
+
+1. [Set up AWS MCP Server](/[platform]/start/mcp-server/set-up-mcp/) if you haven't already
+2. Start a conversation with your AI assistant about what you want to build
+3. Let the pre-built workflows guide you through implementation
+
+For more information about specific Amplify features, explore the documentation:
+
+- [Authentication](/[platform]/build-a-backend/auth/)
+- [Data](/[platform]/build-a-backend/data/)
+- [Storage](/[platform]/build-a-backend/storage/)
+- [Functions](/[platform]/build-a-backend/functions/)
+
+---
+
+---
+title: "Build & connect backend"
+section: "build-a-backend"
+platforms: ["android", "angular", "flutter", "javascript", "nextjs", "react", "react-native", "swift", "vue"]
+gen: 2
+last-updated: "2024-02-21T20:06:17.000Z"
+url: "https://docs.amplify.aws/react/build-a-backend/"
+---
+
+
+
+---
+
+---
+title: "Authentication"
+section: "build-a-backend"
+platforms: ["android", "angular", "flutter", "javascript", "nextjs", "react", "react-native", "swift", "vue"]
+gen: 2
+last-updated: "2024-05-02T22:35:36.000Z"
+url: "https://docs.amplify.aws/react/build-a-backend/auth/"
+---
+
+export async function getStaticPaths() {
+ return getCustomStaticPath(meta.platforms);
+}
+
+---
+
+---
+title: "Set up Amplify Auth"
+section: "build-a-backend/auth"
+platforms: ["android", "angular", "flutter", "javascript", "nextjs", "react", "react-native", "swift", "vue"]
+gen: 2
+last-updated: "2025-12-03T11:13:25.000Z"
+url: "https://docs.amplify.aws/react/build-a-backend/auth/set-up-auth/"
+---
+
+Amplify Auth is powered by [Amazon Cognito](https://aws.amazon.com/cognito/). Cognito is a robust user directory service that handles user registration, authentication, account recovery, and other operations. [Review the concepts to learn more](/[platform]/build-a-backend/auth/concepts/).
+
+To get started with defining your authentication resource, open or create the auth resource file:
+
+```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,
+ },
+})
+```
+
+By default, your auth resource is scaffolded using `email` as the default login mechanism. You can also configure your auth resource to allow signing in with:
+
+- Phone numbers
+- External providers (Google, Facebook, Amazon, or Sign in with Apple)
+
+- [Passwordless authentication](/[platform]/build-a-backend/auth/concepts/passwordless/) (Email OTP, SMS OTP, or WebAuthn passkeys)
+
+
+> **Info:** **Note:** At a minimum you will need to pass a `loginWith` value to set up how your users sign in to your app. Signing in with email and password is configured by default if you do not provide any value.
+
+
+## Enable passwordless authentication
+
+You can enable passwordless authentication methods to provide a more secure and user-friendly experience:
+
+```ts title="amplify/auth/resource.ts"
+import { defineAuth } from '@aws-amplify/backend';
+
+export const auth = defineAuth({
+ loginWith: {
+ email: {
+ otpLogin: true // Enable email-based one-time passwords
+ }
+ }
+});
+```
+
+[Learn more about passwordless authentication options](/[platform]/build-a-backend/auth/concepts/passwordless/).
+
+
+## Deploy auth resource
+
+After you have chosen and defined your authentication resource, run the following command to create your resource in your personal cloud sandbox.
+
+
+```bash title="Terminal" showLineNumbers={false}
+npx ampx sandbox
+```
+
+
+```bash title="Terminal" showLineNumbers={false}
+npx ampx sandbox --outputs-format dart --outputs-out-dir lib
+```
+
+
+> **Warning:** Be sure to add a "raw" folder under `app/src/main/res` directory if it does not exist.
+
+```bash title="Terminal" showLineNumbers={false}
+npx ampx sandbox --outputs-out-dir
+```
+
+
+```bash title="Terminal" showLineNumbers={false}
+npx ampx sandbox
+```
+
+
+After a successful deployment, this command also generates an outputs file (`amplify_outputs.json`) to enable your frontend app to connect to your backend resources. The values you configure in your backend authentication resource are set in the generated outputs file to automatically configure the frontend [`Authenticator connected component`](https://ui.docs.amplify.aws/react/connected-components/authenticator).
+
+## Connect your application code to your auth resource
+
+Creating and correctly implementing the sign-in flow can be challenging and time-consuming. Amplify's Authenticator UI component streamlines this by enabling you to rapidly build the entire authentication flow for your app. The component works seamlessly with configuration in `amplify/auth/resource.ts` to automatically connect with your backend resources.
+
+Amplify has pre-built UI components for React, Vue, Angular, React Native, Swift, Android, and Flutter. In this guide, we are focusing on those for web applications.
+
+
+First, install the `@aws-amplify/ui-react` library:
+
+```bash title="Terminal" showLineNumbers={false}
+npm add @aws-amplify/ui-react
+```
+
+Next, open **pages/\_app.tsx** and add the `Authenticator` component.
+
+```ts title="pages/_app.tsx"
+import type { AppProps } from 'next/app';
+import { Authenticator } from '@aws-amplify/ui-react';
+import { Amplify } from 'aws-amplify';
+import outputs from '@/amplify_outputs.json';
+import '@aws-amplify/ui-react/styles.css';
+
+Amplify.configure(outputs);
+
+export default function App({ Component, pageProps }: AppProps) {
+ return (
+
+ {({ signOut, user }) => (
+
+
Hello {user?.username}
+ Sign out
+
+
+ )}
+
+ );
+};
+```
+
+
+
+#### [Vue 3]
+
+First, install the `@aws-amplify/ui-vue` library:
+
+```bash title="Terminal" showLineNumbers={false}
+npm add @aws-amplify/ui-vue
+```
+
+Next, open **src/App.vue** and add the `Authenticator` component.
+
+**Authenticator**
+
+The `Authenticator` component offers a simple way to add authentication flows into your app. This component encapsulates an authentication workflow in the framework of your choice and is backed by your backend Auth resources. `Authenticator` passes the `user` info and `signOut` function to the inner template.
+
+```html
+
+
+
+
+
+
Hello {{ user.username }}!
+ Sign Out
+
+
+
+```
+
+#### [Vue 2]
+
+First, install the `@aws-amplify/ui-components` library:
+
+```bash title="Terminal" showLineNumbers={false}
+npm add @aws-amplify/ui-components
+```
+
+Now open **src/main.ts** and add the following below your last import:
+
+```js title="src/main.ts"
+import '@aws-amplify/ui-components';
+import {
+ applyPolyfills,
+ defineCustomElements
+} from '@aws-amplify/ui-components/loader';
+import Vue from 'vue';
+
+Vue.config.ignoredElements = [/amplify-\w*/];
+
+applyPolyfills().then(() => {
+ defineCustomElements(window);
+});
+```
+
+Next, open **src/App.ts** and add the `amplify-authenticator` component.
+
+**amplify-authenticator**
+
+The `amplify-authenticator` component offers a simple way to add authentication flows into your app. This component encapsulates an authentication workflow in the framework of your choice and is backed by your backend Auth resources. The optional `amplify-sign-out` component is available if you would like to render a sign-out button.
+
+```html title="src/App.ts"
+
+
+
+ My App
+
+
+
+
+```
+
+
+
+First, install the `@aws-amplify/ui-angular` library:
+
+```bash title="Terminal" showLineNumbers={false}
+npm add @aws-amplify/ui-angular
+```
+
+Now open **app.module.ts** and add the Amplify imports and configuration:
+
+```js title="app.module.ts"
+import { NgModule } from '@angular/core';
+import { BrowserModule } from '@angular/platform-browser';
+import { AmplifyAuthenticatorModule } from '@aws-amplify/ui-angular';
+
+import { AppComponent } from './app.component';
+import outputs from './amplify_outputs.json';
+
+Amplify.configure(outputs);
+
+@NgModule({
+ declarations: [AppComponent],
+ imports: [BrowserModule, AmplifyAuthenticatorModule],
+ providers: [],
+ bootstrap: [AppComponent]
+})
+export class AppModule {}
+```
+
+Next, import the default theme inside **styles.css**:
+
+```css title="styles.css"
+@import '~@aws-amplify/ui-angular/theme.css';
+```
+
+Next, open **app.component.html** and add the `amplify-authenticator` component.
+
+**amplify-authenticator**
+
+The `Authenticator` component offers a simple way to add authentication flows into your app. This component encapsulates an authentication workflow in the framework of your choice and is backed by your backend Auth resources. `Authenticator` passes the `user` info and `signOut` function to the inner template.
+
+The `amplify-authenticator` component offers a simple way to add authentication flows into your app. This component encapsulates an authentication workflow in the framework of your choice and is backed by your backend Auth resources. `amplify-authenticator` passes the `user` info and `signOut` function to the inner template.
+
+```html title="app.component.html"
+
+
+
Welcome {{ user.username }}!
+ Sign Out
+
+
+```
+
+
+First, install the `@aws-amplify/ui-react-native` library:
+
+```bash title="Terminal" showLineNumbers={false}
+npm add \
+ @aws-amplify/react-native \
+ @aws-amplify/ui-react-native \
+ aws-amplify \
+ @react-native-community/netinfo \
+ @react-native-async-storage/async-storage \
+ react-native-safe-area-context@^4.2.5 \
+ react-native-get-random-values
+```
+
+> **Info:** If your project will support Federated Sign In using the `React Native Authenticator` the `@aws-amplify/rtn-web-browser` package is also required:
+>
+> ```bash title="Terminal" showLineNumbers={false}
+npm add @aws-amplify/rtn-web-browser
+```
+
+Then install the iOS cocoapods by running:
+
+```bash title="Terminal" showLineNumbers={false}
+npx pod-install
+```
+
+> **Warning:** For calling native libraries and platform dependencies from Expo, you need to run the prebuild command for generating the folders for related platforms.
+>
+> ```bash title="Terminal" showLineNumbers={false}
+npx expo prebuild
+```
+Next, update the `App.tsx` file with the following to set up the authentication flow:
+
+```typescript
+import React from "react";
+import { Button, View, StyleSheet } from "react-native";
+import { Amplify } from "aws-amplify";
+import { Authenticator, useAuthenticator } from "@aws-amplify/ui-react-native";
+import outputs from "./amplify_outputs.json";
+
+Amplify.configure(outputs);
+
+const SignOutButton = () => {
+ const { signOut } = useAuthenticator();
+
+ return (
+
+
+
+ );
+};
+
+const App = () => {
+ return (
+
+
+
+
+
+ );
+};
+
+const styles = StyleSheet.create({
+ signOutButton: {
+ alignSelf: "flex-end",
+ },
+});
+
+export default App;
+```
+
+
+First, install the `amplify_authenticator` library:
+
+```bash title="Terminal" showLineNumbers={false}
+flutter pub add amplify_flutter
+flutter pub add amplify_auth_cognito
+flutter pub add amplify_authenticator
+```
+
+or you can update your `pubspec.yaml` file with the following
+
+```yaml
+dependencies:
+ amplify_flutter: ^2.0.0
+ amplify_auth_cognito: ^2.0.0
+ amplify_authenticator: ^2.0.0
+```
+
+and run the following command to download the libraries.
+
+```bash title="Terminal" showLineNumbers={false}
+flutter pub get
+```
+
+Next, update your `main.dart` file with the following:
+
+```dart
+import 'package:amplify_auth_cognito/amplify_auth_cognito.dart';
+import 'package:amplify_authenticator/amplify_authenticator.dart';
+import 'package:amplify_flutter/amplify_flutter.dart';
+import 'package:flutter/material.dart';
+
+import 'amplify_outputs.dart';
+
+Future main() async {
+ try {
+ WidgetsFlutterBinding.ensureInitialized();
+ await _configureAmplify();
+ runApp(const MyApp());
+ } on AmplifyException catch (e) {
+ runApp(Text("Error configuring Amplify: ${e.message}"));
+ }
+}
+
+// highlight-start
+Future _configureAmplify() async {
+ try {
+ await Amplify.addPlugin(AmplifyAuthCognito());
+ await Amplify.configure(amplifyConfig);
+ safePrint('Successfully configured');
+ } on Exception catch (e) {
+ safePrint('Error configuring Amplify: $e');
+ }
+}
+// highlight-end
+
+class MyApp extends StatelessWidget {
+ const MyApp({super.key});
+ @override
+ Widget build(BuildContext context) {
+ // highlight-next-line
+ return Authenticator(
+ child: MaterialApp(
+ // highlight-next-line
+ builder: Authenticator.builder(),
+ home: const Scaffold(
+ body: Center(
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ // highlight-next-line
+ SignOutButton(),
+ ],
+ ),
+ ),
+ ),
+ ),
+ );
+ }
+}
+```
+
+
+> **Warning:** Be sure to have compileSdk version as 34 or higher.
+
+The Authenticator component is built using [Jetpack Compose](https://developer.android.com/jetpack/compose). Enable Jetpack Compose by adding the following to the android section of your app's `build.gradle` file:
+
+```kotlin title="app/build.gradle.kts" showLineNumbers={false}
+compileOptions {
+ // Support for modern Java features
+ isCoreLibraryDesugaringEnabled = true
+}
+buildFeatures {
+ compose = true
+}
+composeOptions {
+ kotlinCompilerExtensionVersion = "1.2.0"
+}
+dependencies {
+ coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:ANDROID_DESUGAR_VERSION")
+}
+```
+
+Add the following dependencies to your *app*'s `build.gradle.kts` file and click "Sync Now" when prompted:
+
+```kotlin title="app/build.gradle.kts"
+dependencies {
+ implementation("com.amplifyframework.ui:authenticator:ANDROID_AUTHENTICATOR_VERSION")
+}
+```
+
+> **Warning:** Before calling the `Amplify.configure` function, make sure to either download the `amplify_outputs.json` file from the console, or generate it with the following command:
+>
+> ```bash title="Terminal" showLineNumbers={false}
+npx ampx generate outputs --app-id --branch main --out-dir app/src/main/res/raw
+```
+>
+> Next, be sure the file you generated or downloaded is in the appropriate resource directory for your application (for example, `app/src/main/res/raw`) in your Android project. Otherwise, you will not be able to compile your application.
+
+```kotlin title="MyAmplifyApp.kt"
+import android.app.Application
+import android.util.Log
+import com.amplifyframework.AmplifyException
+import com.amplifyframework.auth.cognito.AWSCognitoAuthPlugin
+import com.amplifyframework.core.Amplify
+import com.amplifyframework.core.configuration.AmplifyOutputs
+
+class MyAmplifyApp: Application() {
+ override fun onCreate() {
+ super.onCreate()
+
+ try {
+ // highlight-next-line
+ Amplify.addPlugin(AWSCognitoAuthPlugin())
+ Amplify.configure(AmplifyOutputs(R.raw.amplify_outputs), applicationContext)
+ Log.i("MyAmplifyApp", "Initialized Amplify")
+ } catch (error: AmplifyException) {
+ Log.e("MyAmplifyApp", "Could not initialize Amplify", error)
+ }
+ }
+}
+```
+
+Lastly, update your MainActivity.kt file to use the Amplify UI components:
+
+```kotlin
+import android.os.Bundle
+import androidx.activity.ComponentActivity
+import androidx.activity.compose.setContent
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.material3.Button
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Surface
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.tooling.preview.Preview
+import com.amplifyframework.core.Amplify
+import com.amplifyframework.ui.authenticator.ui.Authenticator
+// highlight-next-line
+import .ui.theme.MyAmplifyAppTheme
+
+class MainActivity : ComponentActivity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContent {
+ MyAmplifyAppTheme {
+ // A surface container using the 'background' color from the theme
+ Surface(
+ modifier = Modifier.fillMaxSize(),
+ color = MaterialTheme.colorScheme.background
+ ) {
+ // highlight-next-line
+ Authenticator { state ->
+ Column {
+ Text(
+ text = "Hello ${state.user.username}!",
+ )
+ Button(onClick = {
+ // highlight-next-line
+ Amplify.Auth.signOut { }
+ }) {
+ Text(text = "Sign Out")
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+```
+
+
+### Prerequisites
+
+An application with Amplify libraries integrated and a minimum target of any of the following:
+
+- **iOS 13.0**, using **Xcode 14.1** or later.
+- **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** or later. (Preview support - see below for more details.)
+
+
+
+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.
+
+
+
+
+**Note:** To use Amplify Auth in a macOS project, you'll need to enable the Keychain Sharing capability. In Xcode, navigate to **your application target** > **Signing & Capabilities** > **+ Capability**, then select **Keychain Sharing.**
+
+This capability is required because Auth uses the Data Protection Keychain on macOS as a platform best practice. See [TN3137: macOS keychain APIs and implementations](https://developer.apple.com/documentation/technotes/tn3137-on-mac-keychains) for more information on how Keychain works on macOS and the Keychain Sharing entitlement.
+
+For more information on adding capabilities to your application, see [Xcode Capabilities](https://developer.apple.com/documentation/xcode/capabilities).
+
+
+
+Move the generated files to your project. You can do this by dragging and dropping the files to your project.
+
+
+
+Open your project in Xcode and select File > Add Packages... and add the following dependencies:
+
+- Amplify Library for Swift: Enter its GitHub URL (https://github.com/aws-amplify/amplify-swift), *select Up to Next Major Version* and click *Add Package*
+
+ - Select the following libraries:
+ - Amplify
+ - AWSCognitoAuthPlugin
+
+- Amplify UI Swift - Authenticator: Enter its GitHub URL (https://github.com/aws-amplify/amplify-ui-swift-authenticator), *select Up to Next Major Version* and click *Add Package*
+
+ - Select the following library:
+ - Authenticator
+
+Next, update the `init` part of your `MyAmplifyAppApp.swift` file with the following code:
+
+```swift title="MyAmplifyApp.swift"
+import Amplify
+import Authenticator
+import AWSCognitoAuthPlugin
+import SwiftUI
+
+@main
+struct MyApp: App {
+ init() {
+ do {
+ try Amplify.add(plugin: AWSCognitoAuthPlugin())
+ try Amplify.configure(with: .amplifyOutputs)
+ } catch {
+ print("Unable to configure Amplify \(error)")
+ }
+ }
+
+ var body: some Scene {
+ WindowGroup {
+ Authenticator { state in
+ VStack {
+ Text("Hello, \(state.user.username)")
+ Button("Sign out") {
+ Task {
+ await state.signOut()
+ }
+ }
+ }
+ }
+ }
+ }
+}
+```
+
+
+Once you add the Authenticator component to your app, you can test the sign-up, sign-in, and sign-out functionality. You can also [customize the Authenticator connected component](https://ui.docs.amplify.aws/react/connected-components/authenticator/customization) to adjust colors and styling as needed.
+
+## Next steps
+
+Now that you have completed setting up authentication in your Amplify app with email and password, you may also want to add some additional features. We recommend you learn more about:
+
+- [Learn more about authentication concepts](/[platform]/build-a-backend/auth/concepts/)
+- [Moving to production](/[platform]/build-a-backend/auth/moving-to-production/)
+
+---
+
+---
+title: "Concepts"
+section: "build-a-backend/auth"
+platforms: ["android", "angular", "flutter", "javascript", "nextjs", "react", "react-native", "swift", "vue"]
+gen: 2
+last-updated: "2024-09-19T16:52:04.000Z"
+url: "https://docs.amplify.aws/react/build-a-backend/auth/concepts/"
+---
+
+Amplify helps you secure your application while providing an easy sign-in experience for your users. This experience is influenced by your security strategy. This security strategy includes the authentication method, security credentials, and enabling additional verification when needed.
+
+- _Authentication_ is a process to validate **who you are** (abbreviated as _AuthN_). The system that does this validation is referred to as an Identity Provider or IdP. This can be your own self-hosted IdP or a cloud service. Oftentimes, this IdP is an external provider such as Apple, Facebook, Google, or Amazon.
+- _Authorization_ is the process of validating **what you can access** (abbreviated as _AuthZ_). This is sometimes done by looking at tokens with custom logic, predefined rules, or signed requests with policies.
+
+Common authentication methods and associated risks include:
+
+- External provider federation which enables easier access for your users but shares data with third parties.
+
+You can improve security credentials and verification for these authentication methods by:
+
+- Modifying the default password policy to ensure your users create stronger passwords.
+- Requiring additional contact information from users before they can reset passwords.
+- Enabling multi-factor authentication (MFA) which adds a layer of security at sign-in but may also add friction for your users.
+
+## What is Amazon Cognito?
+
+Amplify Auth is powered by [Amazon Cognito](https://aws.amazon.com/cognito/). Amazon Cognito is an identity and access management service, enabling you to secure your web or mobile applications, and is comprised of two services:
+
+1. [Amazon Cognito User Pools](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-identity-pools.html) is a full-featured user directory service to handle user registration, authentication, and account recovery
+2. [Amazon Cognito Federated Identities or Identity Pools](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-identity.html) is a service used to authorize your users to interact with other AWS services
+
+Amplify interfaces with User Pools to store your user information, including federation with other OpenID providers like Apple, Facebook, Google, or Amazon, and leverages federated identities to manage user access to AWS resources.
+
+Authorization is often done in one of two ways:
+
+1. Clients pass the tokens to the backend that perform custom logic to allow or deny actions
+2. Clients sign the requests and the backend validates the signature, allowing or denying actions depending on predefined policy. The predefined rules, known as [IAM access policies](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html), are automatically configured by Amplify.
+
+The first is a common authorization method for HTTP or GraphQL APIs, while the second is necessary for interfacing with AWS services such as Amazon S3, Amazon Pinpoint, and others.
+
+### Before you build
+
+Amazon Cognito can be customized based on your security strategy for authentication. However, some initial configuration options cannot be changed after the backend resources are configured:
+
+- User attributes that are used to identify your individual users (such as email and phone) cannot be renamed or deleted.
+- Sign-in methods (including username, email, and phone) cannot be added or changed after the initial configuration. This includes both defining which attributes are used to sign in and which attributes are required. Required attributes must have a value for all users once set.
+- Verification methods (including username and email) are the same as required attributes and cannot be removed once configured.
+- The `sub` attribute is a unique identifier within each user pool that cannot be modified and can be used to index and search users.
+- If MFA is set to **required** with phone number for all users, you will need to include MFA setup (i.e. mandating phone number) when users sign up.
+
+Visit the [Amazon Cognito documentation](https://docs.aws.amazon.com/cognito/latest/developerguide/what-is-amazon-cognito.html) for more details on these settings, including [User pool attributes](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-settings-attributes.html) and [Adding MFA to a user pool](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-settings-mfa.html).
+
+---
+
+---
+title: "Usernames"
+section: "build-a-backend/auth/concepts"
+platforms: ["angular", "javascript", "nextjs", "react", "vue"]
+gen: 2
+last-updated: "2024-05-01T21:54:24.000Z"
+url: "https://docs.amplify.aws/react/build-a-backend/auth/concepts/usernames/"
+---
+
+Amplify Auth does not support signing in with only username and password, however can be configured to enable usernames for display purposes. Amazon Cognito offers two ways of provisioning login mechanisms:
+
+1. **Username attributes**
+2. **Alias attributes**
+
+Each are described in more detail on the [AWS documentation for Cognito user pool settings](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-settings-attributes.html#user-pool-settings-aliases), however at a high-level can be described as follows:
+
+- **Username attributes** allow you to customize which attribute can be used as the "username", or allowing users to sign in with an email or phone in place of a username
+- **Alias attributes** allow you to specify with attribute(s) can be used with sign in _in addition to_ a username
+
+With Amazon Cognito, usernames are immutable, which means after the initial sign-up users are unable to change their username later. In some applications this may be undesirable, which can motivate the use of alias attributes. Alias attributes allow you to define a mutable "preferred username" in addition to an immutable username.
+
+Amplify Auth leverages **username attributes** to configure Cognito to accept an email or a phone number as the "username". Users will then need to verify their ownership of specified email or phone number to confirm their account.
+
+However, it is common to consider a "username" for display purposes. For example, you can configure your auth resource to accept a "preferred username" to be used as the display name:
+
+```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,
+ },
+ // highlight-start
+ userAttributes: {
+ preferredUsername: {
+ mutable: true,
+ required: false
+ }
+ }
+ // highlight-end
+});
+```
+
+This is not a username the user will be able to sign in with, but it can be used to mask their personal information such as their email or phone number when displaying publicly.
+
+If you would like to override the default behavior and allow your users to sign up with an immutable username, you can use CDK to modify your auth resource's [`usernameAttributes`](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_cognito.CfnUserPool.html#usernameattributes-1) configuration directly:
+
+```ts title="amplify/backend.ts"
+import { defineBackend } from "@aws-amplify/backend"
+import { auth } from "./auth/resource"
+import { data } from "./data/resource"
+
+const backend = defineBackend({
+ auth,
+ data,
+})
+
+const { cfnUserPool } = backend.auth.resources.cfnResources
+// an empty array denotes "email" and "phone_number" cannot be used as a username
+cfnUserPool.usernameAttributes = []
+```
+
+## Next Steps
+
+- [Learn how to configure email sign-up](/[platform]/build-a-backend/auth/concepts/email/)
+- [Learn how to configure phone sign-up](/[platform]/build-a-backend/auth/concepts/phone/)
+
+---
+
+---
+title: "Email"
+section: "build-a-backend/auth/concepts"
+platforms: ["android", "angular", "flutter", "javascript", "nextjs", "react", "react-native", "swift", "vue"]
+gen: 2
+last-updated: "2024-05-01T21:54:24.000Z"
+url: "https://docs.amplify.aws/react/build-a-backend/auth/concepts/email/"
+---
+
+By default Amplify Auth is scaffolded with `email` as the default method for user sign-in.
+
+```ts title="amplify/auth/resource.ts"
+import { defineAuth } from "@aws-amplify/backend"
+
+export const auth = defineAuth({
+ loginWith: {
+ email: true,
+ },
+})
+```
+
+This will configure an `email` attribute that is required for sign-up and cannot be changed.
+
+## Next steps
+
+- [Learn how to use the `signIn` API](/[platform]/build-a-backend/auth/connect-your-frontend/sign-in/)
+- [Learn how to customize emails](/[platform]/build-a-backend/auth/customize-auth-lifecycle/email-customization/)
+- [Learn how to configure your auth resource for production workloads](/[platform]/build-a-backend/auth/moving-to-production/)
+
+---
+
+---
+title: "Phone"
+section: "build-a-backend/auth/concepts"
+platforms: ["android", "angular", "flutter", "javascript", "nextjs", "react", "react-native", "swift", "vue"]
+gen: 2
+last-updated: "2024-05-01T21:54:24.000Z"
+url: "https://docs.amplify.aws/react/build-a-backend/auth/concepts/phone/"
+---
+
+By default Amplify Auth is scaffolded with `email` as the default method for user sign-in, however this can be changed or extended to also allow your users to sign in using their phone number.
+
+```ts title="amplify/auth/resource.ts"
+import { defineAuth } from "@aws-amplify/backend"
+
+export const auth = defineAuth({
+ loginWith: {
+ // highlight-next-line
+ phone: true,
+ },
+})
+```
+
+This will configure the `phone_number` attribute that is required for sign-up and cannot be changed.
+
+## Next steps
+
+- [Learn how to use the `signIn` API](/[platform]/build-a-backend/auth/connect-your-frontend/sign-in/)
+- [Learn how to configure your account for production SMS workloads](/[platform]/build-a-backend/auth/moving-to-production/)
+
+---
+
+---
+title: "Passwordless"
+section: "build-a-backend/auth/concepts"
+platforms: ["android", "angular", "javascript", "nextjs", "react", "react-native", "swift", "vue"]
+gen: 2
+last-updated: "2025-12-03T11:13:25.000Z"
+url: "https://docs.amplify.aws/react/build-a-backend/auth/concepts/passwordless/"
+---
+
+Amplify supports the use of passwordless authentication flows using the following methods:
+
+- [SMS-based one-time password (SMS OTP)](#sms-otp)
+- [Email-based one-time password (Email OTP)](#email-otp)
+- [WebAuthn passkey](#webauthn-passkey)
+
+Passwordless authentication removes the security risks and user friction associated with traditional passwords.
+
+## Configure passwordless authentication
+
+You can enable passwordless authentication methods directly in your `defineAuth` configuration. Passwordless methods are used alongside traditional password-based authentication, giving users multiple options to sign in.
+
+```ts title="amplify/auth/resource.ts"
+import { defineAuth } from '@aws-amplify/backend';
+
+export const auth = defineAuth({
+ loginWith: {
+ email: {
+ otpLogin: true // Enable email OTP
+ }
+ }
+});
+```
+
+You can enable multiple passwordless methods simultaneously:
+
+```ts title="amplify/auth/resource.ts"
+import { defineAuth } from '@aws-amplify/backend';
+
+export const auth = defineAuth({
+ loginWith: {
+ email: {
+ otpLogin: true // Enable email OTP
+ },
+ phone: {
+ otpLogin: true // Enable SMS OTP
+ },
+ webAuthn: true // Enable WebAuthn passkeys
+ }
+});
+```
+
+## SMS OTP
+
+SMS-based authentication uses phone numbers as the identifier and text messages as the verification channel. At a high level end users will perform the following steps to authenticate:
+
+1. User enters their phone number to sign up/sign in
+2. They receive a text message with a time-limited code
+3. After the user enters their code they are authenticated
+
+### Configure SMS OTP
+
+Enable SMS OTP by setting `otpLogin: true` in your phone login configuration:
+
+```ts title="amplify/auth/resource.ts"
+import { defineAuth } from '@aws-amplify/backend';
+
+export const auth = defineAuth({
+ loginWith: {
+ phone: {
+ otpLogin: true
+ }
+ }
+});
+```
+
+> **Info:** SMS-based one-time password requires your Amazon Cognito user pool to be configured to use Amazon Simple Notification Service (SNS) to send text messages. [Learn how to configure your auth resource with SNS](/[platform]/build-a-backend/auth/moving-to-production/#sms).
+>
+>
+
+[Learn more about using SMS OTP in your application code](/[platform]/build-a-backend/auth/connect-your-frontend/sign-in/#sms-otp).
+
+## Email OTP
+
+Email-based authentication uses email addresses for identification and verification. At a high level end users will perform the following steps to authenticate:
+
+1. User enters their email address to sign up/sign in
+2. They receive an email message with a time-limited code
+3. After the users enters their code they are authenticated
+
+### Configure Email OTP
+
+Enable Email OTP by setting `otpLogin: true` in your email login configuration:
+
+```ts title="amplify/auth/resource.ts"
+import { defineAuth } from '@aws-amplify/backend';
+
+export const auth = defineAuth({
+ loginWith: {
+ email: {
+ otpLogin: true
+ }
+ }
+});
+```
+
+> **Info:** Email-based one-time password requires your Amazon Cognito user pool to be configured to use Amazon Simple Email Service (SES) to send email messages. [Learn how to configure your auth resource with SES](/[platform]/build-a-backend/auth/moving-to-production/#email).
+
+[Learn more about using email OTP in your application code](/[platform]/build-a-backend/auth/connect-your-frontend/sign-in/#email-otp).
+
+## WebAuthn Passkey
+
+WebAuthn uses biometrics or security keys for authentication, leveraging device-specific security features. At a high level end users will perform the following steps to authenticate:
+
+1. User chooses to register a passkey
+2. Their device prompts for biometric/security key verification
+3. For future logins, they'll authenticate using the same method
+
+### Configure WebAuthn
+
+Enable WebAuthn passkeys in your auth configuration. The simplest configuration uses automatic relying party ID resolution:
+
+```ts title="amplify/auth/resource.ts"
+import { defineAuth } from '@aws-amplify/backend';
+
+export const auth = defineAuth({
+ loginWith: {
+ email: true, // Users need a sign-up method
+ webAuthn: true // Automatically resolves relying party ID
+ }
+});
+```
+
+When `webAuthn: true` is used, the relying party ID is automatically resolved:
+- In **sandbox** environments: resolves to `localhost`
+- In **branch** deployments: resolves to your Amplify app domain (e.g., `[branch].[appId].amplifyapp.com`)
+
+For production environments or custom domains, specify the relying party ID explicitly:
+
+```ts title="amplify/auth/resource.ts"
+import { defineAuth } from '@aws-amplify/backend';
+
+export const auth = defineAuth({
+ loginWith: {
+ email: true,
+ webAuthn: {
+ relyingPartyId: 'example.com',
+ userVerification: 'required' // or 'preferred' (default)
+ }
+ }
+});
+```
+
+
+You can read more about how passkeys work in the [Android developer docs](https://developer.android.com/design/ui/mobile/guides/patterns/passkeys).
+
+> **Warning:** Registering a passkey is supported on Android 9 (API level 28) and above.
+
+Using passkeys with Amplify requires following these steps:
+
+1. Deploy a Digital Asset Links file to your website granting the `get_login_creds` permission to your application. See the [Credential Manager documentation](https://developer.android.com/identity/sign-in/credential-manager#add-support-dal) for more details about this file.
+1. Configure WebAuthn in your `defineAuth` as shown above, specifying your website domain as the `relyingPartyId`.
+1. Use the Amplify Android APIs to first [register a passkey](/[platform]/build-a-backend/auth/manage-users/manage-webauthn-credentials/#associate-webauthn-credentials) and then to [sign in with WebAuthn](/[platform]/build-a-backend/auth/connect-your-frontend/sign-in/#webauthn-passkeys).
+
+
+
+
+
+[Learn more about using WebAuthn passkeys in your application code](/[platform]/build-a-backend/auth/connect-your-frontend/sign-in/#webauthn-passkeys).
+
+### Managing credentials
+
+Passwordless authentication with WebAuthn requires associating one or more credentials with the user's Amazon Cognito account. Amplify provides APIs that integrate with each platform's local authenticator to easily create, view, and delete these credential associations.
+
+[Learn more about managing WebAuthn credentials](/[platform]/build-a-backend/auth/manage-users/manage-webauthn-credentials).
+
+## Passwordless authentication
+
+When you enable passwordless authentication methods, traditional password authentication remains available. This gives users flexibility to choose their preferred authentication method:
+
+```ts title="amplify/auth/resource.ts"
+import { defineAuth } from '@aws-amplify/backend';
+
+export const auth = defineAuth({
+ loginWith: {
+ email: {
+ otpLogin: true // Email OTP enabled alongside password auth
+ }
+ }
+});
+```
+
+In this configuration, users can authenticate using either:
+- Email and password (traditional)
+- Email OTP (passwordless)
+
+You can enable multiple passwordless methods to give users even more options:
+
+```ts title="amplify/auth/resource.ts"
+import { defineAuth } from '@aws-amplify/backend';
+
+export const auth = defineAuth({
+ loginWith: {
+ email: {
+ otpLogin: true
+ },
+ phone: {
+ otpLogin: true
+ },
+ webAuthn: {
+ relyingPartyId: 'example.com'
+ }
+ }
+});
+```
+
+In this configuration, users can authenticate using:
+- Email and password
+- Email OTP
+- Phone and password
+- SMS OTP
+- WebAuthn passkeys
+
+> **Info:** When using WebAuthn, users still need a way to initially sign up (email or phone). WebAuthn credentials are then associated with their account for future sign-ins.
+
+## Next steps
+
+- [Learn how to implement passwordless sign-in in your application](/[platform]/build-a-backend/auth/connect-your-frontend/sign-in/)
+- [Configure email settings for Email OTP](/[platform]/build-a-backend/auth/moving-to-production/#email)
+- [Configure SMS settings for SMS OTP](/[platform]/build-a-backend/auth/moving-to-production/#sms)
+- [Manage WebAuthn credentials](/[platform]/build-a-backend/auth/manage-users/manage-webauthn-credentials/)
+
+---
+
+---
+title: "User attributes"
+section: "build-a-backend/auth/concepts"
+platforms: ["android", "angular", "flutter", "javascript", "nextjs", "react", "react-native", "swift", "vue"]
+gen: 2
+last-updated: "2025-02-25T21:43:55.000Z"
+url: "https://docs.amplify.aws/react/build-a-backend/auth/concepts/user-attributes/"
+---
+
+Amplify Auth stores user profile information in user attributes. When the default method for user sign-in, Amplify Auth will automatically configure an `email` or `phoneNumber` attribute that is required for sign-in.
+
+To extend a user profile beyond the default `email` or `phoneNumber` attribute that is automatically configured when specified in your auth resource's `loginWith` property, you can configure attributes with the `userAttributes` property:
+
+> **Warning:** **Warning**: After you create your auth resource, you cannot switch an attribute between required and not required.
+
+```ts title="amplify/auth/resource.ts"
+import { defineAuth } from "@aws-amplify/backend"
+
+export const auth = defineAuth({
+ loginWith: {
+ // this configures a required "email" attribute
+ email: true,
+ },
+ // highlight-start
+ userAttributes: {
+ // specify a "birthdate" attribute
+ birthdate: {
+ mutable: true,
+ required: false,
+ }
+ },
+ // highlight-end
+})
+```
+
+## Standard attributes
+
+User attributes are defined as [Cognito Standard Attributes](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-settings-attributes.html#cognito-user-pools-standard-attributes). Attributes can be configured to be _required_ for user sign-up in addition to whether the values are _mutable_. When configuring your resource to allow your users to login with `email`, an email must be specified for user sign-up and cannot be changed later. However additional attributes can be configured to be optional, and mutable after sign-up.
+
+```ts title="amplify/auth/resource.ts"
+import { defineAuth } from "@aws-amplify/backend";
+
+export const auth = defineAuth({
+ loginWith: {
+ email: true,
+ },
+ userAttributes: {
+ // Maps to Cognito standard attribute 'address'
+ address: {
+ mutable: true,
+ required: true,
+ },
+ // Maps to Cognito standard attribute 'birthdate'
+ birthdate: {
+ mutable: true,
+ required: false,
+ },
+ // Maps to Cognito standard attribute 'email'
+ email: {
+ mutable: true,
+ required: true,
+ },
+ // Maps to Cognito standard attribute 'family_name'
+ familyName: {
+ mutable: true,
+ required: false,
+ },
+ // Maps to Cognito standard attribute 'gender'
+ gender: {
+ mutable: true,
+ required: false,
+ },
+ // Maps to Cognito standard attribute 'given_name'
+ givenName: {
+ mutable: true,
+ required: false,
+ },
+ // Maps to Cognito standard attribute 'locale'
+ locale: {
+ mutable: true,
+ required: false,
+ },
+ // Maps to Cognito standard attribute 'middle_name'
+ middleName: {
+ mutable: true,
+ required: false,
+ },
+ // Maps to Cognito standard attribute 'name'
+ fullname: {
+ mutable: true,
+ required: false,
+ },
+ // Maps to Cognito standard attribute 'nickname'
+ nickname: {
+ mutable: true,
+ required: false,
+ },
+ // Maps to Cognito standard attribute 'phone_number'
+ phoneNumber: {
+ mutable: true,
+ required: false,
+ },
+ // Maps to Cognito standard attribute 'picture'
+ profilePicture: {
+ mutable: true,
+ required: false,
+ },
+ // Maps to Cognito standard attribute 'preferred_username'
+ preferredUsername: {
+ mutable: true,
+ required: false,
+ },
+ // Maps to Cognito standard attribute 'profile'
+ profilePage: {
+ mutable: true,
+ required: false,
+ },
+ // Maps to Cognito standard attribute 'zoneinfo'
+ timezone: {
+ mutable: true,
+ required: false,
+ },
+ // Maps to Cognito standard attribute 'updated_at'
+ lastUpdateTime: {
+ mutable: true,
+ required: false,
+ },
+ // Maps to Cognito standard attribute 'website'
+ website: {
+ mutable: true,
+ required: false,
+ },
+ },
+});
+```
+
+## Custom attributes
+
+In addition to the provided standard attributes, you can configure [Custom Attributes](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-settings-attributes.html#user-pool-settings-custom-attributes). These are attributes that are typically unique to your use case, such as a tenant ID or a user's display name. Custom attributes are identified by the `custom:` prefix:
+
+```ts title="amplify/auth/resource.ts"
+import { defineAuth } from "@aws-amplify/backend"
+
+export const auth = defineAuth({
+ loginWith: {
+ // this configures a required "email" attribute
+ email: true,
+ },
+ userAttributes: {
+ // highlight-start
+ "custom:display_name": {
+ dataType: "String",
+ mutable: true,
+ maxLen: 16,
+ minLen: 1,
+ },
+ "custom:favorite_number": {
+ dataType: "Number",
+ mutable: true,
+ min: 1,
+ max: 100,
+ },
+ "custom:is_beta_user": {
+ dataType: "Boolean",
+ mutable: true,
+ },
+ "custom:started_free_trial": {
+ dataType: "DateTime",
+ mutable: true,
+ },
+ // highlight-end
+ },
+})
+```
+
+Unlike standard attributes, custom attributes cannot natively be required for sign-up, however can be codified to require some value by [validating user attributes upon sign-up with a pre sign-up trigger](/[platform]/build-a-backend/functions/examples/user-attribute-validation/).
+
+Custom attributes can also be configured with specific data types. The following data types are supported:
+
+- `String`
+- `Number`
+- `Boolean`
+- `DateTime`
+
+Shown in the snippet above, `String` and `Number` can be assigned minimum and maximum constraints. This is useful to defer simple validations to the underlying service, although does not extend to complex validations such as matching against a regular expression.
+
+## Next steps
+
+- [Learn how attributes are surfaced to tokens](/[platform]/build-a-backend/auth/concepts/tokens-and-credentials/)
+- [Learn how to manage your user attributes](/[platform]/build-a-backend/auth/connect-your-frontend/manage-user-attributes)
+
+---
+
+---
+title: "User groups"
+section: "build-a-backend/auth/concepts"
+platforms: ["angular", "javascript", "nextjs", "react", "vue"]
+gen: 2
+last-updated: "2024-05-03T17:21:51.000Z"
+url: "https://docs.amplify.aws/react/build-a-backend/auth/concepts/user-groups/"
+---
+
+Amplify Auth provides a mechanism that allows you to group users. Assigning users to groups enable you to customize access for a collection of users, or leverage for auditing purposes. For example, only "ADMINS" users are permitted to delete posts from a bulletin, or only "EDITORS" are permitted to modify posts in a "draft" state. To get started with groups, configure the `groups` property:
+
+```ts title="amplify/auth/resource.ts"
+import { defineAuth } from "@aws-amplify/backend"
+
+export const auth = defineAuth({
+ loginWith: {
+ email: true,
+ },
+ // highlight-start
+ groups: ["ADMINS", "EDITORS"],
+ // highlight-end
+})
+```
+
+
+
+**Note:** There are a few [limitations with groups](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-user-groups.html#user-pool-user-groups-limitations), including a limit of 10,000 groups per user pool.
+
+
+
+## Defining access
+
+Amplify resources enable you to define access for groups using common language. For example, you can use `allow.groups` in data:
+
+```ts title="amplify/data/resource.ts"
+import { type ClientSchema, a, defineData } from "@aws-amplify/backend"
+
+const schema = a.schema({
+ Article: a.model({}).authorization(allow => [
+ allow.groups(["EDITORS"]).to(["read", "update"])
+ ])
+})
+
+// ...
+```
+
+Or in storage:
+
+```ts title="amplify/storage/articles/resource.ts"
+import { defineStorage } from "@aws-amplify/backend"
+
+export const storage = defineStorage({
+ name: "articles",
+ access: (allow) => ({
+ "drafts/*": [allow.groups(["EDITORS"]).to(["read", "write"])],
+ }),
+})
+```
+
+By defining access with groups, Amplify configures authorization rules to read from the current user's groups. User pool groups are available as a claim in the user's ID token and access token as `cognito:groups`. Requests can be made to secure resources using the access token and validated against this claim to permit action on the resource.
+
+## Group roles
+
+Each Cognito user pool group is assigned an [IAM role](https://aws.amazon.com/iam/features/manage-roles/). IAM roles can be modified to extend access to other AWS resources. Roles can be accessed from your backend on the `role` property of your group:
+
+```ts title="amplify/backend.ts"
+import { defineBackend } from '@aws-amplify/backend';
+import { auth } from './auth/resource';
+import { data } from './data/resource';
+
+/**
+ * @see https://docs.amplify.aws/react/build-a-backend/ to add storage, functions, and more
+ */
+const backend = defineBackend({
+ auth,
+ data,
+});
+
+// highlight-start
+const { groups } = backend.auth.resources
+
+// https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_iam.IRole.html
+groups["ADMINS"].role
+// highlight-end
+```
+
+## Next steps
+
+- [Learn how to automatically add a user to a group upon account confirmation](/[platform]/build-a-backend/functions/examples/add-user-to-group/)
+- [Learn how to secure access to data models using groups](/[platform]/build-a-backend/data/customize-authz/user-group-based-data-access)
+- [Learn how to secure access to storage objects using groups](/[platform]/build-a-backend/storage/set-up-storage/)
+
+---
+
+---
+title: "Multi-factor authentication"
+section: "build-a-backend/auth/concepts"
+platforms: ["android", "angular", "flutter", "javascript", "nextjs", "react", "react-native", "swift", "vue"]
+gen: 2
+last-updated: "2025-11-14T14:41:17.000Z"
+url: "https://docs.amplify.aws/react/build-a-backend/auth/concepts/multi-factor-authentication/"
+---
+
+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 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';
+
+export const auth = defineAuth({
+ loginWith: {
+ email: true
+ },
+// highlight-start
+ multifactor: {
+ mode: 'OPTIONAL',
+ totp: true,
+ email: true,
+ },
+ senders: {
+ email: {
+ fromEmail: 'noreply@example.com',
+ fromName: 'My App',
+ },
+ },
+// highlight-end
+ userAttributes: {
+ phoneNumber: {
+ required: true
+ }
+ }
+});
+```
+
+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 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) | 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
+
+> **Info:** If you are using the [Authenticator component](https://ui.docs.amplify.aws/react/connected-components/authenticator) with Amplify, this feature works without any additional code. The guide below is for writing your own implementation.
+
+
+
+> **Info:** 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.
+
+
+
+> **Info:** 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.
+
+
+
+> **Info:** 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 SMS as your second layer of authentication with MFA as shown above, your users will get an authentication code via a text message to complete sign-in after they sign in with their username and password.
+
+> **Warning:** **Warning:** In order to send SMS authentication codes, you must [request an origination number](https://docs.aws.amazon.com/pinpoint/latest/userguide/settings-request-number.html). [Learn more about configuring your auth resource for production workloads](/[platform]/build-a-backend/auth/moving-to-production/).
+
+### Enable SMS MFA during sign-up
+
+You will need to pass `phone_number` as a user attribute to enable SMS MFA for your users during sign-up. However, if the primary sign-in mechanism for your Cognito resource is `phone_number` (without enabling `username`), then you do not need to pass it as an attribute.
+
+
+```ts
+import { signUp } from 'aws-amplify/auth';
+
+await signUp({
+ username: "hello@mycompany.com",
+ password: "hunter2",
+ options: {
+ userAttributes: {
+ phone_number: "+15555555555",
+ email: "hello@mycompany.com",
+ },
+ },
+});
+```
+
+
+
+```dart
+Future signUpWithPhoneVerification(
+ String username,
+ String password,
+) async {
+ await Amplify.Auth.signUp(
+ username: username,
+ password: password,
+ options: SignUpOptions(
+ userAttributes: {
+ // ... if required
+ AuthUserAttributeKey.email: 'test@example.com',
+ AuthUserAttributeKey.phoneNumber: '+18885551234',
+ },
+ ),
+ );
+}
+```
+
+
+
+```swift
+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)")
+ }
+}
+```
+
+
+By default, you have to verify a user account after they sign up using the `confirmSignUp` API, which will send a one-time password to the user's phone number or email, depending on your Amazon Cognito configuration.
+
+
+```ts
+import { confirmSignUp } from 'aws-amplify/auth';
+
+await confirmSignUp({
+ username: "hello@mycompany.com",
+ confirmationCode: "123456",
+})
+```
+
+
+
+```dart
+Future confirmSignUpPhoneVerification(
+ String username,
+ String otpCode,
+) async {
+ await Amplify.Auth.confirmSignUp(
+ username: username,
+ confirmationCode: otpCode,
+ );
+}
+```
+
+
+
+```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)")
+ }
+}
+```
+
+
+### Manage SMS MFA during sign-in
+
+After a user signs in, if they have MFA enabled for their account, a challenge will be returned that you would need to call the `confirmSignIn` API where the user provides their confirmation code sent to their phone number.
+
+If MFA is **ON** or enabled for the user, you must call `confirmSignIn` with the OTP sent to their phone.
+
+
+```ts
+import { confirmSignIn } from 'aws-amplify/auth';
+
+await confirmSignIn({
+ challengeResponse: "123456"
+});
+```
+
+
+
+```dart
+Future confirmSignInPhoneVerification(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: 'PREFERRED' });
+```
+
+
+
+```dart
+Future updateMfaPreferences() async {
+ final cognitoPlugin = Amplify.Auth.getPlugin(AmplifyAuthCognito.pluginKey);
+
+ await cognitoPlugin.updateMfaPreference(
+ sms: MfaPreference.enabled, // or .preferred
+ );
+}
+```
+
+
+
+```swift
+func updateMFAPreferences() async throws {
+ let authCognitoPlugin = try Amplify.Auth.getPlugin(
+ for: "awsCognitoAuthPlugin") as? AWSCognitoAuthPlugin
+
+ let smsMfaPreference: MFAPreference = .preferred
+
+ try await authCognitoPlugin?.updateMFAPreference(
+ sms: smsMfaPreference)
+}
+```
+
+
+## Multi-factor authentication with TOTP
+
+
+> **Info:** If you are using the [Authenticator component](https://ui.docs.amplify.aws/react/connected-components/authenticator) with Amplify, this feature works without any additional code. The guide below is for writing your own implementation.
+
+
+
+> **Info:** 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.
+
+
+
+> **Info:** 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.
+
+
+
+> **Info:** 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.
+
+
+You can use Time-based One-Time Password (TOTP) for multi-factor authentication (MFA) in your web or mobile applications. The Amplify Auth category includes support for TOTP setup and verification using authenticator apps, offering an integrated solution and enhanced security for your users. These apps, such as Google Authenticator, Microsoft Authenticator, have the TOTP algorithm built-in and work by using a shared secret key and the current time to generate short-lived, six digit passwords.
+
+### Set up TOTP for a user
+
+
+After you initiate a user sign in with the `signIn` API where a user is required to set up TOTP as an MFA method, the API call will return `CONTINUE_SIGN_IN_WITH_TOTP_SETUP` as a challenge and next step to handle in your app. You will get that challenge if the following conditions are met:
+
+- MFA is marked as **Required** in your user pool.
+- TOTP is enabled in your user pool.
+- User does not have TOTP MFA set up already.
+
+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 { signIn, SignInOutput } from 'aws-amplify/auth';
+
+const output = await signIn({
+ username: "hello@mycompany.com",
+ password: "hunter2"
+});
+
+const { nextStep } = output;
+switch (nextStep.signInStep) {
+ // ...
+ case 'CONTINUE_SIGN_IN_WITH_TOTP_SETUP':
+ const totpSetupDetails = nextStep.totpSetupDetails;
+ const appName = 'my_app_name';
+ const setupUri = totpSetupDetails.getSetupUri(appName);
+ // Open setupUri with an authenticator APP to retrieve an OTP code
+ break;
+ // ...
+}
+```
+
+
+
+After you initiate a user sign in with the `signIn` API where a user is required to set up TOTP as an MFA method, the API call will return `continueSignInWithTOTPSetup` as a challenge and next step to handle in your app. You will get that challenge if the following conditions are met:
+
+- MFA is marked as **Required** in your user pool.
+- TOTP is enabled in your user pool.
+- User does not have TOTP MFA set up already.
+
+The `continueSignInWithTOTPSetup` 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.
+
+
+
+```dart
+Future signInUser(String username, String password) async {
+ try {
+ final result = await Amplify.Auth.signIn(
+ username: username,
+ password: password,
+ );
+ return _handleSignInResult(result);
+ } on AuthException catch (e) {
+ safePrint('Error signing in: ${e.message}');
+ }
+}
+
+Future _handleSignInResult(SignInResult result) async {
+ switch (result.nextStep.signInStep) {
+ // Β·Β·Β·
+ case AuthSignInStep.continueSignInWithTotpSetup:
+ final totpSetupDetails = result.nextStep.totpSetupDetails!;
+ final setupUri = totpSetupDetails.getSetupUri(appName: 'MyApp');
+ safePrint('Open URI to complete setup: $setupUri');
+ // Β·Β·Β·
+ }
+}
+```
+
+
+
+```swift
+func signIn(username: String, password: String) async {
+ do {
+ let signInResult = try await Amplify.Auth.signIn(
+ username: username,
+ password: password
+ )
+
+ if case .continueSignInWithTOTPSetup(let setUpDetails) = signInResult.nextStep {
+
+ print("Received next step as continue sign in by setting up TOTP")
+ print("Shared secret that will be used to set up TOTP in the authenticator app \(setUpDetails.sharedSecret)")
+
+ // appName parameter will help distinguish the account in the Authenticator app
+ let setupURI = try setUpDetails.getSetupURI(appName: ">")
+
+ print("TOTP Setup URI: \(setupURI)")
+
+ // Prompt the user to enter the TOTP code generated in their authenticator app
+ // Then invoke `confirmSignIn` api with the code
+
+ }
+ } catch let error as AuthError {
+ print("Sign in failed \(error)")
+ } catch {
+ print("Unexpected error: \(error)")
+ }
+}
+```
+
+
+The TOTP code can be obtained from the user via a text field or any other means. Once the user provides the TOTP code, call `confirmSignIn` with the TOTP code as the `challengeResponse` parameter.
+
+
+```ts
+import { confirmSignIn } from 'aws-amplify/auth';
+
+await confirmSignIn({
+ challengeResponse: "123456"
+});
+```
+
+
+
+```dart
+Future confirmTotpUser(String totpCode) async {
+ try {
+ final result = await Amplify.Auth.confirmSignIn(
+ confirmationValue: totpCode,
+ );
+ return _handleSignInResult(result);
+ } on AuthException catch (e) {
+ safePrint('Error confirming TOTP code: ${e.message}');
+ }
+}
+```
+
+
+
+```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({ totp: 'PREFERRED' });
+```
+
+
+
+```dart
+Future updateMfaPreferences() async {
+ final cognitoPlugin = Amplify.Auth.getPlugin(AmplifyAuthCognito.pluginKey);
+
+ await cognitoPlugin.updateMfaPreference(
+ totp: MfaPreference.preferred,
+ );
+}
+```
+
+
+
+```swift
+func updateMFAPreferences() async throws {
+ let authCognitoPlugin = try Amplify.Auth.getPlugin(
+ for: "awsCognitoAuthPlugin") as? AWSCognitoAuthPlugin
+
+ let totpMfaPreference: MFAPreference = .preferred
+
+ try await authCognitoPlugin?.updateMFAPreference(
+ totp: totpMfaPreference)
+}
+```
+
+
+### Enable TOTP after a user is signed in
+
+TOTP MFA can be set up after a user has signed in. This can be done when the following conditions are met:
+
+- MFA is marked as **Optional** or **Required** in your user pool.
+- TOTP is marked as an enabled MFA method in your user pool.
+
+TOTP can be set up by calling the `setUpTOTP` and `verifyTOTPSetup` APIs in the `Auth` category.
+
+Invoke the `setUpTOTP` API to generate a `TOTPSetupDetails` object which should 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.
+
+that contains the `sharedSecret` which will be used to either to generate a QR code or can be manually entered into an Authenticator app.
+
+
+```ts
+import { setUpTOTP } from 'aws-amplify/auth';
+
+const totpSetupDetails = await setUpTOTP();
+const appName = 'my_app_name';
+const setupUri = totpSetupDetails.getSetupUri(appName);
+// Open setupUri with an authenticator APP to retrieve an OTP code
+```
+
+
+
+```dart
+Future setUpTotp() async {
+ try {
+ final totpSetupDetails = await Amplify.Auth.setUpTotp();
+ final setupUri = totpSetupDetails.getSetupUri(appName: 'MyApp');
+ safePrint('Open URI to complete setup: $setupUri');
+ } on AuthException catch (e) {
+ safePrint('An error occurred setting up TOTP: $e');
+ }
+}
+```
+
+
+
+```swift
+func setUpTOTP() async {
+ do {
+ let setUpDetails = try await Amplify.Auth.setUpTOTP()
+
+ print("Received next step as continue sign in by setting up TOTP")
+ print("Shared secret that will be used to set up TOTP in the authenticator app \(setUpDetails.sharedSecret)")
+
+ // appName parameter will help distinguish the account in the Authenticator app
+ let setupURI = try setUpDetails.getSetupURI(appName: ">")
+
+ print("TOTP Setup URI: \(setupURI)")
+
+ // Prompt the user to enter the TOTP code generated in their authenticator app
+ // Then invoke `confirmSignIn` api with the code
+ } catch {
+ print("TOTP Setup Initiation failed \(error)")
+ }
+}
+```
+
+
+Once the Authenticator app is set up, the user must generate a TOTP code and provide it to the library. Pass the code to `verifyTOTPSetup` to complete the TOTP setup process.
+
+
+```ts
+import { verifyTOTPSetup } from 'aws-amplify/auth';
+
+await verifyTOTPSetup({ code: "123456" });
+```
+
+
+
+```dart
+Future verifyTotpSetup(String totpCode) async {
+ try {
+ await Amplify.Auth.verifyTotpSetup(totpCode);
+ } on AuthException catch (e) {
+ safePrint('An error occurred verifying TOTP: $e');
+ }
+}
+```
+
+
+
+```swift
+func verifyTOTPSetup(totpCodeFromAuthenticatorApp: String) async {
+ do {
+ try await Amplify.Auth.verifyTOTPSetup(
+ code: totpCodeFromAuthenticatorApp)
+ } catch {
+ print("TOTP Setup Verification failed \(error)")
+ }
+}
+```
+
+
+After TOTP setup is complete, 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' });
+```
+
+
+
+```dart
+Future updateMfaPreferences() async {
+ final cognitoPlugin = Amplify.Auth.getPlugin(AmplifyAuthCognito.pluginKey);
+
+ await cognitoPlugin.updateMfaPreference(
+ sms: MfaPreference.enabled,
+ totp: MfaPreference.preferred,
+ );
+}
+```
+
+
+
+```swift
+func updateMFAPreferences() async throws {
+ let authCognitoPlugin = try Amplify.Auth.getPlugin(
+ for: "awsCognitoAuthPlugin") as? AWSCognitoAuthPlugin
+
+ let smsMfaPreference: MFAPreference = .enabled
+ let totpMfaPreference: MFAPreference = .preferred
+
+ try await authCognitoPlugin?.updateMFAPreference(
+ sms: smsMfaPreference,
+ totp: totpMfaPreference)
+}
+```
+
+
+### Recover from a lost TOTP device
+
+> **Warning:** If a user loses access to their TOTP device, they will need to contact an administrator to get help accessing their account. Based on the Cognito user pool configuration, the administrator can use the [AdminSetUserMFAPreference](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminSetUserMFAPreference.html) to either change the MFA preference to a different MFA method or to disable MFA for the user.
+
+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.
+
+## Multi-factor authentication with EMAIL
+To enable email MFA, set `email: true` in your multifactor configuration and configure an email sender.
+
+> **Warning:** To permit users to sign in with email MFA, your user pool must have the following configuration options:
+>
+> - You have the Plus or Essentials feature plan in your user pool.
+> - Your user pool sends email messages with your own Amazon SES resources.
+>
+> For more details, see [Amazon Cognito email MFA configuration](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-settings-mfa-sms-email-message.html).
+
+```ts title="amplify/auth/resource.ts"
+import { defineAuth } from '@aws-amplify/backend';
+
+export const auth = defineAuth({
+ loginWith: {
+ email: true
+ },
+ multifactor: {
+ mode: 'OPTIONAL',
+ email: true,
+ },
+ // BE SURE TO PICK A RECOVERY OPTION APPROPRIATE FOR YOUR APPLICATION.
+ accountRecovery: "EMAIL_AND_PHONE_WITHOUT_MFA",
+ senders: {
+ email: {
+ fromEmail: 'noreply@example.com',
+ fromName: 'My App',
+ },
+ },
+});
+```
+
+
+> **Info:** 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.
+
+
+
+> **Info:** 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.
+
+
+
+> **Info:** 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.
+
+> **Warning:** 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).
+> - If account recovery is enabled in Cognito, the delivery method for recovery messages cannot be set to `Email only`
+
+### 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 { signUp } from 'aws-amplify/auth';
+
+await signUp({
+ username: "+15555555555",
+ password: "hunter2",
+ options: {
+ userAttributes: {
+ email: "hello@mycompany.com",
+ },
+ },
+});
+```
+
+
+
+
+#### [Java]
+
+```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 - Callbacks]
+
+```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 - Coroutines]
+
+```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)
+}
+```
+
+#### [RxJava]
+
+```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 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 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)")
+ }
+}
+```
+
+
+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.
+
+
+```ts
+import { confirmSignUp } from 'aws-amplify/auth';
+
+await confirmSignUp({
+ username: "+15555555555",
+ confirmationCode: "123456",
+})
+```
+
+
+
+
+#### [Java]
+
+```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 - Callbacks]
+
+```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 - Coroutines]
+
+```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")
+}
+```
+
+#### [RxJava]
+
+```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)
+);
+```
+
+
+
+
+```dart
+Future confirmSignUpEmailVerification(
+ String username,
+ String otpCode,
+) async {
+ await Amplify.Auth.confirmSignUp(
+ username: username,
+ confirmationCode: otpCode,
+ );
+}
+```
+
+
+
+```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)")
+ }
+}
+```
+
+
+### 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]
+
+```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 - Callbacks]
+
+```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 - Coroutines]
+
+```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")
+}
+```
+
+#### [RxJava]
+
+```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({ email: 'PREFERRED' });
+```
+
+
+
+
+#### [Java]
+
+```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]
+
+```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(
+ email: MfaPreference.enabled, // or .preferred
+ );
+}
+```
+
+
+
+```swift
+func updateMFAPreferences() async throws {
+ let authCognitoPlugin = try Amplify.Auth.getPlugin(
+ for: "awsCognitoAuthPlugin") as? AWSCognitoAuthPlugin
+
+ let emailMfaPreference: MFAPreference = .preferred
+
+ try await authCognitoPlugin?.updateMFAPreference(
+ email: emailMfaPreference)
+}
+```
+
+
+## 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 { fetchMFAPreference } from 'aws-amplify/auth';
+
+const { enabled, preferred } = await fetchMFAPreference();
+```
+
+
+
+
+#### [Java]
+
+```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)
+ );
+}
+```
+
+#### [Kotlin]
+
+```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) }
+)
+```
+
+
+
+
+```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}');
+}
+```
+
+
+
+```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)")
+}
+```
+
+
+### Update the current user's MFA preferences
+
+Invoke the following API to update the MFA preference for the current user.
+
+> **Warning:** 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]
+
+```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)
+ );
+}
+```
+
+#### [Kotlin - Callbacks]
+
+```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) }
+)
+```
+
+
+
+
+```dart
+Future updateMfaPreferences() async {
+ final cognitoPlugin = Amplify.Auth.getPlugin(AmplifyAuthCognito.pluginKey);
+
+ await cognitoPlugin.updateMfaPreference(
+ sms: MfaPreference.enabled,
+ totp: MfaPreference.preferred,
+ );
+}
+```
+
+
+
+```swift
+func updateMFAPreferences() async throws {
+ let authCognitoPlugin = try Amplify.Auth.getPlugin(
+ for: "awsCognitoAuthPlugin") as? AWSCognitoAuthPlugin
+
+ let smsMfaPreference: MFAPreference = .enabled
+ let totpMfaPreference: MFAPreference = .preferred
+
+ try await authCognitoPlugin?.updateMFAPreference(
+ sms: smsMfaPreference,
+ totp: totpMfaPreference)
+}
+```
+
+
+## Remember a device
+
+Remembering a device is useful in conjunction with MFA because it allows the second factor requirement to be automatically met when your user signs in on that device and reduces friction in their sign-in experience. By default, this feature is turned off.
+
+> **Info:** **Note:** The [device tracking and remembering](https://aws.amazon.com/blogs/mobile/tracking-and-remembering-devices-using-amazon-cognito-your-user-pools/) features are not available if any of the following conditions are met:
+>
+> - the federated OAuth flow with Cognito User Pools or Hosted UI is used, or
+> - when the `signIn` API uses the `USER_PASSWORD_AUTH` as the `authFlowType`.
+
+### Configure device tracking
+
+You can configure device tracking with `deviceTracking` construct.
+
+```ts title="amplify/backend.ts"
+import { defineBackend } from '@aws-amplify/backend';
+import { auth } from './auth/resource';
+import { data } from './data/resource';
+
+const backend = defineBackend({
+ auth,
+ data
+});
+
+const { cfnUserPool } = backend.auth.resources.cfnResources;
+
+cfnUserPool.addPropertyOverride('DeviceConfiguration', {
+ ChallengeRequiredOnNewDevice: true,
+ DeviceOnlyRememberedOnUserPrompt: false
+});
+```
+
+
+
+There are differences to keep in mind when working with remembered, forgotten, and tracked devices.
+
+- **Tracked:** Every time the user signs in with a new device, the client is given the device key at the end of a successful authentication event. We use this device key to generate a salt and password verifier which is used to call the `ConfirmDevice` API. At this point, the device is considered to be "tracked". Once the device is in a tracked state, you can use the Amazon Cognito console to see the time it started to be tracked, last authentication time, and other information about that device.
+- **Remembered:** Remembered devices are also tracked. During user authentication, the device key and secret pair assigned to a remembered device is used to authenticate the device to verify that it is the same device that the user previously used to sign in.
+- **Not Remembered:** A not-remembered device is a tracked device where Cognito has been configured to require users to "Opt-in" to remember a device but the user has chosen not to remember the device. This use case is for users signing into their application from a device that they don't own.
+- **Forgotten:** In the event that you no longer want to remember or track devices, you can use the `forgetDevice()` API to remove devices from being both remembered and tracked.
+
+
+
+## Next steps
+
+- [Learn how to sign-up with MFA enabled](/[platform]/build-a-backend/auth/connect-your-frontend/sign-in/#with-multi-factor-auth-enabled)
+- [Learn how to manage user devices](/[platform]/build-a-backend/auth/manage-users/manage-devices/)
+
+---
+
+---
+title: "External identity providers"
+section: "build-a-backend/auth/concepts"
+platforms: ["android", "angular", "flutter", "javascript", "nextjs", "react", "react-native", "swift", "vue"]
+gen: 2
+last-updated: "2025-06-23T10:51:32.000Z"
+url: "https://docs.amplify.aws/react/build-a-backend/auth/concepts/external-identity-providers/"
+---
+
+Before you configure external sign-in with Amplify Auth you will need to set up your developer account with each provider you are using.
+
+
+
+**Note:** Amazon Cognito provides first class support for Facebook Login, Google Sign-In, Login with Amazon, and Sign in with Apple for seamless setup. However you can configure other Identity Providers that support SAML or OpenID Connect (OIDC).
+
+
+
+> **Warning:** **Warning:** When configuring external sign-in it's important to exercise caution when designating attributes as "required." Different external 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.
+
+#### [Facebook Login]
+
+1. Create a [developer account with Facebook](https://developers.facebook.com/docs/facebook-login).
+2. [Sign in](https://developers.facebook.com/) with your Facebook credentials.
+3. Choose _My Apps_ from the top navigation bar, and on the page that loads choose _Create App_. 
+4. For your use case, choose _Set up Facebook Login_. 
+5. For platform, choose _Website_ and select _No, I'm not building a game_.
+6. Give your Facebook app a name and choose _Create app_. 
+7. On the left navigation bar, choose _Settings_ and then _Basic_. 
+8. Note the _App ID_ and the _App Secret_. You will use them in the next section in the CLI flow.
+
+#### [Google Sign-In]
+
+1. Go to [Google developer console](https://console.developers.google.com).
+2. Click _Select a project_. 
+3. Click _NEW PROJECT_. 
+4. Type in project name and click _CREATE_. 
+5. Once the project is created, from the left navigation menu, select _APIs & Services_, then select _Credentials_. 
+6. Click _CONFIGURE CONSENT SCREEN_. 
+7. Click _CREATE_. 
+8. Type in _App Information_ and _Developer contact information_ which are required fields and click _SAVE AND CONTINUE_ three times (OAuth consent screen -> Scopes -> Test Users) to finish setting up the consent screen.
+9. Back under the _Credentials_ tab, Create your OAuth2.0 credentials by choosing _OAuth client ID_ from the _Create credentials_ drop-down list. .
+10. Choose _Web application_ as _Application type_ and name your OAuth Client.
+11. Click _Create_.
+12. Take note of _Your client ID_ and _Your Client Secret_. You will need them for the next section in the CLI flow.
+13. Choose _OK_.
+
+#### [Login with Amazon]
+
+1. Create a [developer account with Amazon](https://developer.amazon.com/login-with-amazon).
+2. [Sign in](https://developer.amazon.com/loginwithamazon/console/site/lwa/overview.html) with your Amazon credentials.
+3. You need to create an Amazon security profile to receive the Amazon Client ID and Client Secret. Choose _Create a Security Profile_. 
+4. Type in a _Security Profile Name_, a _Security Profile Description_, and a _Consent Privacy Notice URL_. 
+5. Choose _Save_.
+6. Choose _Show Client ID_ and _Client Secret_ to show the client ID and secret. You will need them for the next section in the CLI flow. 
+
+#### [Sign in with Apple]
+
+1. [Sign In](https://developer.apple.com/account/) with your Apple developer credentials.
+2. On the main developer portal page, select _Certificates, IDs, & Profiles_.
+3. On the left navigation bar, select _Identifier_.
+4. On the _Identifiers_ page, select the _plus icon (+)_.
+5. On the _Register a New Identifier_ page, select _App IDs_.
+6. On the _Register an App ID_ page, under _App ID Prefix_, take note of the _Team ID_ value.
+7. Provide a description in the _Description_ text box and provide the `bundleID` of the iOS app. 
+8. Under _Capabilities_, select _Sign in with Apple_.
+9. Select _Continue_, review the configuration, and then select _Register_.
+10. On the _Identifiers_ page, on the right, select _App IDs_, and then select _Services ID_.
+11. Select the _plus icon (+)_ and, on the _Register a New Identifier_ page, select _Services IDs_.
+12. Provide a description in the _Description_ text box and provide an identifier for the Service ID. 
+13. Select _Continue_ and register the Service ID.
+
+Your developer accounts with the external providers are now set up and you can return to the Amplify specific configuration.
+
+## Configure external sign-in backend
+
+In `amplify/auth/resource.ts` the external providers need to be added.
+
+The following is an example of how you would set up access to all of the external providers supported by Amplify Auth. Please note you will need to configure your `callbackUrls` and `logoutUrls` URLs for your application, which will inform your backend resources how to behave when initiating sign in and sign out operations in your app.
+
+
+
+Secrets must be created manually with [`ampx sandbox secret`](/[platform]/reference/cli-commands#npx-ampx-sandbox-secret) for use with cloud sandbox, or via the Amplify Console for branch environments.
+
+
+
+
+```ts title="amplify/auth/resource.ts"
+import { defineAuth, secret } from '@aws-amplify/backend';
+
+export const auth = defineAuth({
+ loginWith: {
+ email: true,
+ externalProviders: {
+ google: {
+ clientId: secret('GOOGLE_CLIENT_ID'),
+ clientSecret: secret('GOOGLE_CLIENT_SECRET')
+ },
+ signInWithApple: {
+ clientId: secret('SIWA_CLIENT_ID'),
+ keyId: secret('SIWA_KEY_ID'),
+ privateKey: secret('SIWA_PRIVATE_KEY'),
+ teamId: secret('SIWA_TEAM_ID')
+ },
+ loginWithAmazon: {
+ clientId: secret('LOGINWITHAMAZON_CLIENT_ID'),
+ clientSecret: secret('LOGINWITHAMAZON_CLIENT_SECRET')
+ },
+ facebook: {
+ clientId: secret('FACEBOOK_CLIENT_ID'),
+ clientSecret: secret('FACEBOOK_CLIENT_SECRET')
+ },
+ callbackUrls: [
+ 'http://localhost:3000/profile',
+ 'https://mywebsite.com/profile'
+ ],
+ logoutUrls: ['http://localhost:3000/', 'https://mywebsite.com'],
+ }
+ }
+});
+```
+
+
+```ts title="amplify/auth/resource.ts"
+import { defineAuth, secret } from '@aws-amplify/backend';
+
+export const auth = defineAuth({
+ loginWith: {
+ email: true,
+ externalProviders: {
+ google: {
+ clientId: secret('GOOGLE_CLIENT_ID'),
+ clientSecret: secret('GOOGLE_CLIENT_SECRET')
+ },
+ signInWithApple: {
+ clientId: secret('SIWA_CLIENT_ID'),
+ keyId: secret('SIWA_KEY_ID'),
+ privateKey: secret('SIWA_PRIVATE_KEY'),
+ teamId: secret('SIWA_TEAM_ID')
+ },
+ loginWithAmazon: {
+ clientId: secret('LOGINWITHAMAZON_CLIENT_ID'),
+ clientSecret: secret('LOGINWITHAMAZON_CLIENT_SECRET')
+ },
+ facebook: {
+ clientId: secret('FACEBOOK_CLIENT_ID'),
+ clientSecret: secret('FACEBOOK_CLIENT_SECRET')
+ },
+ callbackUrls: ["myapp://callback/"],
+ logoutUrls: ["myapp://signout/"],
+ }
+ }
+});
+```
+
+
+You need to now inform your external provider of the newly configured authentication resource and its OAuth redirect URI:
+
+#### [Facebook Login]
+
+1. [Sign In](https://developers.facebook.com/) to your Facebook developer account with your Facebook credentials.
+2. Choose _My Apps_ from the top navigation bar, and on the _Apps_ page, choose your app you created before.
+3. On the left navigation bar, choose _Products_. Add _Facebook Login_ if it isn't already added.
+4. If already added, choose _Settings_ under the _Configure_ dropdown. 
+5. Under _Valid OAuth Redirect URIs_ type your user pool domain with the `/oauth2/idpresponse` endpoint.
+
+ `https:///oauth2/idpresponse`
+
+
+
+6. Save your changes.
+
+#### [Google Sign-In]
+
+1. Go to the [Google developer console](https://console.developers.google.com).
+2. On the left navigation bar, look for _APIs and Services_ under _Pinned_ or under _More Products_ if not pinned.
+3. Within the _APIs and Services_ sub menu, choose _Credentials_.
+4. Select the client you created in the first step and click the _Edit_ button.
+5. Type your user pool domain into the _Authorized JavaScript origins_ form.
+6. Type your user pool domain with the `/oauth2/idpresponse` endpoint into _Authorized Redirect URIs_.
+
+ 
+
+ Note: If you saw an error message `Invalid Redirect: domain must be added to the authorized domains list before submitting.` when adding the endpoint, please go to the _Authorized Domains List_ and add the domain.
+
+7. Click _Save_.
+
+#### [Login with Amazon]
+
+1. [Sign in](https://developer.amazon.com/loginwithamazon/console/site/lwa/overview.html) with your Amazon credentials.
+2. Hover over the gear and choose _Web Settings_ associated with the security profile you created in the previous step, and then choose _Edit_. 
+3. Type your user pool domain into _Allowed Origins_ and type your user pool domain with the `/oauth2/idpresponse` endpoint into _Allowed Return URLs_. 
+4. Choose _Save_.
+
+#### [Sign in with Apple]
+
+1. [Sign In](https://developer.apple.com/account/) with your Apple developer credentials.
+2. On the main developer portal page, select _Certificates, IDs, & Profiles_.
+3. On the left navigation bar, select _Identifiers_ and then select _Service IDs_ from the drop down list on the right.
+4. Select the Service ID created when you set up your auth provider as outlined in the section above.
+5. Enable _Sign In with Apple_ and select _Configure_.
+6. Under _Primary App ID_ select the App ID that was created before.
+7. Type your user pool domain into _Domains and Subdomains_.
+8. Type your user pool domain with the `/oauth2/idpresponse` endpoint into _Return URLs_. 
+9. Click _Next_, review the information, then select _Done_.
+10. On _Edit your Services ID Configuration_ click _Continue_, review the information, then select _Save_.
+11. On the main _Certificates, Identifiers & Profiles_, select _Keys_.
+12. On the _Keys_ page, select the _plus icon (+)_.
+13. Provide a name for the key under _Key Name_.
+14. Enable _Sign in with Apple_ and select _Configure_. 
+15. Under _Primary App ID_ select the App ID that was created before.
+16. Click on _Save_.
+17. On _Register a New Key_ click _Continue_, review the information, then select _Register_.
+18. You will be redirected to a new page. Take note of the _Key ID_ and download the .p8 file containing the private key. 
+
+[Learn more about using social identity providers with user pool](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-social-idp.html)
+
+### Customizing scopes for retrieving user data from external providers
+
+You can determine the pieces of data you want to retrieve from each external provider when setting them up in the `amplify/auth/resource.ts` file using `scopes`.
+
+
+```ts title="amplify/auth/resource.ts"
+import { defineAuth } from '@aws-amplify/backend';
+
+export const auth = defineAuth({
+ loginWith: {
+ email: true,
+ externalProviders: {
+ loginWithAmazon: {
+ clientId: secret('LOGINWITHAMAZON_CLIENT_ID'),
+ clientSecret: secret('LOGINWITHAMAZON_CLIENT_SECRET'),
+ // highlight-next-line
+ scopes: ['profile']
+ },
+ callbackUrls: [
+ 'http://localhost:3000/profile',
+ 'https://mywebsite.com/profile'
+ ],
+ logoutUrls: ['http://localhost:3000/', 'https://mywebsite.com'],
+ }
+ }
+});
+```
+
+
+```ts title="amplify/auth/resource.ts"
+import { defineAuth } from '@aws-amplify/backend';
+
+export const auth = defineAuth({
+ loginWith: {
+ email: true,
+ externalProviders: {
+ loginWithAmazon: {
+ clientId: secret('LOGINWITHAMAZON_CLIENT_ID'),
+ clientSecret: secret('LOGINWITHAMAZON_CLIENT_SECRET'),
+ // highlight-next-line
+ scopes: ['email']
+ },
+ callbackUrls: ["myapp://callback/"],
+ logoutUrls: ["myapp://signout/"],
+ }
+ }
+});
+```
+
+
+### Attribute mapping
+
+Identity provider (IdP) services store user attributes in different formats. When using external IdPs with Amazon Cognito user pools, attribute mapping allows you to standardize these varying formats into a consistent schema.
+
+Learn more about [mapping IdP attributes to user pool profiles and tokens](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-specifying-attribute-mapping.html).
+
+> **Warning:** **Note:** When a federated user signs in to your application, a mapping must be present for each attribute that your user pool requires. Additionally, you must also ensure that the target of each attribute mapping is mutable. Amazon Cognito will attempt to update each mapped attribute when a user signs in regardless of whether the latest value already matches the existing information. If these criteria are not met, Amazon Cognito will return an error and the sign in attempt will fail.
+
+
+```ts title="amplify/auth/resource.ts"
+import { defineAuth } from '@aws-amplify/backend';
+
+export const auth = defineAuth({
+ loginWith: {
+ email: true,
+ externalProviders: {
+ loginWithAmazon: {
+ clientId: secret('LOGINWITHAMAZON_CLIENT_ID'),
+ clientSecret: secret('LOGINWITHAMAZON_CLIENT_SECRET'),
+ // highlight-start
+ attributeMapping: {
+ email: 'email'
+ }
+ // highlight-end
+ },
+ callbackUrls: [
+ 'http://localhost:3000/profile',
+ 'https://mywebsite.com/profile'
+ ],
+ logoutUrls: ['http://localhost:3000/', 'https://mywebsite.com'],
+ }
+ }
+});
+```
+
+
+```ts title="amplify/auth/resource.ts"
+import { defineAuth } from '@aws-amplify/backend';
+
+export const auth = defineAuth({
+ loginWith: {
+ email: true,
+ externalProviders: {
+ loginWithAmazon: {
+ clientId: secret('LOGINWITHAMAZON_CLIENT_ID'),
+ clientSecret: secret('LOGINWITHAMAZON_CLIENT_SECRET'),
+ // highlight-start
+ attributeMapping: {
+ email: 'email'
+ }
+ // highlight-end
+ },
+ callbackUrls: ["myapp://callback/"],
+ logoutUrls: ["myapp://signout/"],
+ }
+ }
+});
+```
+
+
+
+[Learn more about configuring the React Authenticator component for external providers](https://ui.docs.amplify.aws/react/connected-components/authenticator/configuration#external-providers)
+
+
+## Configure OIDC provider
+
+To setup a OIDC provider, you can configure them in your `amplify/auth/resource.ts` file. For example, if you would like to setup a Microsoft EntraID provider, you can do so as follows:
+
+
+```ts title="amplify/auth/resource.ts"
+import { defineAuth, secret } from '@aws-amplify/backend';
+
+export const auth = defineAuth({
+ loginWith: {
+ email: true,
+ externalProviders: {
+ oidc: [
+ {
+ name: 'MicrosoftEntraID',
+ clientId: secret('MICROSOFT_ENTRA_ID_CLIENT_ID'),
+ clientSecret: secret('MICROSOFT_ENTRA_ID_CLIENT_SECRET'),
+ issuerUrl: '',
+ },
+ ],
+ logoutUrls: ['http://localhost:3000/', 'https://mywebsite.com'],
+ callbackUrls: [
+ 'http://localhost:3000/profile',
+ 'https://mywebsite.com/profile',
+ ],
+ },
+ },
+});
+```
+
+
+```ts title="amplify/auth/resource.ts"
+import { defineAuth, secret } from '@aws-amplify/backend';
+
+export const auth = defineAuth({
+ loginWith: {
+ email: true,
+ externalProviders: {
+ oidc: [
+ {
+ name: 'MicrosoftEntraID',
+ clientId: secret('MICROSOFT_ENTRA_ID_CLIENT_ID'),
+ clientSecret: secret('MICROSOFT_ENTRA_ID_CLIENT_SECRET'),
+ issuerUrl: '',
+ },
+ ],
+ callbackUrls: ["myapp://callback/"],
+ logoutUrls: ["myapp://signout/"],
+ },
+ },
+});
+```
+
+
+
+Use the `signInWithRedirect` API to initiate sign-in with an OIDC identity provider.
+
+```ts title="src/my-client-side-js.js"
+import { signInWithRedirect } from 'aws-amplify/auth';
+
+await signInWithRedirect({
+ provider: {
+ custom: 'MicrosoftEntraID'
+ }
+});
+```
+
+
+## Configure SAML provider
+
+To setup a SAML provider, you can configure them in your `amplify/auth/resource.ts` file. For example, if you would like to setup a Microsoft EntraID provider, you can do so as follows:
+
+
+```ts title="amplify/auth/resource.ts"
+import { defineAuth } from '@aws-amplify/backend';
+
+export const auth = defineAuth({
+ loginWith: {
+ email: true,
+ externalProviders: {
+ saml: {
+ name: 'MicrosoftEntraIDSAML',
+ metadata: {
+ metadataContent: '', // or content of the metadata file
+ metadataType: 'URL', // or 'FILE'
+ },
+ },
+ logoutUrls: ['http://localhost:3000/', 'https://mywebsite.com'],
+ callbackUrls: [
+ 'http://localhost:3000/profile',
+ 'https://mywebsite.com/profile',
+ ],
+ },
+ },
+});
+```
+
+
+```ts title="amplify/auth/resource.ts"
+import { defineAuth } from '@aws-amplify/backend';
+
+export const auth = defineAuth({
+ loginWith: {
+ email: true,
+ externalProviders: {
+ saml: {
+ name: 'MicrosoftEntraIDSAML',
+ metadata: {
+ metadataContent: '', // or content of the metadata file
+ metadataType: 'URL', // or 'FILE'
+ },
+ },
+ callbackUrls: ["myapp://callback/"],
+ logoutUrls: ["myapp://signout/"],
+ },
+ },
+});
+```
+
+
+
+Use the `signInWithRedirect` API to initiate sign-in with a SAML identity provider.
+
+```ts title="src/my-client-side-js.js"
+import { signInWithRedirect } from 'aws-amplify/auth';
+
+await signInWithRedirect({
+ provider: {
+ custom: 'MicrosoftEntraIDSAML'
+ }
+});
+```
+
+
+
+
+## Set up your frontend
+
+> **Info:** If you are using the [Authenticator component](https://ui.docs.amplify.aws/react/connected-components/authenticator/configuration#external-providers) with Amplify, this feature works without any additional code. The guide below is for writing your own implementation.
+
+Use the `signInWithRedirect` API to initiate sign-in with an external identity provider.
+
+```ts title="src/my-client-side-js.js"
+import { signInWithRedirect } from 'aws-amplify/auth';
+
+await signInWithRedirect({
+ provider: 'Apple'
+});
+```
+
+### Redirect URLs
+
+_Sign in_ & _Sign out_ redirect URL(s) are used to redirect end users after the sign in or sign out operation has occurred. You may want to specify multiple URLs for various use-cases such as having different URLs for development/ production or redirect users to an intermediate URL before returning them to the app.
+
+#### Specifying a redirect URL on sign out
+If you have multiple sign out redirect URLs configured, you may choose to override the default behavior of selecting a redirect URL and provide the one of your choosing when calling `signOut`. The provided redirect URL should match at least one of the configured redirect URLs. If no redirect URL is provided to `signOut`, one will be selected based on the current app domain.
+
+```ts
+import { Amplify } from 'aws-amplify';
+import { signOut } from 'aws-amplify/auth';
+
+// Assuming the following URLS were provided manually or via the Amplify configuration file,
+// redirectSignOut: 'http://localhost:3000/,https://authProvider/logout?logout_uri=https://mywebsite.com/'
+
+signOut({
+ global: false,
+ oauth: {
+ redirectUrl: 'https://authProvider/logout?logout_uri=https://mywebsite.com/'
+ }
+});
+
+```
+
+
+### (Required for Multi-Page Applications) Complete external Sign In after Redirect
+
+If you are developing a multi-page application, and the redirected page is not the same page that initiated the sign in, you will need to add the following code to the redirected page to ensure the sign in gets completed:
+
+```ts title="src/my-redirected-page.ts"
+import 'aws-amplify/auth/enable-oauth-listener';
+import { getCurrentUser, fetchUserAttributes } from 'aws-amplify/auth';
+import { Hub } from 'aws-amplify/utils';
+
+Hub.listen("auth", async ({ payload }) => {
+ switch (payload.event) {
+ case "signInWithRedirect":
+ const user = await getCurrentUser();
+ const userAttributes = await fetchUserAttributes();
+ console.log({user, userAttributes});
+ break;
+ case "signInWithRedirect_failure":
+ // handle sign in failure
+ break;
+ case "customOAuthState":
+ const state = payload.data; // this will be customState provided on signInWithRedirect function
+ console.log(state);
+ break;
+ }
+});
+```
+
+
+
+**Note:** The listener only works on the client side in the context of a SSR-enabled project, so ensure to import the listener on the client side only. For example, in a Next.js project, you should add the above import statement to a component that renders on the client side only by `'use client'`.
+
+
+
+
+
+When you import and use the `signInWithRedirect` function, it will add a listener as a side effect that will complete the external sign in when an end user is redirected back to your app. This works well in a single-page application but in a multi-page application, you might get redirected to a page that doesn't include the listener that was originally added as a side-effect. Hence you must include the specific OAuth listener on your login success page.
+
+
+
+
+
+## Set up your frontend
+
+> **Info:** If you are using the [Authenticator component](https://ui.docs.amplify.aws/react/connected-components/authenticator/configuration#external-providers) with Amplify, this feature works without any additional code. The guide below is for writing your own implementation.
+
+Use the `signInWithRedirect` API to initiate sign-in with an external identity provider.
+
+```ts title="src/my-client-side-js.js"
+import { signInWithRedirect } from 'aws-amplify/auth';
+
+signInWithRedirect({
+ provider: 'Apple'
+});
+```
+
+### Redirect URLs
+
+_Sign in_ & _Sign out_ redirect URL(s) are used to redirect end users after the sign in or sign out operation has occurred. You may want to specify multiple URLs for various use-cases such as having different URLs for development/ production or redirect users to an intermediate URL before returning them to the app.
+
+#### Specifying a redirect URL on sign out
+If you have multiple sign out redirect URLs configured, you may choose to override the default behavior of selecting a redirect URL and provide the one of your choosing when calling `signOut`. The provided redirect URL should match at least one of the configured redirect URLs. If no redirect URL is provided to `signOut`, the first item from the the configured redirect URLs list that does not contain a HTTP nor HTTPS prefix will be picked.
+
+```ts
+import { signOut } from 'aws-amplify/auth';
+
+// Assuming the following URLS were provided manually or via the Amplify configuration file,
+// redirectSignOut: 'myDevApp://,https://authProvider/logout?logout_uri=myDevApp://'
+
+signOut({
+ global: false,
+ oauth: {
+ redirectUrl: 'https://authProvider/logout?logout_uri=myapp://'
+ }
+});
+```
+ Irrespective of whether a `redirectUrl` is provided to `signOut`, a URL that does not contain http or https is expected to be present in the configured redirect URL list. This is because iOS requires an appScheme when creating the web session.
+
+
+## Next steps
+
+- [Learn how to sign in with external providers](/[platform]/build-a-backend/auth/connect-your-frontend/sign-in/#sign-in-with-an-external-identity-provider)
+
+---
+
+---
+title: "Guest access"
+section: "build-a-backend/auth/concepts"
+platforms: ["javascript", "react-native", "flutter", "swift", "android", "angular", "nextjs", "react", "vue"]
+gen: 2
+last-updated: "2024-05-02T22:35:36.000Z"
+url: "https://docs.amplify.aws/react/build-a-backend/auth/concepts/guest-access/"
+---
+
+
+The Auth Plugin can be configured to automatically obtain guest credentials once the device is online so that you are able to use other categories "anonymously" without the need to sign in. You will not be able to perform user specific methods while in this state such as updating attributes, changing your password, or getting the current user. However, you can obtain the unique Identity ID which is assigned to the device through the `fetchAuthSession` method [described here](/[platform]/build-a-backend/auth/concepts/tokens-and-credentials/).
+
+
+Amplify Auth can be configured to automatically obtain guest credentials once the device is online so that you are able to use other categories "anonymously" without the need to sign in. You will not be able to perform user specific methods while in this state such as updating attributes, changing your password, or getting the current user. However, you can obtain the unique Identity ID which is assigned to the device through the `fetchAuthSession` method [described here](/[platform]/build-a-backend/auth/connect-your-frontend/manage-user-sessions/).
+
+
+Amplify Gen 2 enables guest access by default. To disable it, you can update the `backend.ts` file with the following changes:
+
+```ts title="amplify/backend.ts"
+import { defineBackend } from '@aws-amplify/backend'
+import { auth } from './auth/resource'
+import { data } from './data/resource'
+
+const backend = defineBackend({
+ auth,
+ data,
+});
+
+// highlight-start
+const { cfnIdentityPool } = backend.auth.resources.cfnResources;
+cfnIdentityPool.allowUnauthenticatedIdentities = false;
+// highlight-end
+```
+
+---
+
+---
+title: "Tokens and credentials"
+section: "build-a-backend/auth/concepts"
+platforms: ["android", "angular", "flutter", "javascript", "nextjs", "react", "react-native", "swift", "vue"]
+gen: 2
+last-updated: "2024-10-18T22:41:29.000Z"
+url: "https://docs.amplify.aws/react/build-a-backend/auth/concepts/tokens-and-credentials/"
+---
+
+Amplify Auth interacts with its underlying [Amazon Cognito user pool](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-identity-pools.html) as an OpenID Connect (OIDC) provider. When users successfully authenticate you receive OIDC-compliant JSON web tokens (JWT). These tokens are used to _identity_ your user, and _access_ resources.
+
+[**Access tokens**](https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-the-access-token.html) are used to verify the bearer of the token (i.e. the Cognito user) is authorized to perform an action against a resource. Below is an example payload of an access token vended by Cognito:
+
+```json
+{
+ "sub": "54288468-e051-706d-a73f-03892273d7e9",
+ "iss": "https://cognito-idp.us-east-1.amazonaws.com/us-east-1_yoKn9s4Tq",
+ "client_id": "1sg675g08g6g0e9f64grv9n5sk",
+ "origin_jti": "0eadb994-a6e0-419e-b309-a7a0d522d72f",
+ "event_id": "b180897a-181c-4f73-94bb-a2946e8b4ef1",
+ "token_use": "access",
+ "scope": "aws.cognito.signin.user.admin",
+ "auth_time": 1714241873,
+ "exp": 1714245473,
+ "iat": 1714241873,
+ "jti": "57f10a4d-a1f2-453b-8672-d1cfa8187047",
+ "username": "54288468-e051-706d-a73f-03892273d7e9"
+}
+```
+
+[**ID tokens**](https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-the-id-token.html) are intended to be used within your frontend application only. This token contains personally identifiable information (PII) and should not be used to authorize access against a resource. Below is an example of an ID token with the default Amplify Auth configuration of email and password auth.
+
+```json
+{
+ "sub": "54288468-e051-706d-a73f-03892273d7e9",
+ "email_verified": true,
+ "iss": "https://cognito-idp.us-east-1.amazonaws.com/us-east-1_yoKn9s4Tq",
+ "cognito:username": "54288468-e051-706d-a73f-03892273d7e9",
+ "origin_jti": "0eadb994-a6e0-419e-b309-a7a0d522d72f",
+ "aud": "1sg675g08g6g0e9f64grv9n5sk",
+ "event_id": "b180897a-181c-4f73-94bb-a2946e8b4ef1",
+ "token_use": "id",
+ "auth_time": 1714241873,
+ "exp": 1714245473,
+ "iat": 1714241873,
+ "jti": "bb69af10-3ce0-47c2-8d8d-5bdc8630ab58",
+ "email": "hello@mycompany.com"
+}
+```
+
+When additional user attributes are specified for Amplify Auth, their values will be found in the ID token. For example, if a `nickname` attribute is requested it will be available on the ID token with the `nickname` claim:
+
+```diff
+{
+ "sub": "54288468-e051-706d-a73f-03892273d7e9",
+ "email_verified": true,
+ "iss": "https://cognito-idp.us-east-1.amazonaws.com/us-east-1_yoKn9s4Tq",
+ "cognito:username": "54288468-e051-706d-a73f-03892273d7e9",
+ "origin_jti": "0eadb994-a6e0-419e-b309-a7a0d522d72f",
+ "aud": "1sg675g08g6g0e9f64grv9n5sk",
+ "event_id": "b180897a-181c-4f73-94bb-a2946e8b4ef1",
+ "token_use": "id",
+ "auth_time": 1714241873,
++ "nickname": "hello",
+ "exp": 1714245473,
+ "iat": 1714241873,
+ "jti": "bb69af10-3ce0-47c2-8d8d-5bdc8630ab58",
+ "email": "hello@mycompany.com"
+}
+```
+
+Conversely, user pool group claims are found in both the access token and ID token on the `cognito:groups` claim:
+
+```json
+{
+ "sub": "54288468-e051-706d-a73f-03892273d7e9",
+ "email_verified": true,
+ "iss": "https://cognito-idp.us-east-1.amazonaws.com/us-east-1_yoKn9s4Tq",
+ "cognito:username": "54288468-e051-706d-a73f-03892273d7e9",
+ "cognito:groups": ["ADMINS"],
+ "origin_jti": "0eadb994-a6e0-419e-b309-a7a0d522d72f",
+ "aud": "1sg675g08g6g0e9f64grv9n5sk",
+ "event_id": "b180897a-181c-4f73-94bb-a2946e8b4ef1",
+ "token_use": "id",
+ "auth_time": 1714241873,
+ "nickname": "hello",
+ "exp": 1714245473,
+ "iat": 1714241873,
+ "jti": "bb69af10-3ce0-47c2-8d8d-5bdc8630ab58",
+ "email": "hello@mycompany.com"
+}
+```
+
+Visit the [AWS documentation for using tokens with Cognito user pools](https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-tokens-with-identity-providers.html) to learn more about tokens, how they're used with Cognito, and their intended usage.
+
+
+## Understand token management options
+
+Token keys are automatically rotated for you for added security but you can update how they are stored, customize the refresh rate and expiration times, and revoke tokens on sign-out.
+
+### Update your token-saving mechanism
+
+You can update the storage mechanism to choose where and how tokens are persisted in your application. The default option is `localStorage`. Additionally, you can import the `sessionStorage`, `sharedInMemoryStorage` or `CookieStorage` options as well.
+
+If you want to customize your own mechanism, you can import the `KeyValueStorageInterface` interface and implement it in your own class.
+
+#### Browser Local Storage
+
+In Amplify the `localStorage` is the default storage mechanism. It saves the tokens in the browser's `localStorage`. This local storage will persist across browser sessions and tabs. You can explicitly set to this storage by calling:
+
+```ts
+import { cognitoUserPoolsTokenProvider } from 'aws-amplify/auth/cognito';
+import { defaultStorage } from 'aws-amplify/utils';
+
+cognitoUserPoolsTokenProvider.setKeyValueStorage(defaultStorage);
+```
+
+#### Cookie Storage
+
+`CookieStorage` saves the tokens in the browser's `Cookies`. The cookies will persist across browser sessions and tabs. You can explicitly set to this storage by calling:
+
+```ts
+import { cognitoUserPoolsTokenProvider } from 'aws-amplify/auth/cognito';
+import { CookieStorage } from 'aws-amplify/utils';
+
+cognitoUserPoolsTokenProvider.setKeyValueStorage(new CookieStorage());
+```
+
+#### Browser Session Storage
+
+`sessionStorage` saves the tokens in the browser's `sessionStorage` and these tokens will clear when a tab is closed. The benefit to this storage mechanism is that the session only lasts as long as the browser is open and you can sign out users when they close the tab. You can update to this storage by calling:
+
+```ts
+import { cognitoUserPoolsTokenProvider } from 'aws-amplify/auth/cognito';
+import { sessionStorage } from 'aws-amplify/utils';
+
+cognitoUserPoolsTokenProvider.setKeyValueStorage(sessionStorage);
+```
+
+#### Custom Storage
+
+You can implement your own custom storage mechanism by creating a class that implements the storage interface. Here is an example that uses memory storage:
+
+```ts
+import { cognitoUserPoolsTokenProvider } from 'aws-amplify/auth/cognito';
+import { KeyValueStorageInterface } from 'aws-amplify/utils';
+
+class MyCustomStorage implements KeyValueStorageInterface {
+ storageObject: Record = {};
+ async setItem(key: string, value: string): Promise {
+ this.storageObject[key] = value;
+ }
+ async getItem(key: string): Promise {
+ return this.storageObject[key];
+ }
+ async removeItem(key: string): Promise {
+ delete this.storageObject[key];
+ }
+ async clear(): Promise {
+ this.storageObject = {};
+ }
+}
+
+cognitoUserPoolsTokenProvider.setKeyValueStorage(new MyCustomStorage());
+```
+
+When you get the current user session, the tokens will be saved in your custom location.
+
+
+Amplify Auth persists authentication-related information to make it available to other Amplify categories and to your application.
+
+Amplify Flutter securely manages credentials and user identity information. You do not need to store, refresh, or delete credentials yourself. Amplify Flutter stores auth data on the device using platform capabilities such as [Keychain Services](https://developer.apple.com/documentation/security/keychain_services/) on iOS and macOS and [EncryptedSharedPreferences](https://developer.android.com/reference/androidx/security/crypto/EncryptedSharedPreferences) on Android.
+
+> **Info:** Amplify will refresh the [access token](https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-the-access-token.html) and [ID token](https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-the-id-token.html) as long as the [refresh token](https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-the-refresh-token.html) is valid. Once the refresh token expires, the user will need to reauthenticate to obtain a new one.
+
+Some platform specific option can be customized with the out of the box options. In the example below, credentials will be stored in-memory on Web instead of the default behavior of using browser storage.
+
+```dart
+await Amplify.addPlugin(
+ AmplifyAuthCognito(
+ secureStorageFactory: AmplifySecureStorage.factoryFrom(
+ webOptions: WebSecureStorageOptions(
+ persistenceOption: WebPersistenceOption.inMemory,
+ ),
+ ),
+ ),
+);
+```
+
+If you would like further customization, you can provide your own factory for creating `SecureStorageInterface` instances to `AmplifyAuthCognito`. The example below shows the use of a custom implementation that stores data in-memory on all platforms.
+
+```dart
+await Amplify.addPlugin(
+ AmplifyAuthCognito(secureStorageFactory: InMemoryStorage.new),
+);
+```
+
+```dart
+class InMemoryStorage implements SecureStorageInterface {
+ InMemoryStorage(this.scope);
+
+ /// The scope of the item being stored.
+ ///
+ /// This can be used as a namespace for stored items.
+ final AmplifySecureStorageScope scope;
+
+ static final Map _data = {};
+
+ @override
+ void write({required String key, required String value}) {
+ _data['${scope.name}.$key'] = value;
+ }
+
+ @override
+ String? read({required String key}) {
+ return _data['${scope.name}.$key'];
+ }
+
+ @override
+ void delete({required String key}) {
+ _data.remove('${scope.name}.$key');
+ }
+}
+```
+
+
+## Token Revocation
+
+
+Token revocation is enabled automatically in Amplify Auth. To revoke tokens you can set up global sign-out with `signOut({ global: true })` to globally sign out your user from all of their devices.
+
+
+Token revocation is enabled automatically in Amplify Auth. To revoke tokens you can invoke `await Amplify.Auth.signOut(options: const signOutOptions(globalSignOut: true))` to globally sign out your user from all of their devices.
+
+
+Token revocation is enabled automatically in Amplify Auth. To revoke tokens you can invoke `await Amplify.Auth.signOut(options: .init(globalSignOut: true))` to globally sign out your user from all of their devices.
+
+
+## Next steps
+
+
+- [Learn how to customize the ID token](/[platform]/build-a-backend/functions/examples/override-token/)
+- [Learn how to bring your own tokens from external providers](/[platform]/build-a-backend/auth/advanced-workflows/#custom-token-providers)
+- [Learn how to use cookie storage server-side](/[platform]/build-a-backend/server-side-rendering/#configure-amplify-library-for-client-side-usage)
+
+
+- [Learn how to customize the ID token](/[platform]/build-a-backend/functions/examples/override-token/)
+- [Learn how to bring your own tokens from external providers](/[platform]/build-a-backend/auth/advanced-workflows/#custom-token-providers)
+
+
+---
+
+---
+title: "Connect your frontend"
+section: "build-a-backend/auth"
+platforms: ["android", "angular", "flutter", "javascript", "nextjs", "react", "react-native", "swift", "vue"]
+gen: 2
+last-updated: "2024-05-01T21:35:13.000Z"
+url: "https://docs.amplify.aws/react/build-a-backend/auth/connect-your-frontend/"
+---
+
+
+
+---
+
+---
+title: "Using the Authenticator"
+section: "build-a-backend/auth/connect-your-frontend"
+platforms: ["android", "angular", "flutter", "javascript", "nextjs", "react", "react-native", "swift", "vue"]
+gen: 2
+last-updated: "2024-05-17T17:18:27.000Z"
+url: "https://docs.amplify.aws/react/build-a-backend/auth/connect-your-frontend/using-the-authenticator/"
+---
+
+
+The quickest way to get started with Amplify Auth in your frontend application is with the [Authenticator component](https://ui.docs.amplify.aws/swift/connected-components/authenticator), which provides a customizable UI and complete authentication flows.
+
+```swift
+import Amplify
+import Authenticator
+import AWSCognitoAuthPlugin
+import SwiftUI
+
+@main
+struct MyApp: App {
+ init() {
+ do {
+ try Amplify.add(plugin: AWSCognitoAuthPlugin())
+ try Amplify.configure(with: .amplifyOutputs)
+ } catch {
+ print("Unable to configure Amplify \(error)")
+ }
+ }
+
+ var body: some Scene {
+ WindowGroup {
+ Authenticator { state in
+ VStack {
+ Text("Hello, \(state.user.username)")
+ Button("Sign out") {
+ Task {
+ await state.signOut()
+ }
+ }
+ }
+ }
+ }
+ }
+}
+```
+
+
+
+The quickest way to get started with Amplify Auth in your frontend application is with the [Authenticator component](https://ui.docs.amplify.aws/flutter/connected-components/authenticator), which provides a customizable UI and complete authentication flows.
+
+
+
+The quickest way to get started with Amplify Auth in your frontend application is with the [Authenticator component](https://ui.docs.amplify.aws/android/connected-components/authenticator), which provides a customizable UI and complete authentication flows.
+
+
+
+The quickest way to get started with Amplify Auth in your frontend application is with the [Authenticator component](https://ui.docs.amplify.aws/react/connected-components/authenticator), which provides a customizable UI and complete authentication flows.
+
+```tsx title="src/App.tsx"
+import { Authenticator } from '@aws-amplify/ui-react';
+import { Amplify } from 'aws-amplify';
+import '@aws-amplify/ui-react/styles.css';
+import outputs from "../amplify_outputs.json";
+
+Amplify.configure(outputs);
+
+export default function App() {
+ return (
+
+ {({ signOut, user }) => (
+
+
Hello {user?.username}
+ Sign out
+
+ )}
+
+ );
+}
+```
+
+
+The Authenticator component is automatically configured based on the outputs generated from your backend. To learn more about the Authenticator and how to customize its appearance, visit the [Amplify UI documentation](https://ui.docs.amplify.aws/).
+
+
+Conversely, you can bring your own UI and leverage the library from [`aws-amplify`](https://www.npmjs.com/package/aws-amplify) to handle authentication flows manually.
+
+
+---
+
+---
+title: "Sign-up"
+section: "build-a-backend/auth/connect-your-frontend"
+platforms: ["android", "angular", "flutter", "javascript", "nextjs", "react", "react-native", "swift", "vue"]
+gen: 2
+last-updated: "2024-12-09T19:54:14.000Z"
+url: "https://docs.amplify.aws/react/build-a-backend/auth/connect-your-frontend/sign-up/"
+---
+
+Amplify provides a client library that enables you to interact with backend resources such as Amplify Auth.
+
+
+> **Info:** The quickest way to get started with Amplify Auth in your frontend application is with the [Authenticator component](https://ui.docs.amplify.aws/react/connected-components/authenticator), which provides a customizable UI and complete authentication flows.
+
+
+
+> **Info:** The quickest way to get started with Amplify Auth in your frontend application is with the [Authenticator component](https://ui.docs.amplify.aws/swift/connected-components/authenticator), which provides a customizable UI and complete authentication flows.
+
+
+
+> **Info:** The quickest way to get started with Amplify Auth in your frontend application is with the [Authenticator component](https://ui.docs.amplify.aws/flutter/connected-components/authenticator), which provides a customizable UI and complete authentication flows.
+
+
+
+> **Info:** The quickest way to get started with Amplify Auth in your frontend application is with the [Authenticator component](https://ui.docs.amplify.aws/android/connected-components/authenticator), which provides a customizable UI and complete authentication flows.
+
+
+To get started, you can use the `signUp()` API to create a new user in your backend:
+
+
+```ts
+import { signUp } from "aws-amplify/auth"
+
+const { isSignUpComplete, userId, nextStep } = await signUp({
+ username: "hello@mycompany.com",
+ password: "hunter2",
+ options: {
+ userAttributes: {
+ email: "hello@mycompany.com",
+ phone_number: "+15555555555" // E.164 number convention
+ },
+ }
+});
+```
+
+
+```dart
+/// Signs a user up with a username, password, and email. The required
+/// attributes may be different depending on your app's configuration.
+Future signUpUser({
+ required String username,
+ required String password,
+ required String email,
+ String? phoneNumber,
+}) async {
+ try {
+ final userAttributes = {
+ AuthUserAttributeKey.email: email,
+ if (phoneNumber != null) AuthUserAttributeKey.phoneNumber: phoneNumber,
+ // additional attributes as needed
+ };
+ final result = await Amplify.Auth.signUp(
+ username: username,
+ password: password,
+ options: SignUpOptions(
+ userAttributes: userAttributes,
+ ),
+ );
+ await _handleSignUpResult(result);
+ } on AuthException catch (e) {
+ safePrint('Error signing up user: ${e.message}');
+ }
+}
+```
+
+```dart
+Future _handleSignUpResult(SignUpResult result) async {
+ switch (result.nextStep.signUpStep) {
+ case AuthSignUpStep.confirmSignUp:
+ final codeDeliveryDetails = result.nextStep.codeDeliveryDetails!;
+ _handleCodeDelivery(codeDeliveryDetails);
+ break;
+ case AuthSignUpStep.done:
+ safePrint('Sign up is complete');
+ break;
+ }
+}
+
+void _handleCodeDelivery(AuthCodeDeliveryDetails codeDeliveryDetails) {
+ safePrint(
+ 'A confirmation code has been sent to ${codeDeliveryDetails.destination}. '
+ 'Please check your ${codeDeliveryDetails.deliveryMedium.name} for the code.',
+ );
+}
+```
+
+
+
+#### [Java]
+
+```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 - Callbacks]
+
+```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 - Coroutines]
+
+```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)
+}
+```
+
+#### [RxJava]
+
+```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())
+ );
+```
+
+
+
+
+#### [Async/Await]
+
+```swift
+func signUp(username: String, password: String, email: String, phonenumber: String) async {
+ let userAttributes = [AuthUserAttribute(.email, value: email), AuthUserAttribute(.phoneNumber, value: phonenumber)]
+ let options = AuthSignUpRequest.Options(userAttributes: userAttributes)
+
+ do {
+ let signUpResult = try await Amplify.Auth.signUp(
+ username: username,
+ password: password,
+ options: options
+ )
+
+ 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)")
+ }
+}
+```
+
+#### [Combine]
+
+```swift
+func signUp(username: String, password: String, email: String, phonenumber: String) -> AnyCancellable {
+ let userAttributes = [
+ AuthUserAttribute(.email, value: email),
+ AuthUserAttribute(.phoneNumber, value: phonenumber)
+ ]
+ let options = AuthSignUpRequest.Options(userAttributes: userAttributes)
+ Amplify.Publisher.create {
+ try await Amplify.Auth.signUp(
+ username: username,
+ password: password,
+ options: options
+ )
+ }.sink {
+ if case let .failure(authError) = $0 {
+ print("An error occurred while registering a user \(authError)")
+ }
+ }
+ receiveValue: { signUpResult in
+ if case let .confirmUser(deliveryDetails, _, userId) = signUpResult.nextStep {
+ print("Delivery details \(String(describing: deliveryDetails)) for userId: \(String(describing: userId)))")
+ } else {
+ print("SignUp Complete")
+ }
+ }
+ return sink
+}
+```
+
+
+
+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:
+
+
+| 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. |
+
+
+
+| 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
+
+By default, each user that signs up remains in the unconfirmed status until they verify with a confirmation code that was sent to their email or phone number. The following are the default verification methods used when either `phone` or `email` are used as `loginWith` options.
+
+| Login option | User account verification channel |
+| ------------------- | --------------------------------- |
+| `phone` | Phone Number |
+| `email` | Email |
+| `email` and `phone` | Email |
+
+You can confirm the sign-up after receiving a confirmation code from the user:
+
+
+```ts
+import { confirmSignUp } from 'aws-amplify/auth';
+
+const { isSignUpComplete, nextStep } = await confirmSignUp({
+ username: "hello@mycompany.com",
+ confirmationCode: "123456"
+});
+```
+
+
+```dart
+Future confirmUser({
+ required String username,
+ required String confirmationCode,
+}) async {
+ try {
+ final result = await Amplify.Auth.confirmSignUp(
+ username: username,
+ confirmationCode: confirmationCode,
+ );
+ // Check if further confirmations are needed or if
+ // the sign up is complete.
+ await _handleSignUpResult(result);
+ } on AuthException catch (e) {
+ safePrint('Error confirming user: ${e.message}');
+ }
+}
+```
+
+
+
+#### [Java]
+
+```java
+Amplify.Auth.confirmSignUp(
+ "username",
+ "the code you received via email",
+ result -> Log.i("AuthQuickstart", result.isSignUpComplete() ? "Confirm signUp succeeded" : "Confirm sign up not complete"),
+ error -> Log.e("AuthQuickstart", error.toString())
+);
+```
+
+#### [Kotlin - Callbacks]
+
+```kotlin
+Amplify.Auth.confirmSignUp(
+ "username", "the code you received via email",
+ { result ->
+ if (result.isSignUpComplete) {
+ Log.i("AuthQuickstart", "Confirm signUp succeeded")
+ } else {
+ Log.i("AuthQuickstart","Confirm sign up not complete")
+ }
+ },
+ { Log.e("AuthQuickstart", "Failed to confirm sign up", it) }
+)
+```
+
+#### [Kotlin - Coroutines]
+
+```kotlin
+try {
+ val code = "code you received via email"
+ val result = Amplify.Auth.confirmSignUp("username", code)
+ if (result.isSignUpComplete) {
+ Log.i("AuthQuickstart", "Signup confirmed")
+ } else {
+ Log.i("AuthQuickstart", "Signup confirmation not yet complete")
+ }
+} catch (error: AuthException) {
+ Log.e("AuthQuickstart", "Failed to confirm signup", error)
+}
+```
+
+#### [RxJava]
+
+```java
+RxAmplify.Auth.confirmSignUp("username", "the code you received via email")
+ .subscribe(
+ result -> Log.i("AuthQuickstart", result.isSignUpComplete() ? "Confirm signUp succeeded" : "Confirm sign up not complete"),
+ error -> Log.e("AuthQuickstart", error.toString())
+ );
+```
+
+
+
+
+#### [Async/Await]
+
+```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)")
+ }
+}
+```
+
+#### [Combine]
+
+```swift
+func confirmSignUp(for username: String, with confirmationCode: String) -> AnyCancellable {
+ Amplify.Publisher.create {
+ try await Amplify.Auth.confirmSignUp(
+ for: username,
+ confirmationCode: confirmationCode
+ )
+ }.sink {
+ if case let .failure(authError) = $0 {
+ print("An error occurred while confirming sign up \(authError)")
+ }
+ }
+ receiveValue: { _ in
+ print("Confirm signUp succeeded")
+ }
+}
+```
+
+
+
+
+> **Info:** **Note:** When specifying `email` or `phone` as a way for your users to sign-in, these are attributes that are used in place of the username. Visit the [concepts page to learn more about usernames](/[platform]/build-a-backend/auth/concepts/).
+
+
+
+## Practical Example
+
+
+```tsx title="src/App.tsx"
+import type { FormEvent } from "react"
+import { Amplify } from "aws-amplify"
+// highlight-next-line
+import { signUp } from "aws-amplify/auth"
+import outputs from "../amplify_outputs.json"
+
+Amplify.configure(outputs)
+
+interface SignUpFormElements extends HTMLFormControlsCollection {
+ email: HTMLInputElement
+ password: HTMLInputElement
+}
+
+interface SignUpForm extends HTMLFormElement {
+ readonly elements: SignUpFormElements
+}
+
+export default function App() {
+ async function handleSubmit(event: FormEvent) {
+ event.preventDefault()
+ const form = event.currentTarget
+ // ... validate inputs
+ await signUp({
+ username: form.elements.email.value,
+ password: form.elements.password.value,
+ })
+ }
+
+ return (
+
+ )
+}
+```
+
+
+
+
+## Sign up with passwordless methods
+
+Your application's users can also sign up using passwordless methods. To learn more, visit the [concepts page for passwordless](/[platform]/build-a-backend/auth/concepts/passwordless/).
+
+### SMS OTP
+
+
+```typescript
+// Sign up using a phone number
+const { nextStep: signUpNextStep } = await signUp({
+ username: 'hello',
+ options: {
+ userAttributes: {
+ phone_number: '+15555551234',
+ },
+ },
+});
+
+if (signUpNextStep.signUpStep === 'DONE') {
+ console.log(`SignUp Complete`);
+}
+
+if (signUpNextStep.signUpStep === 'CONFIRM_SIGN_UP') {
+ console.log(
+ `Code Delivery Medium: ${signUpNextStep.codeDeliveryDetails.deliveryMedium}`,
+ );
+ console.log(
+ `Code Delivery Destination: ${signUpNextStep.codeDeliveryDetails.destination}`,
+ );
+}
+
+// Confirm sign up with the OTP received
+const { nextStep: confirmSignUpNextStep } = await confirmSignUp({
+ username: 'hello',
+ confirmationCode: '123456',
+});
+
+if (confirmSignUpNextStep.signUpStep === 'DONE') {
+ console.log(`SignUp Complete`);
+}
+```
+
+
+
+#### [Java]
+
+```java
+// Sign up using a phone number
+ArrayList attributes = new ArrayList<>();
+attributes.add(new AuthUserAttribute(AuthUserAttributeKey.phoneNumber(), "+15551234567"));
+
+Amplify.Auth.signUp(
+ "hello@example.com",
+ null,
+ AuthSignUpOptions.builder().userAttributes(attributes).build(),
+ result -> {
+ if (result.isSignUpComplete()) {
+ Log.i("AuthQuickstart", "Sign up is complete");
+ } else if (result.getNextStep().getSignUpStep() == AuthSignUpStep.CONFIRM_SIGN_UP_STEP) {
+ Log.i("AuthQuickstart", "Code Deliver Medium: " +
+ result.getNextStep().getCodeDeliveryDetails().getDeliveryMedium());
+ Log.i("AuthQuickstart", "Code Deliver Destination: " +
+ result.getNextStep().getCodeDeliveryDetails().getDestination());
+ }
+ },
+ error -> Log.e("AuthQuickstart", error.toString())
+);
+
+// Confirm sign up with the OTP received
+Amplify.Auth.confirmSignUp(
+ "hello@example.com",
+ "123456",
+ result -> {
+ if (result.isSignUpComplete()) {
+ Log.i("AuthQuickstart", "Sign up is complete");
+ }
+ },
+ error -> Log.e("AuthQuickstart", error.toString())
+);
+```
+
+#### [Kotlin - Callbacks]
+
+```kotlin
+// Sign up using a phone number
+val attributes = listOf(
+ AuthUserAttribute(AuthUserAttributeKey.phoneNumber(), "+15555551234")
+)
+val options =
+ AuthSignUpOptions
+ .builder()
+ .userAttributes(attributes)
+ .build()
+
+Amplify.Auth.signUp(
+ "hello@example.com",
+ null,
+ options,
+ { result ->
+ if (result.isSignUpComplete) {
+ Log.i("AuthQuickstart", "Sign up is complete")
+ } else if (result.nextStep.signUpStep == AuthSignUpStep.CONFIRM_SIGN_UP_STEP) {
+ Log.i("AuthQuickstart", "Code Deliver Medium: " +
+ "${result.nextStep.codeDeliveryDetails?.deliveryMedium}")
+ Log.i("AuthQuickstart", "Code Deliver Destination: " +
+ "${result.nextStep.codeDeliveryDetails?.destination}")
+ }
+ },
+ { Log.e("AuthQuickstart", "Failed to sign up", it) }
+)
+
+// Confirm sign up with the OTP received
+Amplify.Auth.confirmSignUp(
+ "hello@example.com",
+ "123456",
+ { result ->
+ if (result.nextStep.signUpStep == AuthSignUpStep.DONE) {
+ Log.i("AuthQuickstart", "Sign up is complete")
+ }
+ },
+ { Log.e("AuthQuickstart", "Failed to sign up", it) }
+)
+```
+
+#### [Kotlin - Coroutines]
+
+```kotlin
+// Sign up using a phone number
+val attributes = listOf(
+ AuthUserAttribute(AuthUserAttributeKey.phoneNumber(), "+15555551234")
+)
+val options =
+ AuthSignUpOptions
+ .builder()
+ .userAttributes(attributes)
+ .build()
+var result = Amplify.Auth.signUp("hello@example.com", null, options)
+
+if (result.isSignUpComplete) {
+ Log.i("AuthQuickstart", "Sign up is complete")
+} else if (result.nextStep.signUpStep == AuthSignUpStep.CONFIRM_SIGN_UP_STEP) {
+ Log.i("AuthQuickstart", "Code Deliver Medium: " +
+ "${result.nextStep.codeDeliveryDetails?.deliveryMedium}")
+ Log.i("AuthQuickstart", "Code Deliver Destination: " +
+ "${result.nextStep.codeDeliveryDetails?.destination}")
+}
+
+// Confirm sign up with the OTP received
+result = Amplify.Auth.confirmSignUp(
+ "hello@example.com",
+ "123456"
+)
+
+if (result.nextStep.signUpStep == AuthSignUpStep.DONE) {
+ Log.i("AuthQuickstart", "Sign up is complete")
+}
+```
+
+#### [RxJava]
+
+```java
+// Sign up using a phone number
+ArrayList attributes = new ArrayList<>();
+attributes.add(new AuthUserAttribute(AuthUserAttributeKey.phoneNumber(), "+15551234567"));
+
+RxAmplify.Auth.signUp(
+ "hello@example.com",
+ null,
+ AuthSignUpOptions.builder().userAttributes(attributes).build()
+)
+ .subscribe(
+ result -> {
+ if (result.isSignUpComplete()) {
+ Log.i("AuthQuickstart", "Sign up is complete");
+ } else if (result.getNextStep().getSignUpStep() == AuthSignUpStep.CONFIRM_SIGN_UP_STEP) {
+ Log.i("AuthQuickstart", "Code Deliver Medium: " +
+ result.getNextStep().getCodeDeliveryDetails().getDeliveryMedium());
+ Log.i("AuthQuickstart", "Code Deliver Destination: " +
+ result.getNextStep().getCodeDeliveryDetails().getDestination());
+ }
+ },
+ error -> Log.e("AuthQuickstart", error.toString())
+ );
+
+// Confirm sign up with the OTP received
+RxAmplify.Auth.confirmSignUp(
+ "hello@example.com",
+ "123456"
+)
+ .subscribe(
+ result -> {
+ if (result.isSignUpComplete()) {
+ Log.i("AuthQuickstart", "Sign up is complete");
+ }
+ },
+ error -> Log.e("AuthQuickstart", error.toString())
+ );
+```
+
+
+
+
+#### [Async/Await]
+
+```swift
+// Sign up using an phone number
+func signUp(username: String, phonenumber: String) async {
+ let userAttributes = [
+ AuthUserAttribute(.phoneNumber, value: phonenumber)
+ ]
+ let options = AuthSignUpRequest.Options(userAttributes: userAttributes)
+ do {
+ let signUpResult = try await Amplify.Auth.signUp(
+ username: username,
+ options: options
+ )
+ 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)")
+ }
+}
+
+// Confirm sign up with the OTP received
+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)")
+ }
+}
+```
+
+#### [Combine]
+
+```swift
+// Sign up using a phone number
+func signUp(username: String, phonenumber: String) -> AnyCancellable {
+ let userAttributes = [
+ AuthUserAttribute(.phoneNumber, value: phonenumber)
+ ]
+ let options = AuthSignUpRequest.Options(userAttributes: userAttributes)
+ let sink = Amplify.Publisher.create {
+ try await Amplify.Auth.signUp(
+ username: username,
+ options: options
+ )
+ }.sink {
+ if case let .failure(authError) = $0 {
+ print("An error occurred while registering a user \(authError)")
+ }
+ }
+ receiveValue: { signUpResult in
+ if case let .confirmUser(deliveryDetails, _, userId) = signUpResult.nextStep {
+ print("Delivery details \(String(describing: deliveryDetails)) for userId: \(String(describing: userId)))")
+ } else {
+ print("SignUp Complete")
+ }
+ }
+ return sink
+}
+
+// Confirm sign up with the OTP received
+func confirmSignUp(for username: String, with confirmationCode: String) -> AnyCancellable {
+ Amplify.Publisher.create {
+ try await Amplify.Auth.confirmSignUp(
+ for: username,
+ confirmationCode: confirmationCode
+ )
+ }.sink {
+ if case let .failure(authError) = $0 {
+ print("An error occurred while confirming sign up \(authError)")
+ }
+ }
+ receiveValue: { _ in
+ print("Confirm signUp succeeded")
+ }
+}
+```
+
+
+
+### Email OTP
+
+
+```typescript
+// Sign up using an email address
+const { nextStep: signUpNextStep } = await signUp({
+ username: 'hello',
+ options: {
+ userAttributes: {
+ email: 'hello@example.com',
+ },
+ },
+});
+
+if (signUpNextStep.signUpStep === 'DONE') {
+ console.log(`SignUp Complete`);
+}
+
+if (signUpNextStep.signUpStep === 'CONFIRM_SIGN_UP') {
+ console.log(
+ `Code Delivery Medium: ${signUpNextStep.codeDeliveryDetails.deliveryMedium}`,
+ );
+ console.log(
+ `Code Delivery Destination: ${signUpNextStep.codeDeliveryDetails.destination}`,
+ );
+}
+
+// Confirm sign up with the OTP received
+const { nextStep: confirmSignUpNextStep } = await confirmSignUp({
+ username: 'hello',
+ confirmationCode: '123456',
+});
+
+if (confirmSignUpNextStep.signUpStep === 'DONE') {
+ console.log(`SignUp Complete`);
+}
+```
+
+
+
+#### [Java]
+
+```java
+// Sign up using an email address
+ArrayList attributes = new ArrayList<>();
+attributes.add(new AuthUserAttribute(AuthUserAttributeKey.email(), "hello@example.com"));
+
+Amplify.Auth.signUp(
+ "hello@example.com",
+ null,
+ AuthSignUpOptions.builder().userAttributes(attributes).build(),
+ result -> {
+ if (result.isSignUpComplete()) {
+ Log.i("AuthQuickstart", "Sign up is complete");
+ } else if (result.getNextStep().getSignUpStep() == AuthSignUpStep.CONFIRM_SIGN_UP_STEP) {
+ Log.i("AuthQuickstart", "Code Deliver Medium: " +
+ result.getNextStep().getCodeDeliveryDetails().getDeliveryMedium());
+ Log.i("AuthQuickstart", "Code Deliver Destination: " +
+ result.getNextStep().getCodeDeliveryDetails().getDestination());
+ }
+ },
+ error -> Log.e("AuthQuickstart", error.toString())
+);
+
+// Confirm sign up with the OTP received
+Amplify.Auth.confirmSignUp(
+ "hello@example.com",
+ "123456",
+ result -> {
+ if (result.isSignUpComplete()) {
+ Log.i("AuthQuickstart", "Sign up is complete");
+ }
+ },
+ error -> Log.e("AuthQuickstart", error.toString())
+);
+```
+
+#### [Kotlin - Callbacks]
+
+```kotlin
+// Sign up using an email address
+val attributes = listOf(
+ AuthUserAttribute(AuthUserAttributeKey.email(), "my@email.com")
+)
+val options =
+ AuthSignUpOptions
+ .builder()
+ .userAttributes(attributes)
+ .build()
+
+Amplify.Auth.signUp(
+ "hello@example.com",
+ null,
+ options,
+ { result ->
+ if (result.isSignUpComplete) {
+ Log.i("AuthQuickstart", "Sign up is complete")
+ } else if (result.nextStep.signUpStep == AuthSignUpStep.CONFIRM_SIGN_UP_STEP) {
+ Log.i("AuthQuickstart", "Code Deliver Medium: " +
+ "${result.nextStep.codeDeliveryDetails?.deliveryMedium}")
+ Log.i("AuthQuickstart", "Code Deliver Destination: " +
+ "${result.nextStep.codeDeliveryDetails?.destination}")
+ }
+ },
+ { Log.e("AuthQuickstart", "Failed to sign up", it) }
+)
+
+// Confirm sign up with the OTP received
+Amplify.Auth.confirmSignUp(
+ "hello@example.com",
+ "123456",
+ { result ->
+ if (result.nextStep.signUpStep == AuthSignUpStep.DONE) {
+ Log.i("AuthQuickstart", "Sign up is complete")
+ }
+ },
+ { Log.e("AuthQuickstart", "Failed to sign up", it) }
+)
+```
+
+#### [Kotlin - Coroutines]
+
+```kotlin
+// Sign up using an email address
+val attributes = listOf(
+ AuthUserAttribute(AuthUserAttributeKey.email(), "my@email.com")
+)
+val options =
+ AuthSignUpOptions
+ .builder()
+ .userAttributes(attributes)
+ .build()
+var result = Amplify.Auth.signUp("hello@example.com", null, options)
+
+if (result.isSignUpComplete) {
+ Log.i("AuthQuickstart", "Sign up is complete")
+} else if (result.nextStep.signUpStep == AuthSignUpStep.CONFIRM_SIGN_UP_STEP) {
+ Log.i("AuthQuickstart", "Code Deliver Medium: " +
+ "${result.nextStep.codeDeliveryDetails?.deliveryMedium}")
+ Log.i("AuthQuickstart", "Code Deliver Destination: " +
+ "${result.nextStep.codeDeliveryDetails?.destination}")
+}
+
+// Confirm sign up with the OTP received
+result = Amplify.Auth.confirmSignUp(
+ "hello@example.com",
+ "123456"
+)
+
+if (result.nextStep.signUpStep == AuthSignUpStep.DONE) {
+ Log.i("AuthQuickstart", "Sign up is complete")
+}
+```
+
+#### [RxJava]
+
+```java
+// Sign up using an email address
+ArrayList attributes = new ArrayList<>();
+attributes.add(new AuthUserAttribute(AuthUserAttributeKey.email(), "my@email.com"));
+
+RxAmplify.Auth.signUp(
+ "hello@example.com",
+ null,
+ AuthSignUpOptions.builder().userAttributes(attributes).build()
+)
+ .subscribe(
+ result -> {
+ if (result.isSignUpComplete()) {
+ Log.i("AuthQuickstart", "Sign up is complete");
+ } else if (result.getNextStep().getSignUpStep() == AuthSignUpStep.CONFIRM_SIGN_UP_STEP) {
+ Log.i("AuthQuickstart", "Code Deliver Medium: " +
+ result.getNextStep().getCodeDeliveryDetails().getDeliveryMedium());
+ Log.i("AuthQuickstart", "Code Deliver Destination: " +
+ result.getNextStep().getCodeDeliveryDetails().getDestination());
+ }
+ },
+ error -> Log.e("AuthQuickstart", error.toString())
+ );
+
+// Confirm sign up with the OTP received
+RxAmplify.Auth.confirmSignUp(
+ "hello@example.com",
+ "123456"
+)
+ .subscribe(
+ result -> {
+ if (result.isSignUpComplete()) {
+ Log.i("AuthQuickstart", "Sign up is complete");
+ }
+ },
+ error -> Log.e("AuthQuickstart", error.toString())
+ );
+```
+
+
+
+
+#### [Async/Await]
+
+```swift
+// Sign up using an email
+func signUp(username: String, email: String) async {
+ let userAttributes = [
+ AuthUserAttribute(.email, value: email)
+ ]
+ let options = AuthSignUpRequest.Options(userAttributes: userAttributes)
+ do {
+ let signUpResult = try await Amplify.Auth.signUp(
+ username: username,
+ options: options
+ )
+ 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)")
+ }
+}
+
+// Confirm sign up with the OTP received
+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)")
+ }
+}
+```
+
+#### [Combine]
+
+```swift
+// Sign up using an email
+func signUp(username: String, email: String) -> AnyCancellable {
+ let userAttributes = [
+ AuthUserAttribute(.email, value: email)
+ ]
+ let options = AuthSignUpRequest.Options(userAttributes: userAttributes)
+ let sink = Amplify.Publisher.create {
+ try await Amplify.Auth.signUp(
+ username: username,
+ options: options
+ )
+ }.sink {
+ if case let .failure(authError) = $0 {
+ print("An error occurred while registering a user \(authError)")
+ }
+ }
+ receiveValue: { signUpResult in
+ if case let .confirmUser(deliveryDetails, _, userId) = signUpResult.nextStep {
+ print("Delivery details \(String(describing: deliveryDetails)) for userId: \(String(describing: userId)))")
+ } else {
+ print("SignUp Complete")
+ }
+ }
+ return sink
+}
+
+// Confirm sign up with the OTP received
+func confirmSignUp(for username: String, with confirmationCode: String) -> AnyCancellable {
+ Amplify.Publisher.create {
+ try await Amplify.Auth.confirmSignUp(
+ for: username,
+ confirmationCode: confirmationCode
+ )
+ }.sink {
+ if case let .failure(authError) = $0 {
+ print("An error occurred while confirming sign up \(authError)")
+ }
+ }
+ receiveValue: { _ in
+ print("Confirm signUp succeeded")
+ }
+}
+```
+
+
+
+### Auto Sign In
+
+
+```typescript
+// Call `signUp` API with `USER_AUTH` as the authentication flow type for `autoSignIn`
+const { nextStep: signUpNextStep } = await signUp({
+ username: 'hello',
+ options: {
+ userAttributes: {
+ email: 'hello@example.com',
+ phone_number: '+15555551234',
+ },
+ autoSignIn: {
+ authFlowType: 'USER_AUTH',
+ },
+ },
+});
+
+if (signUpNextStep.signUpStep === 'CONFIRM_SIGN_UP') {
+ console.log(
+ `Code Delivery Medium: ${signUpNextStep.codeDeliveryDetails.deliveryMedium}`,
+ );
+ console.log(
+ `Code Delivery Destination: ${signUpNextStep.codeDeliveryDetails.destination}`,
+ );
+}
+
+// Call `confirmSignUp` API with the OTP received
+const { nextStep: confirmSignUpNextStep } = await confirmSignUp({
+ username: 'hello',
+ confirmationCode: '123456',
+});
+
+if (confirmSignUpNextStep.signUpStep === 'COMPLETE_AUTO_SIGN_IN') {
+ // Call `autoSignIn` API to complete the flow
+ const { nextStep } = await autoSignIn();
+
+ if (nextStep.signInStep === 'DONE') {
+ console.log('Successfully signed in.');
+ }
+}
+
+```
+
+
+
+#### [Java]
+
+```java
+private void confirmSignUp(String username, String confirmationCode) {
+ // Confirm sign up with the OTP received then auto sign in
+ Amplify.Auth.confirmSignUp(
+ username,
+ confirmationCode,
+ result -> {
+ if (result.getNextStep().getSignUpStep() == AuthSignUpStep.COMPLETE_AUTO_SIGN_IN) {
+ Log.i("AuthQuickstart", "Sign up is complete, auto sign in");
+ autoSignIn();
+ }
+ },
+ error -> Log.e("AuthQuickstart", error.toString())
+ );
+}
+
+private void autoSignIn() {
+ Amplify.Auth.autoSignIn(
+ result -> Log.i("AuthQuickstart", "Sign in is complete"),
+ error -> Log.e("AuthQuickstart", error.toString())
+ );
+}
+```
+
+#### [Kotlin - Callbacks]
+
+```kotlin
+fun confirmSignUp(username: String, confirmationCode: String) {
+ // Confirm sign up with the OTP received
+ Amplify.Auth.confirmSignUp(
+ username,
+ confirmationCode,
+ { signUpResult ->
+ if (signUpResult.nextStep.signUpStep == AuthSignUpStep.COMPLETE_AUTO_SIGN_IN) {
+ Log.i("AuthQuickstart", "Sign up is complete, auto sign in")
+ autoSignIn()
+ }
+ },
+ { Log.e("AuthQuickstart", "Failed to sign up", it) }
+ )
+}
+fun autoSignIn() {
+ Amplify.Auth.autoSignIn(
+ { signInResult ->
+ Log.i("AuthQuickstart", "Sign in is complete")
+ },
+ { Log.e("AuthQuickstart", "Failed to sign in", it) }
+ )
+}
+```
+
+#### [Kotlin - Coroutines]
+
+```kotlin
+suspend fun confirmSignUp(username: String, confirmationCode: String) {
+ // Confirm sign up with the OTP received then auto sign in
+ val result = Amplify.Auth.confirmSignUp(
+ "hello@example.com",
+ "123456"
+ )
+
+ if (result.nextStep.signUpStep == AuthSignUpStep.COMPLETE_AUTO_SIGN_IN) {
+ Log.i("AuthQuickstart", "Sign up is complete, auto sign in")
+ autoSignIn()
+ }
+}
+
+suspend fun autoSignIn() {
+ val result = Amplify.Auth.autoSignIn()
+ if (result.isSignedIn) {
+ Log.i("AuthQuickstart", "Sign in is complete")
+ } else {
+ Log.e("AuthQuickstart", "Sign in did not complete $result")
+ }
+}
+```
+
+#### [RxJava]
+
+```java
+private void confirmSignUp(String username, String confirmationCode) {
+ // Confirm sign up with the OTP received then auto sign in
+ RxAmplify.Auth.confirmSignUp(
+ username,
+ confirmationCode
+ )
+ .subscribe(
+ result -> {
+ if (result.getNextStep().getSignUpStep() == AuthSignUpStep.COMPLETE_AUTO_SIGN_IN) {
+ Log.i("AuthQuickstart", "Sign up is complete, auto sign in");
+ autoSignIn();
+ }
+ },
+ error -> Log.e("AuthQuickstart", error.toString())
+ );
+}
+
+private void autoSignIn() {
+ RxAmplify.Auth.autoSignIn()
+ .subscribe(
+ result -> Log.i("AuthQuickstart", "Sign in is complete" + result.toString()),
+ error -> Log.e("AuthQuickstart", error.toString())
+ );
+}
+```
+
+
+
+
+#### [Async/Await]
+
+```swift
+// Confirm sign up with the OTP received and auto sign in
+func confirmSignUp(for username: String, with confirmationCode: String) async {
+ do {
+ let confirmSignUpResult = try await Amplify.Auth.confirmSignUp(
+ for: username,
+ confirmationCode: confirmationCode
+ )
+ if case .completeAutoSignIn(let session) = confirmSignUpResult.nextStep {
+ let autoSignInResult = try await Amplify.Auth.autoSignIn()
+ print("Auto sign in result: \(autoSignInResult.isSignedIn)")
+ } else {
+ 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)")
+ }
+}
+```
+
+#### [Combine]
+
+```swift
+// Confirm sign up with the OTP received and auto sign in
+func confirmSignUp(for username: String, with confirmationCode: String) -> AnyCancellable {
+ Amplify.Publisher.create {
+ try await Amplify.Auth.confirmSignUp(
+ for: username,
+ confirmationCode: confirmationCode
+ )
+ }.sink {
+ if case let .failure(authError) = $0 {
+ print("An error occurred while confirming sign up \(authError)")
+ }
+ }
+ receiveValue: { confirmSignUpResult in
+ if case let .completeAutoSignIn(session) = confirmSignUpResult.nextStep {
+ print("Confirm Sign Up succeeded. Next step is auto sign in")
+ // call `autoSignIn()` API to complete sign in
+ } else {
+ print("Confirm sign up result completed: \(confirmSignUpResult.isSignUpComplete)")
+ }
+ }
+}
+
+func autoSignIn() -> AnyCancellable {
+ Amplify.Publisher.create {
+ try await Amplify.Auth.autoSignIn()
+ }.sink {
+ if case let .failure(authError) = $0 {
+ print("Auto Sign in failed \(authError)")
+ }
+ }
+ receiveValue: { autoSignInResult in
+ if autoSignInResult.isSignedIn {
+ print("Auto Sign in succeeded")
+ }
+ }
+}
+```
+
+
+
+
+---
+
+---
+title: "Sign-in"
+section: "build-a-backend/auth/connect-your-frontend"
+platforms: ["android", "angular", "flutter", "javascript", "nextjs", "react", "react-native", "swift", "vue"]
+gen: 2
+last-updated: "2025-06-24T13:29:28.000Z"
+url: "https://docs.amplify.aws/react/build-a-backend/auth/connect-your-frontend/sign-in/"
+---
+
+Amplify provides a client library that enables you to interact with backend resources such as Amplify Auth.
+
+
+> **Info:** The quickest way to get started with Amplify Auth in your frontend application is with the [Authenticator component](https://ui.docs.amplify.aws/react/connected-components/authenticator), which provides a customizable UI and complete authentication flows.
+
+
+
+> **Info:** The quickest way to get started with Amplify Auth in your frontend application is with the [Authenticator component](https://ui.docs.amplify.aws/swift/connected-components/authenticator), which provides a customizable UI and complete authentication flows.
+
+
+
+> **Info:** The quickest way to get started with Amplify Auth in your frontend application is with the [Authenticator component](https://ui.docs.amplify.aws/flutter/connected-components/authenticator), which provides a customizable UI and complete authentication flows.
+
+
+
+> **Info:** The quickest way to get started with Amplify Auth in your frontend application is with the [Authenticator component](https://ui.docs.amplify.aws/android/connected-components/authenticator), which provides a customizable UI and complete authentication flows.
+
+
+## Using the signIn API
+
+
+```ts
+import { signIn } from 'aws-amplify/auth'
+
+await signIn({
+ username: "hello@mycompany.com",
+ password: "hunter2",
+})
+```
+
+
+```dart
+Future signInUser(String username, String password) async {
+ try {
+ final result = await Amplify.Auth.signIn(
+ username: username,
+ password: password,
+ );
+ await _handleSignInResult(result);
+ } on AuthException catch (e) {
+ safePrint('Error signing in: ${e.message}');
+ }
+}
+```
+
+Depending on your configuration and how the user signed up, one or more confirmations will be necessary. Use the `SignInResult` returned from `Amplify.Auth.signIn` to check the next step for signing in. When the value is `done`, the user has successfully signed in.
+
+```dart
+Future _handleSignInResult(SignInResult result) async {
+ switch (result.nextStep.signInStep) {
+ case AuthSignInStep.confirmSignInWithSmsMfaCode:
+ final codeDeliveryDetails = result.nextStep.codeDeliveryDetails!;
+ _handleCodeDelivery(codeDeliveryDetails);
+ break;
+ case AuthSignInStep.confirmSignInWithNewPassword:
+ safePrint('Enter a new password to continue signing in');
+ break;
+ case AuthSignInStep.confirmSignInWithCustomChallenge:
+ final parameters = result.nextStep.additionalInfo;
+ final prompt = parameters['prompt']!;
+ safePrint(prompt);
+ break;
+ case AuthSignInStep.resetPassword:
+ final resetResult = await Amplify.Auth.resetPassword(
+ username: username,
+ );
+ await _handleResetPasswordResult(resetResult);
+ break;
+ case AuthSignInStep.confirmSignUp:
+ // Resend the sign up code to the registered device.
+ final resendResult = await Amplify.Auth.resendSignUpCode(
+ username: username,
+ );
+ _handleCodeDelivery(resendResult.codeDeliveryDetails);
+ break;
+ case AuthSignInStep.done:
+ safePrint('Sign in is complete');
+ break;
+ }
+}
+
+void _handleCodeDelivery(AuthCodeDeliveryDetails codeDeliveryDetails) {
+ safePrint(
+ 'A confirmation code has been sent to ${codeDeliveryDetails.destination}. '
+ 'Please check your ${codeDeliveryDetails.deliveryMedium.name} for the code.',
+ );
+}
+```
+
+
+
+#### [Java]
+
+```java
+Amplify.Auth.signIn(
+ "username",
+ "password",
+ result -> Log.i("AuthQuickstart", result.isSignedIn() ? "Sign in succeeded" : "Sign in not complete"),
+ error -> Log.e("AuthQuickstart", error.toString())
+);
+```
+
+#### [Kotlin - Callbacks]
+
+```kotlin
+Amplify.Auth.signIn("username", "password",
+ { result ->
+ if (result.isSignedIn) {
+ Log.i("AuthQuickstart", "Sign in succeeded")
+ } else {
+ Log.i("AuthQuickstart", "Sign in not complete")
+ }
+ },
+ { Log.e("AuthQuickstart", "Failed to sign in", it) }
+)
+```
+
+#### [Kotlin - Coroutines]
+
+```kotlin
+try {
+ val result = Amplify.Auth.signIn("username", "password")
+ if (result.isSignedIn) {
+ Log.i("AuthQuickstart", "Sign in succeeded")
+ } else {
+ Log.e("AuthQuickstart", "Sign in not complete")
+ }
+} catch (error: AuthException) {
+ Log.e("AuthQuickstart", "Sign in failed", error)
+}
+```
+
+#### [RxJava]
+
+```java
+RxAmplify.Auth.signIn("username", "password")
+ .subscribe(
+ result -> Log.i("AuthQuickstart", result.isSignedIn() ? "Sign in succeeded" : "Sign in not complete"),
+ error -> Log.e("AuthQuickstart", error.toString())
+ );
+```
+
+
+
+
+#### [Async/Await]
+
+```swift
+func signIn(username: String, password: String) async {
+ do {
+ let signInResult = try await Amplify.Auth.signIn(
+ username: username,
+ password: password
+ )
+ if signInResult.isSignedIn {
+ print("Sign in succeeded")
+ }
+ } catch let error as AuthError {
+ print("Sign in failed \(error)")
+ } catch {
+ print("Unexpected error: \(error)")
+ }
+}
+```
+
+#### [Combine]
+
+```swift
+func signIn(username: String, password: String) -> AnyCancellable {
+ Amplify.Publisher.create {
+ try await Amplify.Auth.signIn(
+ username: username,
+ password: password
+ )
+ }.sink {
+ if case let .failure(authError) = $0 {
+ print("Sign in failed \(authError)")
+ }
+ }
+ receiveValue: { signInResult in
+ if signInResult.isSignedIn {
+ print("Sign in succeeded")
+ }
+ }
+}
+```
+
+
+
+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:
+
+
+| 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 an SMS code from the user. Complete the process with `confirmSignIn`. |
+| `CONFIRM_SIGN_IN_WITH_EMAIL_CODE` | The sign-in must be confirmed with an EMAIL code from the user. Complete the process with `confirmSignIn`. |
+| `CONFIRM_SIGN_IN_WITH_PASSWORD` | The sign-in must be confirmed with the password from the user. Complete the process with `confirmSignIn`. |
+| `CONTINUE_SIGN_IN_WITH_FIRST_FACTOR_SELECTION` | The user must select their mode of first factor authentication. Complete the process by passing the desired mode to the `challengeResponse` field of `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. |
+
+
+
+| 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`. |
+| `CONFIRM_SIGN_IN_WITH_PASSWORD` | The sign-in must be confirmed with the password from the user. 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_MFA_SELECTION` | The user must select their mode of MFA verification before signing in. Complete the process with `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`. |
+| `CONTINUE_SIGN_IN_WITH_FIRST_FACTOR_SELECTION` | The user must select their mode of first factor authentication. Complete the process by passing the desired mode to the `challengeResponse` field of `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 |
+| --------- | ----------- |
+| `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`. |
+| `confirmSignInWithPassword` | The user must set a new password. Complete the process with `confirmSignIn`. |
+| `continueSignInWithFirstFactorSelection` | The user must select their preferred mode of First Factor authentication. 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. |
+
+
+
+| 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. |
+
+
+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/).
+
+
+
+
+
+
+#### [Async/Await]
+
+```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)")
+ }
+}
+```
+
+#### [Combine]
+
+```swift
+func confirmSignIn() -> AnyCancellable {
+ Amplify.Publisher.create {
+ try await Amplify.Auth.confirmSignIn(challengeResponse: "")
+ }.sink {
+ if case let .failure(authError) = $0 {
+ print("Confirm sign in failed \(authError)")
+ }
+ }
+ receiveValue: { signInResult in
+ print("Confirm sign in succeeded. Next step: \(signInResult.nextStep)")
+ }
+}
+```
+
+
+
+
+
+
+
+### Practical Example
+
+
+```tsx title="src/App.tsx"
+import type { FormEvent } from "react"
+import { Amplify } from "aws-amplify"
+// highlight-next-line
+import { signIn } from "aws-amplify/auth"
+import outputs from "../amplify_outputs.json"
+
+Amplify.configure(outputs)
+
+interface SignInFormElements extends HTMLFormControlsCollection {
+ email: HTMLInputElement
+ password: HTMLInputElement
+}
+
+interface SignInForm extends HTMLFormElement {
+ readonly elements: SignInFormElements
+}
+
+export default function App() {
+ async function handleSubmit(event: FormEvent) {
+ event.preventDefault()
+ const form = event.currentTarget
+ // ... validate inputs
+ await signIn({
+ username: form.elements.email.value,
+ password: form.elements.password.value,
+ })
+ }
+
+ return (
+
+ )
+}
+```
+
+
+
+## With multi-factor auth enabled
+
+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.
+
+
+
+#### [Java]
+
+```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 - Callbacks]
+
+```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 - Coroutines]
+
+```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)
+}
+```
+
+#### [RxJava]
+
+```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())
+ );
+```
+
+
+
+
+#### [Async/Await]
+
+```swift
+func signUp(username: String, password: String, email: String, phonenumber: String) async {
+ let userAttributes = [AuthUserAttribute(.email, value: email), AuthUserAttribute(.phoneNumber, value: phonenumber)]
+ let options = AuthSignUpRequest.Options(userAttributes: userAttributes)
+
+ do {
+ let signUpResult = try await Amplify.Auth.signUp(
+ username: username,
+ password: password,
+ options: options
+ )
+
+ 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)")
+ }
+}
+```
+
+#### [Combine]
+
+```swift
+func signUp(username: String, password: String, email: String, phonenumber: String) -> AnyCancellable {
+ let userAttributes = [
+ AuthUserAttribute(.email, value: email),
+ AuthUserAttribute(.phoneNumber, value: phonenumber)
+ ]
+ let options = AuthSignUpRequest.Options(userAttributes: userAttributes)
+ Amplify.Publisher.create {
+ try await Amplify.Auth.signUp(
+ username: username,
+ password: password,
+ options: options
+ )
+ }.sink {
+ if case let .failure(authError) = $0 {
+ print("An error occurred while registering a user \(authError)")
+ }
+ }
+ receiveValue: { signUpResult in
+ if case let .confirmUser(deliveryDetails, _, userId) = signUpResult.nextStep {
+ print("Delivery details \(String(describing: deliveryDetails)) for userId: \(String(describing: userId)))")
+ } else {
+ print("SignUp Complete")
+ }
+ }
+ return sink
+}
+```
+
+
+
+### 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`. |
+| `CONFIRM_SIGN_IN_WITH_PASSWORD` | The sign-in must be confirmed with the password from the user. Complete the process with `confirmSignIn`. |
+| `CONTINUE_SIGN_IN_WITH_FIRST_FACTOR_SELECTION` | The user must select their mode of first factor authentication. Complete the process by passing the desired mode to the `challengeResponse` field of `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`. |
+| `CONFIRM_SIGN_IN_WITH_PASSWORD` | The sign-in must be confirmed with the password from the user. Complete the process with `confirmSignIn`. |
+| `CONTINUE_SIGN_IN_WITH_FIRST_FACTOR_SELECTION` | The user must select their mode of first factor authentication. Complete the process by passing the desired mode to the `challengeResponse` field of `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`. |
+
+
+
+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`. |
+| `confirmSignInWithPassword` | The user must set a new password. Complete the process with `confirmSignIn`. |
+| `continueSignInWithFirstFactorSelection` | The user must select their preferred mode of First Factor authentication. 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`. |
+
+
+
+> **Info:** **Note:** you must call `confirmSignIn` in the same app session as you call `signIn`. If you close the app, you will need to call `signIn` again. As a result, for testing purposes, you'll at least need an input field where you can enter the code sent via SMS and pass it to `confirmSignIn`.
+
+
+
+```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",
+ });
+}
+
+```
+> **Info:** **Note:** The Amplify authentication flow will persist relevant session data throughout the lifespan of a page session. This enables the `confirmSignIn` API to be leveraged even after a full page refresh in a multi-page application, such as when redirecting from a login page to a sign in confirmation page.
+
+
+
+
+#### [Java]
+
+```java
+Amplify.Auth.confirmSignIn(
+ "confirmation code received via SMS",
+ result -> Log.i("AuthQuickstart", result.toString()),
+ error -> Log.e("AuthQuickstart", error.toString())
+);
+```
+
+#### [Kotlin - Callbacks]
+
+```kotlin
+Amplify.Auth.confirmSignIn("code received via SMS",
+ { Log.i("AuthQuickstart", "Confirmed signin: $it") },
+ { Log.e("AuthQuickstart", "Failed to confirm signin", it) }
+)
+```
+
+#### [Kotlin - Coroutines]
+
+```kotlin
+try {
+ val result = Amplify.Auth.confirmSignIn("code received via SMS")
+ Log.i("AuthQuickstart", "Confirmed signin: $result")
+} catch (error: AuthException) {
+ Log.e("AuthQuickstart", "Failed to confirm signin", error)
+}
+```
+
+#### [RxJava]
+
+```java
+RxAmplify.Auth.confirmSignIn("confirmation code received via SMS")
+ .subscribe(
+ result -> Log.i("AuthQuickstart", result.toString()),
+ error -> Log.e("AuthQuickstart", error.toString())
+ );
+```
+
+
+
+
+#### [Async/Await]
+
+```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)")
+ }
+}
+```
+
+#### [Combine]
+
+```swift
+func confirmSignIn() -> AnyCancellable {
+ Amplify.Publisher.create {
+ try await Amplify.Auth.confirmSignIn(challengeResponse: "")
+ }.sink {
+ if case let .failure(authError) = $0 {
+ print("Confirm sign in failed \(authError)")
+ }
+ }
+ receiveValue: { signInResult in
+ print("Confirm sign in succeeded. Next step: \(signInResult.nextStep)")
+ }
+}
+```
+
+
+
+## Sign in with an external identity provider
+
+
+To sign in using an external identity provider such as Google, use the `signInWithRedirect` function.
+
+> **Info:** For guidance on configuring an external Identity Provider with Amplify see [External Identity Providers](/[platform]/build-a-backend/auth/concepts/external-identity-providers/)
+
+```ts
+import { signInWithRedirect } from "aws-amplify/auth"
+
+signInWithRedirect({ provider: "Google" })
+```
+
+> **Info:** **Note:** if you do not pass an argument to `signInWithRedirect` it will redirect your users to the [Cognito Hosted UI](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-app-integration.html), which has limited support for customization.
+
+Alternatively if you have configured OIDC or SAML-based identity providers in your auth resource, you can specify a "custom" provider in `signInWithRedirect`:
+
+```ts
+import { signInWithRedirect } from "aws-amplify/auth"
+
+signInWithRedirect({ provider: {
+ custom: "MyOidcProvider"
+}})
+```
+
+## Auto sign-in
+
+The `autoSignIn` API will automatically sign-in a user when it was previously enabled by the `signUp` API and after any of the following cases has completed:
+
+- User confirmed their account with a verification code sent to their phone or email (default option).
+- User confirmed their account with a verification link sent to their phone or email. In order to enable this option you need to go to the [Amazon Cognito console](https://aws.amazon.com/pm/cognito), look for your userpool, then go to the `Messaging` tab and enable `link` mode inside the `Verification message` option. Finally you need to define the `signUpVerificationMethod` to `link` inside the `Cognito` option of your `Auth` config.
+
+```ts title="src/main.ts"
+import { autoSignIn } from 'aws-amplify/auth';
+
+await autoSignIn();
+```
+
+**Note**: When MFA is enabled, your users may be presented with multiple consecutive steps that require them to enter an OTP to proceed with the sign up and subsequent sign in flow. This requirement is not present when using the `USER_AUTH` flow.
+
+
+
+
+### Install native module
+
+`signInWithRedirect` displays the sign-in UI inside a platform-dependent webview. On iOS devices, an [ASWebAuthenticationSession](https://developer.apple.com/documentation/authenticationservices/aswebauthenticationsession) will be launched and, on Android, a [Custom Tab](https://developer.chrome.com/docs/android/custom-tabs/). After the sign-in process is complete, the sign-in UI will redirect back to your app.
+
+To enable this capability, an additional dependency must be installed.
+
+```bash title="Terminal" showLineNumbers={false}
+npm add @aws-amplify/rtn-web-browser
+```
+
+### Platform Setup
+
+On iOS, there are no additional setup steps.
+
+#### Android
+
+After a successful sign-in, the sign-in UI will attempt to redirect back to your application. To register the redirect URI scheme you configured above with the device, an `intent-filter` must be added to your application's `AndroidManifest.xml` file which should be located in your React Native app's `android/app/src/main` directory.
+
+Add the `intent-filter` to your application's main activity, replacing `myapp` with your redirect URI scheme as necessary.
+
+```xml title="android/app/src/main/AndroidManifest.xml"
+
+
+ ...
+
+
+
+
+
+
+ ...
+
+
+```
+
+
+
+To sign in using an external identity provider such as Google, use the `signInWithWebUI` function.
+
+### How It Works
+
+Sign-in with web UI will display the sign-in UI inside a webview. After the sign-in process is complete, the sign-in UI will redirect back to your app.
+
+### Platform Setup
+
+#### Web
+
+To use Hosted UI in your Flutter web application locally, you must run the app with the `--web-port=3000` argument (with the value being whichever port you assigned to localhost host when configuring your redirect URIs).
+
+#### Android
+
+Add the following `queries` element to the `AndroidManifest.xml` file in your app's `android/app/src/main` directory, as well as the following `intent-filter` to the `MainActivity` in the same file.
+
+Replace `myapp` with your redirect URI scheme as necessary:
+
+```xml
+
+
+
+
+
+
+ ...
+
+
+
+
+
+
+
+
+ ...
+
+```
+
+#### macOS
+
+Open XCode and enable the App Sandbox capability and then select "Incoming Connections (Server)" under "Network".
+
+
+
+#### iOS, Windows and Linux
+
+No specific platform configuration is required.
+
+### Launch Social Web UI Sign In
+
+You're now ready to launch sign in with your external provider's web UI.
+
+```dart
+Future socialSignIn() async {
+ try {
+ final result = await Amplify.Auth.signInWithWebUI(
+ provider: AuthProvider.google,
+ );
+ safePrint('Sign in result: $result');
+ } on AuthException catch (e) {
+ safePrint('Error signing in: ${e.message}');
+ }
+}
+```
+
+
+To sign in using an external identity provider such as Google, use the `signInWithSocialWebUI` function.
+
+### Update AndroidManifest.xml
+
+Add the following activity and queries tag to your app's `AndroidManifest.xml` file, replacing `myapp` with
+your redirect URI prefix if necessary:
+
+```xml
+
+ ...
+
+
+
+
+
+
+
+
+ ...
+
+```
+
+### Launch Social Web UI Sign In
+
+Sweet! You're now ready to launch sign in with your social provider's web UI.
+
+For now, just add this method to the `onCreate` method of MainActivity with whatever provider you're using (shown with Facebook below):
+
+#### [Java]
+
+```java
+// Replace facebook with your chosen auth provider such as google, amazon, or apple
+Amplify.Auth.signInWithSocialWebUI(
+ AuthProvider.facebook(),
+ this,
+ result -> Log.i("AuthQuickstart", result.toString()),
+ error -> Log.e("AuthQuickstart", error.toString())
+);
+```
+
+#### [Kotlin - Callbacks]
+
+```kotlin
+// Replace facebook with your chosen auth provider such as google, amazon, or apple
+Amplify.Auth.signInWithSocialWebUI(
+ AuthProvider.facebook(),
+ this,
+ { Log.i("AuthQuickstart", "Sign in OK: $it") },
+ { Log.e("AuthQuickstart", "Sign in failed", it) }
+)
+```
+
+#### [Kotlin - Coroutines]
+
+```kotlin
+try {
+ // Replace facebook with your chosen auth provider such as google, amazon, or apple
+ val result = Amplify.Auth.signInWithSocialWebUI(AuthProvider.facebook(), this)
+ Log.i("AuthQuickstart", "Sign in OK: $result")
+} catch (error: AuthException) {
+ Log.e("AuthQuickstart", "Sign in failed", error)
+}
+```
+
+#### [RxJava]
+
+```java
+// Replace facebook with your chosen auth provider such as google, amazon, or apple
+RxAmplify.Auth.signInWithSocialWebUI(AuthProvider.facebook(), this)
+ .subscribe(
+ result -> Log.i("AuthQuickstart", result.toString()),
+ error -> Log.e("AuthQuickstart", error.toString())
+ );
+```
+
+
+
+
+To sign in using an external identity provider such as Google, use the `signInWithWebUI` function.
+
+### Update Info.plist
+
+Sign-in with web UI requires the Amplify plugin to show up the sign-in UI inside a webview. After the sign-in process is complete it will redirect back to your app.
+You have to enable this in your app's `Info.plist`. Right click Info.plist and then choose Open As > Source Code. Add the following entry in the URL scheme:
+
+```xml
+
+
+
+
+
+
+
+
+ CFBundleURLTypes
+
+
+ CFBundleURLSchemes
+
+ myapp
+
+
+
+
+
+
+```
+
+When creating a new SwiftUI app using Xcode 13 no longer require configuration files such as the Info.plist. If you are missing this file, click on the project target, under Info, Url Types, and click '+' to add a new URL Type. Add `myapp` to the URL Schemes. You should see the Info.plist file now with the entry for CFBundleURLSchemes.
+
+### Launch Social Web UI Sign In
+
+Invoke the following API with the provider you're using (shown with Facebook below):
+
+#### [Async/Await]
+
+```swift
+func socialSignInWithWebUI() async {
+ do {
+ let signInResult = try await Amplify.Auth.signInWithWebUI(for: .facebook, presentationAnchor: self.view.window!)
+ if signInResult.isSignedIn {
+ print("Sign in succeeded")
+ }
+ } catch let error as AuthError {
+ print("Sign in failed \(error)")
+ } catch {
+ print("Unexpected error: \(error)")
+ }
+}
+```
+
+#### [Combine]
+
+```swift
+func socialSignInWithWebUI() -> AnyCancellable {
+ Amplify.Publisher.create {
+ try await Amplify.Auth.signInWithWebUI(for: .facebook, presentationAnchor: self.view.window!)
+ }.sink {
+ if case let .failure(authError) = $0 {
+ print("Sign in failed \(authError)")
+ }
+ }
+ receiveValue: { signInResult in
+ if signInResult.isSignedIn {
+ print("Sign in succeeded")
+ }
+ }
+}
+```
+
+
+
+
+## Sign in with passwordless methods
+
+Your application's users can also sign in using passwordless methods. To learn more, including how to setup the various passwordless authentication flows, visit the [concepts page for passwordless](/[platform]/build-a-backend/auth/concepts/passwordless/).
+
+### SMS OTP
+
+
+Pass `SMS_OTP` as the `preferredChallenge` when calling the `signIn` API in order to initiate a passwordless authentication flow with SMS OTP.
+
+```ts
+const { nextStep: signInNextStep } = await signIn({
+ username: '+15551234567',
+ options: {
+ authFlowType: 'USER_AUTH',
+ preferredChallenge: 'SMS_OTP',
+ },
+});
+
+if (signInNextStep.signInStep === 'CONFIRM_SIGN_IN_WITH_SMS_CODE') {
+ // prompt user for otp code delivered via SMS
+ const { nextStep: confirmSignInNextStep } = await confirmSignIn({
+ challengeResponse: '123456',
+ });
+
+ if (confirmSignInNextStep.signInStep === 'DONE') {
+ console.log('Sign in successful!');
+ }
+}
+```
+
+
+Pass `SMS_OTP` as the `preferredFirstFactor` when calling the `signIn` API in order to initiate a passwordless authentication flow with SMS OTP.
+
+#### [Java]
+
+```java
+// Use options to specify the preferred first factor
+AWSCognitoAuthSignInOptions options = AWSCognitoAuthSignInOptions.builder()
+ .authFlowType(AuthFlowType.USER_AUTH)
+ .preferredFirstFactor(AuthFactorType.SMS_OTP) // Sign in using SMS OTP
+ .build();
+
+// Sign in the user
+Amplify.Auth.signIn(
+ username,
+ null, // no password
+ options,
+ result -> {
+ if (result.getNextStep().getSignInStep() == AuthSignInStep.CONFIRM_SIGN_IN_WITH_OTP) {
+ // Show UI to collect OTP
+ }
+ },
+ error -> Log.e("AuthQuickstart", error.toString())
+);
+
+// Then pass that OTP into the confirmSignIn API
+Amplify.Auth.confirmSignIn(
+ "123456",
+ result -> {
+ // result.getNextStep().getSignInStep() should be "DONE" now
+ },
+ error -> Log.e("AuthQuickstart", error.toString())
+);
+```
+
+#### [Kotlin - Callbacks]
+
+```kotlin
+// Use options to specify the preferred first factor
+val options = AWSCognitoAuthSignInOptions.builder()
+ .authFlowType(AuthFlowType.USER_AUTH)
+ .preferredFirstFactor(AuthFactorType.SMS_OTP) // Sign in using SMS OTP
+ .build()
+
+// Sign in the user
+Amplify.Auth.signIn(
+ username,
+ null, // no password
+ options,
+ { result: AuthSignInResult ->
+ if (result.nextStep.signInStep == AuthSignInStep.CONFIRM_SIGN_IN_WITH_OTP) {
+ // Show UI to collect OTP
+ }
+ },
+ { error: AuthException -> Log.e("AuthQuickstart", error.toString()) }
+)
+
+// Then pass that OTP into the confirmSignIn API
+Amplify.Auth.confirmSignIn(
+ "123456",
+ { result: AuthSignInResult? -> },
+ { error: AuthException -> Log.e("AuthQuickstart", error.toString()) }
+)
+```
+
+#### [Kotlin - Coroutines]
+
+```kotlin
+// Use options to specify the preferred first factor
+val options = AWSCognitoAuthSignInOptions.builder()
+ .authFlowType(AuthFlowType.USER_AUTH)
+ .preferredFirstFactor(AuthFactorType.SMS_OTP) // Sign in using SMS OTP
+ .build()
+
+// Sign in the user
+val result = Amplify.Auth.signIn(
+ username = username,
+ password = null,
+ options = options
+)
+if (result.nextStep.signInStep == AuthSignInStep.CONFIRM_SIGN_IN_WITH_OTP) {
+ // Show UI to collect OTP
+}
+
+// Then pass that OTP into the confirmSignIn API
+val confirmResult = Amplify.Auth.confirmSignIn(
+ challengeResponse = "123456"
+)
+// confirmResult.nextStep.signInStep should be "DONE"
+```
+
+#### [RxJava]
+
+```java
+// Use options to specify the preferred first factor
+AWSCognitoAuthSignInOptions options = AWSCognitoAuthSignInOptions.builder()
+ .authFlowType(AuthFlowType.USER_AUTH)
+ .preferredFirstFactor(AuthFactorType.SMS_OTP) // Sign in using SMS OTP
+ .build();
+
+// Sign in the user
+RxAmplify.Auth.signIn(
+ username,
+ null, // no password
+ options
+).subscribe(
+ result -> {
+ if (result.getNextStep().getSignInStep() == AuthSignInStep.CONFIRM_SIGN_IN_WITH_OTP) {
+ // Show UI to collect OTP
+ }
+ },
+ error -> Log.e("AuthQuickstart", error.toString())
+)
+
+// Then pass that OTP into the confirmSignIn API
+RxAmplify.Auth.confirmSignIn("123456")
+ .subscribe(
+ result -> {
+ // result.getNextStep().getSignInStep() should be "DONE" now
+ },
+ error -> Log.e("AuthQuickstart", error.toString())
+ );
+```
+
+
+
+Pass `smsOTP` as the `preferredFirstFactor` when calling the `signIn` API in order to initiate a passwordless authentication flow with SMS OTP.
+
+#### [Async/Await]
+
+```swift
+// sign in with `smsOTP` as preferred factor
+func signIn(username: String) async {
+ do {
+ let pluginOptions = AWSAuthSignInOptions(
+ authFlowType: .userAuth(preferredFirstFactor: .smsOTP))
+ let signInResult = try await Amplify.Auth.signIn(
+ username: username,
+ options: .init(pluginOptions: pluginOptions))
+ print("Sign in succeeded. Next step: \(signInResult.nextStep)")
+ } catch let error as AuthError {
+ print("Sign in failed \(error)")
+ } catch {
+ print("Unexpected error: \(error)")
+ }
+}
+
+// confirm sign in with the code received
+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)")
+ }
+}
+
+```
+
+#### [Combine]
+
+```swift
+// sign in with `smsOTP` as preferred factor
+func signIn(username: String) -> AnyCancellable {
+ Amplify.Publisher.create {
+ let pluginOptions = AWSAuthSignInOptions(
+ authFlowType: .userAuth(preferredFirstFactor: .smsOTP))
+ try await Amplify.Auth.signIn(
+ username: username,
+ options: .init(pluginOptions: pluginOptions))
+ }.sink {
+ if case let .failure(authError) = $0 {
+ print("Sign in failed \(authError)")
+ }
+ }
+ receiveValue: { signInResult in
+ print("Sign in succeeded. Next step: \(signInResult.nextStep)")
+ }
+}
+
+// confirm sign in with the code received
+func confirmSignIn() -> AnyCancellable {
+ Amplify.Publisher.create {
+ try await Amplify.Auth.confirmSignIn(challengeResponse: "")
+ }.sink {
+ if case let .failure(authError) = $0 {
+ print("Confirm sign in failed \(authError)")
+ }
+ }
+ receiveValue: { signInResult in
+ print("Confirm sign in succeeded. Next step: \(signInResult.nextStep)")
+ }
+}
+```
+
+
+
+### Email OTP
+
+
+Pass `EMAIL_OTP` as the `preferredChallenge` when calling the `signIn` API in order to initiate a passwordless authentication flow using email OTP.
+
+```ts
+const { nextStep: signInNextStep } = await signIn({
+ username: 'hello@example.com',
+ options: {
+ authFlowType: 'USER_AUTH',
+ preferredChallenge: 'EMAIL_OTP',
+ },
+});
+
+if (signInNextStep.signInStep === 'CONFIRM_SIGN_IN_WITH_EMAIL_CODE') {
+ // prompt user for otp code delivered via email
+ const { nextStep: confirmSignInNextStep } = await confirmSignIn({
+ challengeResponse: '123456',
+ });
+
+ if (confirmSignInNextStep.signInStep === 'DONE') {
+ console.log('Sign in successful!');
+ }
+}
+```
+
+
+Pass `EMAIL_OTP` as the `preferredFirstFactor` when calling the `signIn` API in order to initiate a passwordless authentication flow with Email OTP.
+
+#### [Java]
+
+```java
+// Use options to specify the preferred first factor
+AWSCognitoAuthSignInOptions options = AWSCognitoAuthSignInOptions.builder()
+ .authFlowType(AuthFlowType.USER_AUTH)
+ .preferredFirstFactor(AuthFactorType.EMAIL_OTP) // Sign in using Email OTP
+ .build();
+
+// Sign in the user
+Amplify.Auth.signIn(
+ username,
+ null, // no password
+ options,
+ result -> {
+ if (result.getNextStep().getSignInStep() == AuthSignInStep.CONFIRM_SIGN_IN_WITH_OTP) {
+ // Show UI to collect OTP
+ }
+ },
+ error -> Log.e("AuthQuickstart", error.toString())
+);
+
+// Then pass that OTP into the confirmSignIn API
+Amplify.Auth.confirmSignIn(
+ "123456",
+ result -> {
+ // result.getNextStep().getSignInStep() should be "DONE" now
+ },
+ error -> Log.e("AuthQuickstart", error.toString())
+);
+```
+
+#### [Kotlin - Callbacks]
+
+```kotlin
+// Use options to specify the preferred first factor
+val options = AWSCognitoAuthSignInOptions.builder()
+ .authFlowType(AuthFlowType.USER_AUTH)
+ .preferredFirstFactor(AuthFactorType.EMAIL_OTP) // Sign in using Email OTP
+ .build()
+
+// Sign in the user
+Amplify.Auth.signIn(
+ username,
+ null, // no password
+ options,
+ { result: AuthSignInResult ->
+ if (result.nextStep.signInStep == AuthSignInStep.CONFIRM_SIGN_IN_WITH_OTP) {
+ // Show UI to collect OTP
+ }
+ },
+ { error: AuthException -> Log.e("AuthQuickstart", error.toString()) }
+)
+
+// Then pass that OTP into the confirmSignIn API
+Amplify.Auth.confirmSignIn(
+ "123456",
+ { result: AuthSignInResult? -> },
+ { error: AuthException -> Log.e("AuthQuickstart", error.toString()) }
+)
+```
+
+#### [Kotlin - Coroutines]
+
+```kotlin
+// Use options to specify the preferred first factor
+val options = AWSCognitoAuthSignInOptions.builder()
+ .authFlowType(AuthFlowType.USER_AUTH)
+ .preferredFirstFactor(AuthFactorType.EMAIL_OTP) // Sign in using Email OTP
+ .build()
+
+// Sign in the user
+val result = Amplify.Auth.signIn(
+ username = username,
+ password = null,
+ options = options
+)
+if (result.nextStep.signInStep == AuthSignInStep.CONFIRM_SIGN_IN_WITH_OTP) {
+ // Show UI to collect OTP
+}
+
+// Then pass that OTP into the confirmSignIn API
+val confirmResult = Amplify.Auth.confirmSignIn(
+ challengeResponse = "123456"
+)
+// confirmResult.nextStep.signInStep should be "DONE"
+```
+
+#### [RxJava]
+
+```java
+// Use options to specify the preferred first factor
+AWSCognitoAuthSignInOptions options = AWSCognitoAuthSignInOptions.builder()
+ .authFlowType(AuthFlowType.USER_AUTH)
+ .preferredFirstFactor(AuthFactorType.EMAIL_OTP) // Sign in using Email OTP
+ .build();
+
+// Sign in the user
+RxAmplify.Auth.signIn(
+ username,
+ null, // no password
+ options
+).subscribe(
+ result -> {
+ if (result.getNextStep().getSignInStep() == AuthSignInStep.CONFIRM_SIGN_IN_WITH_OTP) {
+ // Show UI to collect OTP
+ }
+ },
+ error -> Log.e("AuthQuickstart", error.toString())
+)
+
+// Then pass that OTP into the confirmSignIn API
+RxAmplify.Auth.confirmSignIn("123456")
+ .subscribe(
+ result -> {
+ // result.getNextStep().getSignInStep() should be "DONE" now
+ },
+ error -> Log.e("AuthQuickstart", error.toString())
+ );
+```
+
+
+
+Pass `emailOTP` as the `preferredFirstFactor` when calling the `signIn` API in order to initiate a passwordless authentication flow with Email OTP.
+
+#### [Async/Await]
+
+```swift
+// sign in with `emailOTP` as preferred factor
+func signIn(username: String) async {
+ do {
+ let pluginOptions = AWSAuthSignInOptions(
+ authFlowType: .userAuth(preferredFirstFactor: .emailOTP))
+ let signInResult = try await Amplify.Auth.signIn(
+ username: username,
+ options: .init(pluginOptions: pluginOptions))
+ print("Sign in succeeded. Next step: \(signInResult.nextStep)")
+ } catch let error as AuthError {
+ print("Sign in failed \(error)")
+ } catch {
+ print("Unexpected error: \(error)")
+ }
+}
+
+// confirm sign in with the code received
+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)")
+ }
+}
+
+```
+
+#### [Combine]
+
+```swift
+// sign in with `emailOTP` as preferred factor
+func signIn(username: String) -> AnyCancellable {
+ Amplify.Publisher.create {
+ let pluginOptions = AWSAuthSignInOptions(
+ authFlowType: .userAuth(preferredFirstFactor: .emailOTP))
+ try await Amplify.Auth.signIn(
+ username: username,
+ options: .init(pluginOptions: pluginOptions))
+ }.sink {
+ if case let .failure(authError) = $0 {
+ print("Sign in failed \(authError)")
+ }
+ }
+ receiveValue: { signInResult in
+ print("Sign in succeeded. Next step: \(signInResult.nextStep)")
+ }
+}
+
+// confirm sign in with the code received
+func confirmSignIn() -> AnyCancellable {
+ Amplify.Publisher.create {
+ try await Amplify.Auth.confirmSignIn(challengeResponse: "")
+ }.sink {
+ if case let .failure(authError) = $0 {
+ print("Confirm sign in failed \(authError)")
+ }
+ }
+ receiveValue: { signInResult in
+ print("Confirm sign in succeeded. Next step: \(signInResult.nextStep)")
+ }
+}
+```
+
+
+
+### WebAuthn Passkeys
+
+
+Pass `WEB_AUTHN` as the `preferredChallenge` in order to initiate the passwordless authentication flow using a WebAuthn credential.
+
+```ts
+const { nextStep: signInNextStep } = await signIn({
+ username: 'hello@example.com',
+ options: {
+ authFlowType: 'USER_AUTH',
+ preferredChallenge: 'WEB_AUTHN',
+ },
+});
+
+if (signInNextStep.signInStep === 'DONE') {
+ console.log('Sign in successful!');
+}
+```
+
+
+Pass `WEB_AUTHN` as the `preferredFirstFactor` in order to initiate the passwordless authentication flow using a WebAuthn credential. This flow
+completes without any additional interaction from your application, so there is only one `Amplify.Auth` call needed for WebAuthn.
+
+
+The user must have previously associated a credential to use this auth factor. To learn more, visit the [manage WebAuthn credentials page](/[platform]/build-a-backend/auth/manage-users/manage-webauthn-credentials/).
+
+
+
+Amplify requires an `Activity` reference to attach the PassKey UI to your Application's [Task](https://developer.android.com/guide/components/activities/tasks-and-back-stack) when using WebAuthn - if an `Activity` is not supplied then the UI will appear in a separate Task. For this reason, we strongly recommend always passing the `callingActivity` option to both the `signIn` and `confirmSignIn` APIs if your application allows users to sign in with passkeys.
+
+
+#### [Java]
+
+```java
+// Use options to specify the preferred first factor
+AWSCognitoAuthSignInOptions options = AWSCognitoAuthSignInOptions.builder()
+ .authFlowType(AuthFlowType.USER_AUTH)
+ .callingActivity(callingActivity)
+ .preferredFirstFactor(AuthFactorType.WEB_AUTHN) // Sign in using WebAuthn
+ .build();
+
+// Sign in the user
+Amplify.Auth.signIn(
+ username,
+ null, // no password
+ options,
+ result -> Log.i("AuthQuickStart", "Next sign in step: " + result.getNextStep()),
+ error -> Log.e("AuthQuickstart", error.toString())
+);
+```
+
+#### [Kotlin - Callbacks]
+
+```kotlin
+// Use options to specify the preferred first factor
+val options = AWSCognitoAuthSignInOptions.builder()
+ .authFlowType(AuthFlowType.USER_AUTH)
+ .callingActivity(callingActivity)
+ .preferredFirstFactor(AuthFactorType.WEB_AUTHN) // Sign in using WebAuthn
+ .build()
+
+// Sign in the user
+Amplify.Auth.signIn(
+ username,
+ null, // no password
+ options,
+ { result: AuthSignInResult -> Log.i("AuthQuickStart", "Next sign in step: ${result.nextStep}") },
+ { error: AuthException -> Log.e("AuthQuickStart", error.toString()) }
+)
+```
+
+#### [Kotlin - Coroutines]
+
+```kotlin
+// Use options to specify the preferred first factor
+val options = AWSCognitoAuthSignInOptions.builder()
+ .authFlowType(AuthFlowType.USER_AUTH)
+ .callingActivity(callingActivity)
+ .preferredFirstFactor(AuthFactorType.WEB_AUTHN) // Sign in using WebAuthn
+ .build()
+
+// Sign in the user
+val result = Amplify.Auth.signIn(
+ username = username,
+ password = null,
+ options = options
+)
+
+// result.nextStep.signInStep should be "DONE" if use granted access to the passkey
+// NOTE: `signIn` will throw a UserCancelledException if user dismissed the passkey UI
+```
+
+#### [RxJava]
+
+```java
+// Use options to specify the preferred first factor
+AWSCognitoAuthSignInOptions options = AWSCognitoAuthSignInOptions.builder()
+ .authFlowType(AuthFlowType.USER_AUTH)
+ .callingActivity(callingActivity)
+ .preferredFirstFactor(AuthFactorType.WEB_AUTHN) // Sign in using WebAuthn
+ .build();
+
+// Sign in the user
+RxAmplify.Auth.signIn(
+ username,
+ null, // no password
+ options
+).subscribe(
+ result -> Log.i("AuthQuickStart", "Next sign in step: " + result.getNextStep()),
+ error -> Log.e("AuthQuickstart", error.toString())
+)
+```
+
+Using WebAuthn sign in may result in a number of possible exception types.
+
+- `UserCancelledException` - If the user declines to authorize access to the passkey in the system UI. You can retry the WebAuthn flow by invoking `confirmSignIn` again, or restart the `signIn` process to select a different `AuthFactorType`.
+- `WebAuthnNotEnabledException` - This indicates WebAuthn is not enabled in your user pool.
+- `WebAuthnNotSupportedException` - This indicates WebAuthn is not supported on the user's device.
+- `WebAuthnRpMismatchException` - This indicates there is a problem with the `assetlinks.json` file deployed to your relying party.
+- `WebAuthnFailedException` - This exception is used for other errors that may occur with WebAuthn. Inspect the `cause` to determine the best course of action.
+
+
+
+
+Pass `webAuthn` as the `preferredFirstFactor` in order to initiate the passwordless authentication flow using a WebAuthn credential.
+
+#### [Async/Await]
+
+```swift
+// sign in with `webAuthn` as preferred factor
+func signIn(username: String) async {
+ do {
+ let authFactorType : AuthFactorType
+ if #available(iOS 17.4, *) {
+ authFactorType = .webAuthn
+ } else {
+ // Fallback on earlier versions
+ authFactorType = .passwordSRP
+ }
+
+ let signInResult = try await Amplify.Auth.signIn(
+ username: username,
+ options: .init(pluginOptions: AWSAuthSignInOptions(
+ authFlowType: .userAuth(
+ preferredFirstFactor: authFactorType))))
+ print("Sign in succeeded. Next step: \(signInResult.nextStep)")
+ } catch let error as AuthError {
+ print("Sign in failed \(error)")
+ } catch {
+ print("Unexpected error: \(error)")
+ }
+}
+
+```
+
+#### [Combine]
+
+```swift
+// sign in with `webAuthn` as preferred factor
+func signIn(username: String) async {
+ Amplify.Publisher.create {
+ let authFactorType : AuthFactorType
+ if #available(iOS 17.4, *) {
+ authFactorType = .webAuthn
+ } else {
+ // Fallback on earlier versions
+ authFactorType = .passwordSRP
+ }
+
+ try await Amplify.Auth.signIn(
+ username: username,
+ options: .init(pluginOptions: AWSAuthSignInOptions(
+ authFlowType: .userAuth(
+ preferredFirstFactor: authFactorType))))
+ }.sink {
+ if case let .failure(authError) = $0 {
+ print("Sign in failed \(authError)")
+ }
+ }
+ receiveValue: { signInResult in
+ print("Sign in succeeded. Next step: \(signInResult.nextStep)")
+ }
+}
+```
+
+
+
+### Password
+
+
+Pass either `PASSWORD` or `PASSWORD_SRP` as the `preferredChallenge` in order to initiate a traditional password based authentication flow.
+
+```ts
+const { nextStep: signInNextStep } = await signIn({
+ username: 'hello@example.com',
+ password: 'example-password',
+ options: {
+ authFlowType: 'USER_AUTH',
+ preferredChallenge: 'PASSWORD_SRP', // or 'PASSWORD'
+ },
+});
+
+if (confirmSignInNextStep.signInStep === 'DONE') {
+ console.log('Sign in successful!');
+}
+```
+
+
+
+Pass either `PASSWORD` or `PASSWORD_SRP` as the `preferredFirstFactor` in order to initiate a traditional password based authentication flow.
+
+#### [Java]
+
+```java
+// Use options to specify the preferred first factor
+AWSCognitoAuthSignInOptions options = AWSCognitoAuthSignInOptions.builder()
+ .authFlowType(AuthFlowType.USER_AUTH)
+ .preferredFirstFactor(AuthFactorType.PASSWORD) // Sign in using Password
+ .build();
+
+// Sign in the user
+Amplify.Auth.signIn(
+ username,
+ password, // supply the password if preferredFirstFactor is PASSWORD or PASSWORD_SRP
+ options,
+ result -> Log.i("AuthQuickStart", "Next sign in step: " + result.getNextStep()),
+ error -> Log.e("AuthQuickstart", error.toString())
+);
+```
+
+#### [Kotlin - Callbacks]
+
+```kotlin
+// Use options to specify the preferred first factor
+val options = AWSCognitoAuthSignInOptions.builder()
+ .authFlowType(AuthFlowType.USER_AUTH)
+ .preferredFirstFactor(AuthFactorType.PASSWORD) // Sign in using Password
+ .build()
+
+// Sign in the user
+Amplify.Auth.signIn(
+ username,
+ password, // supply the password if preferredFirstFactor is PASSWORD or PASSWORD_SRP
+ options,
+ { result: AuthSignInResult -> Log.i("AuthQuickStart", "Next sign in step: ${result.nextStep}") },
+ { error: AuthException -> Log.e("AuthQuickstart", error.toString()) }
+)
+```
+
+#### [Kotlin - Coroutines]
+
+```kotlin
+// Use options to specify the preferred first factor
+val options = AWSCognitoAuthSignInOptions.builder()
+ .authFlowType(AuthFlowType.USER_AUTH)
+ .preferredFirstFactor(AuthFactorType.PASSWORD) // Sign in using Password
+ .build()
+
+// Sign in the user
+val result = Amplify.Auth.signIn(
+ username = username,
+ password = password, // supply the password if preferredFirstFactor is PASSWORD or PASSWORD_SRP
+ options = options
+)
+
+// result.nextStep.signInStep should be "DONE"
+```
+
+#### [RxJava]
+
+```java
+// Use options to specify the preferred first factor
+AWSCognitoAuthSignInOptions options = AWSCognitoAuthSignInOptions.builder()
+ .authFlowType(AuthFlowType.USER_AUTH)
+ .preferredFirstFactor(AuthFactorType.Password) // Sign in using Password
+ .build();
+
+// Sign in the user
+RxAmplify.Auth.signIn(
+ username,
+ password, // supply the password if preferredFirstFactor is PASSWORD or PASSWORD_SRP
+ options
+).subscribe(
+ result -> Log.i("AuthQuickStart", "Next sign in step: " + result.getNextStep()),
+ error -> Log.e("AuthQuickstart", error.toString())
+)
+```
+
+
+
+Pass either `password` or `passwordSRP` as the `preferredFirstFactor` in order to initiate a traditional password based authentication flow.
+
+#### [Async/Await]
+
+```swift
+// sign in with `password` as preferred factor
+func signIn(username: String) async {
+ do {
+ let pluginOptions = AWSAuthSignInOptions(
+ authFlowType: .userAuth(preferredFirstFactor: .password))
+ let signInResult = try await Amplify.Auth.signIn(
+ username: username,
+ options: .init(pluginOptions: pluginOptions))
+ print("Sign in succeeded. Next step: \(signInResult.nextStep)")
+ } catch let error as AuthError {
+ print("Sign in failed \(error)")
+ } catch {
+ print("Unexpected error: \(error)")
+ }
+}
+
+```
+
+#### [Combine]
+
+```swift
+// sign in with `password` as preferred factor
+func signIn(username: String) async {
+ Amplify.Publisher.create {
+ let pluginOptions = AWSAuthSignInOptions(
+ authFlowType: .userAuth(preferredFirstFactor: .password))
+ try await Amplify.Auth.signIn(
+ username: username,
+ options: .init(pluginOptions: pluginOptions))
+ }.sink {
+ if case let .failure(authError) = $0 {
+ print("Sign in failed \(authError)")
+ }
+ }
+ receiveValue: { signInResult in
+ print("Sign in succeeded. Next step: \(signInResult.nextStep)")
+ }
+}
+```
+
+
+
+### First Factor Selection
+
+
+Omit the `preferredChallenge` parameter to discover which first factors are available for a given user. This is useful to allow
+users to choose how they would like to sign in.
+
+The `confirmSignIn` API can then be used to select a challenge and initiate the associated authentication flow.
+
+```ts
+const { nextStep: signInNextStep } = await signIn({
+ username: '+15551234567',
+ options: {
+ authFlowType: 'USER_AUTH',
+ },
+});
+
+if (
+ signInNextStep.signInStep === 'CONTINUE_SIGN_IN_WITH_FIRST_FACTOR_SELECTION'
+) {
+ // present user with list of available challenges
+ console.log(`Available Challenges: ${signInNextStep.availableChallenges}`);
+
+ // respond with user selection using `confirmSignIn` API
+ const { nextStep: nextConfirmSignInStep } = await confirmSignIn({
+ challengeResponse: 'SMS_OTP', // or 'EMAIL_OTP', 'WEB_AUTHN', 'PASSWORD', 'PASSWORD_SRP'
+ });
+}
+
+```
+
+
+
+Omit the `preferredFirstFactor` option to discover which first factors are available for a given user. This is useful to allow
+users to choose how they would like to sign in.
+
+The `confirmSignIn` API can then be used to select a challenge and initiate the associated authentication flow.
+
+#### [Java]
+
+```java
+// Omit preferredFirstFactor. If the user has more than one factor available then
+// the next step will be CONTINUE_SIGN_IN_WITH_FIRST_FACTOR_SELECTION.
+AuthSignInOptions options = AWSCognitoAuthSignInOptions.builder()
+ .authFlowType(AuthFlowType.USER_AUTH)
+ .build();
+
+// Step 1: Sign in the user
+Amplify.Auth.signIn(
+ "hello@example.com",
+ null,
+ options,
+ result -> {
+ if (result.getNextStep().getSignInStep() == AuthSignInStep.CONTINUE_SIGN_IN_WITH_FIRST_FACTOR_SELECTION) {
+ Log.i(
+ "AuthQuickstart",
+ "Available authentication factors for this user: " + result.getNextStep().getAvailableFactors()
+ );
+ }
+ },
+ error -> Log.e("AuthQuickstart", error.toString())
+);
+
+// Step 2: Select SMS OTP for sign in
+Amplify.Auth.confirmSignIn(
+ AuthFactorType.SMS_OTP.getChallengeResponse(),
+ result -> {
+ if (result.getNextStep().getSignInStep() == AuthSignInStep.CONFIRM_SIGN_IN_WITH_OTP) {
+ Log.i(
+ "AuthQuickStart",
+ "OTP code sent to " + result.getNextStep().getCodeDeliveryDetails()
+ )
+ // Show UI to collect OTP
+ }
+ },
+ error -> Log.e("AuthQuickstart", error.toString())
+);
+
+// Step 3: Then pass that OTP into the confirmSignIn API
+Amplify.Auth.confirmSignIn(
+ "123456",
+ result -> {
+ // result.getNextStep().getSignInStep() should be "DONE" now
+ },
+ error -> Log.e("AuthQuickstart", error.toString())
+);
+```
+
+#### [Kotlin - Callbacks]
+
+```kotlin
+// Omit preferredFirstFactor. If the user has more than one factor available then
+// the next step will be CONTINUE_SIGN_IN_WITH_FIRST_FACTOR_SELECTION.
+val options: AuthSignInOptions = AWSCognitoAuthSignInOptions.builder()
+ .authFlowType(AuthFlowType.USER_AUTH)
+ .build()
+
+// Step 1: Sign in the user
+Amplify.Auth.signIn(
+ "hello@example.com",
+ null,
+ options,
+ { result: AuthSignInResult ->
+ if (result.nextStep.signInStep == AuthSignInStep.CONTINUE_SIGN_IN_WITH_FIRST_FACTOR_SELECTION) {
+ Log.i(
+ "AuthQuickstart",
+ "Available authentication factors for this user: ${result.nextStep.availableFactors}"
+ )
+ }
+ },
+ { error: AuthException -> Log.e("AuthQuickstart", error.toString()) }
+)
+
+// Step 2: Select SMS OTP for sign in
+Amplify.Auth.confirmSignIn(
+ AuthFactorType.SMS_OTP.getChallengeResponse(),
+ { result: AuthSignInResult ->
+ if (result.nextStep.signInStep == AuthSignInStep.CONFIRM_SIGN_IN_WITH_OTP) {
+ Log.i(
+ "AuthQuickStart",
+ "OTP code sent to ${result.nextStep.codeDeliveryDetails}"
+ )
+ // Show UI to collect OTP
+ }
+ },
+ { error: AuthException -> Log.e("AuthQuickstart", error.toString()) }
+)
+
+// Step 3: Then pass that OTP into the confirmSignIn API
+Amplify.Auth.confirmSignIn(
+ "123456",
+ { result: AuthSignInResult? ->
+ // result.nextStep.signInStep should be "DONE" now
+ },
+ { error: AuthException -> Log.e("AuthQuickstart", error.toString()) }
+)
+```
+
+#### [Kotlin - Coroutines]
+
+```kotlin
+// Omit preferredFirstFactor. If the user has more than one factor available then
+// the next step will be CONTINUE_SIGN_IN_WITH_FIRST_FACTOR_SELECTION.
+val options: AuthSignInOptions = AWSCognitoAuthSignInOptions.builder()
+ .authFlowType(AuthFlowType.USER_AUTH)
+ .build()
+
+// Step 1: Sign in the user
+val result = Amplify.Auth.signIn(
+ username = "hello@example.com",
+ password = null,
+ options = options
+)
+
+if (result.nextStep.signInStep == AuthSignInStep.CONTINUE_SIGN_IN_WITH_FIRST_FACTOR_SELECTION) {
+ Log.i(
+ "AuthQuickStart",
+ "Available authentication factors for this user: ${result.nextStep.availableFactors}"
+ )
+}
+
+// Step 2: Select SMS OTP for sign in
+val selectFactorResult = Amplify.Auth.confirmSignIn(challengeResponse = AuthFactorType.SMS_OTP.challengeResponse)
+
+if (result.nextStep.signInStep == AuthSignInStep.CONFIRM_SIGN_IN_WITH_OTP) {
+ Log.i(
+ "AuthQuickStart",
+ "OTP code sent to ${result.nextStep.codeDeliveryDetails}"
+ )
+ // Show UI to collect OTP
+}
+
+// Step 3: Then pass that OTP into the confirmSignIn API
+val confirmResult = Amplify.Auth.confirmSignIn(challengeResponse = "123456")
+
+// confirmResult.nextStep.signInStep should be "DONE" now
+```
+
+#### [RxJava]
+
+```java
+// Omit preferredFirstFactor. If the user has more than one factor available then
+// the next step will be CONTINUE_SIGN_IN_WITH_FIRST_FACTOR_SELECTION.
+AWSCognitoAuthSignInOptions options = AWSCognitoAuthSignInOptions.builder()
+ .authFlowType(AuthFlowType.USER_AUTH)
+ .build();
+
+// Step 1: Sign in the user
+RxAmplify.Auth.signIn(
+ username,
+ null, // no password
+ options
+).subscribe(
+ result -> {
+ if (result.getNextStep().getSignInStep() == AuthSignInStep.CONTINUE_SIGN_IN_WITH_FIRST_FACTOR_SELECTION) {
+ Log.i(
+ "AuthQuickstart",
+ "Available authentication factors for this user: " + result.getNextStep().getAvailableFactors()
+ );
+ }
+ },
+ error -> Log.e("AuthQuickstart", error.toString())
+)
+
+// Step 2: Select SMS OTP for sign in
+RxAmplify.Auth.confirmSignIn(AuthFactorType.SMS_OTP.getChallengeResponse())
+ .subscribe(
+ result -> {
+ if (result.getNextStep().getSignInStep() == AuthSignInStep.CONFIRM_SIGN_IN_WITH_OTP) {
+ Log.i(
+ "AuthQuickStart",
+ "OTP code sent to " + result.getNextStep().getCodeDeliveryDetails()
+ )
+ // Show UI to collect OTP
+ }
+ },
+ error -> Log.e("AuthQuickstart", error.toString())
+ );
+
+// Step 3: Then pass that OTP into the confirmSignIn API
+RxAmplify.Auth.confirmSignIn("123456")
+ .subscribe(
+ result -> {
+ // result.getNextStep().getSignInStep() should be "DONE" now
+ },
+ error -> Log.e("AuthQuickstart", error.toString())
+ );
+```
+
+
+
+Omit the `preferredFirstFactor` parameter to discover which first factors are available for a given user. This is useful to allow
+users to choose how they would like to sign in.
+
+The `confirmSignIn` API can then be used to select a challenge and initiate the associated authentication flow.
+
+#### [Async/Await]
+
+```swift
+// Step 1: Initiate UserAuth Sign-In
+let pluginOptions = AWSAuthSignInOptions(authFlowType: .userAuth)
+let signInResult = try await Amplify.Auth.signIn(
+ username: "user@example.com",
+ options: .init(pluginOptions: pluginOptions)
+)
+
+switch signInResult.nextStep {
+case .continueSignInWithFirstFactorSelection(let availableFactors):
+ print("Available factors to select: \(availableFactors)")
+ // Prompt the user to select a first factor
+default:
+ break
+}
+
+// Step 2: Select Authentication Factor
+let confirmSignInResult = try await Amplify.Auth.confirmSignIn(
+ challengeResponse: AuthFactorType.emailOTP.challengeResponse
+)
+
+switch confirmSignInResult.nextStep {
+case .confirmSignInWithOTP(let deliveryDetails):
+ print("Delivery details: \(deliveryDetails)")
+ // Prompt the user to enter email OTP code received
+default:
+ break
+}
+
+// Step 3: Complete Sign-In with OTP Code
+let finalSignInResult = try await Amplify.Auth.confirmSignIn(
+ challengeResponse: ""
+)
+
+if case .done = finalSignInResult.nextStep {
+ print("Login successful")
+}
+```
+
+#### [Combine]
+
+```swift
+func signInWithUserAuth(username: String, getOTP: @escaping () async -> String) -> AnyCancellable {
+ Amplify.Publisher.create {
+ // Step 1: Initiate UserAuth Sign-In
+ let pluginOptions = AWSAuthSignInOptions(authFlowType: .userAuth)
+ let signInResult = try await Amplify.Auth.signIn(
+ username: username,
+ options: .init(pluginOptions: pluginOptions)
+ )
+
+ // Step 2: Handle factor selection
+ if case .continueSignInWithFirstFactorSelection(let availableFactors) = signInResult.nextStep {
+ print("Available factors to select: \(availableFactors)")
+
+ // For this example, we select emailOTP. You could prompt the user here.
+ let confirmSignInResult = try await Amplify.Auth.confirmSignIn(
+ challengeResponse: AuthFactorType.emailOTP.challengeResponse
+ )
+
+ // Step 3: Handle OTP delivery
+ if case .confirmSignInWithOTP(let deliveryDetails) = confirmSignInResult.nextStep {
+ print("Delivery details: \(deliveryDetails)")
+
+ // Prompt user for OTP code (async closure)
+ let code = await getOTP()
+
+ // Step 4: Complete sign-in with OTP code
+ let finalSignInResult = try await Amplify.Auth.confirmSignIn(
+ challengeResponse: code
+ )
+
+ return finalSignInResult
+ } else {
+ // Handle other next steps if needed
+ return confirmSignInResult
+ }
+ } else {
+ // Handle other next steps or immediate sign-in
+ return signInResult
+ }
+ }
+ .sink(
+ receiveCompletion: { completion in
+ if case let .failure(authError) = completion {
+ print("Sign in failed: \(authError)")
+ }
+ },
+ receiveValue: { result in
+ if result.isSignedIn || (result.nextStep == .done) {
+ print("Sign in succeeded")
+ } else {
+ print("Next step: \(result.nextStep)")
+ }
+ }
+ )
+}
+```
+
+
+
+---
+
+---
+title: "Switching authentication flows"
+section: "build-a-backend/auth/connect-your-frontend"
+platforms: ["angular", "javascript", "nextjs", "react", "react-native", "swift", "vue", "android"]
+gen: 2
+last-updated: "2024-12-09T19:54:14.000Z"
+url: "https://docs.amplify.aws/react/build-a-backend/auth/connect-your-frontend/switching-authentication-flows/"
+---
+
+
+`AWSCognitoAuthPlugin` allows you to switch between different auth flows while initiating signIn. You can configure the flow in the `amplify_outputs.json` file or pass the `authFlowType` as a runtime parameter to the `signIn` api call.
+
+For client side authentication there are four different flows that can be configured during runtime:
+
+1. `userSRP`: The `userSRP` flow uses the [SRP protocol (Secure Remote Password)](https://en.wikipedia.org/wiki/Secure_Remote_Password_protocol) where the password never leaves the client and is unknown to the server. This is the recommended flow and is used by default.
+
+2. `userPassword`: The `userPassword` flow will send user credentials unencrypted to the back-end. If you want to migrate users to Cognito using the "Migration" trigger and avoid forcing users to reset their passwords, you will need to use this authentication type because the Lambda function invoked by the trigger needs to verify the supplied credentials.
+
+3. `customWithSRP`: The `customWithSRP` flow is used to start with SRP authentication and then switch to custom authentication. This is useful if you want to use SRP for the initial authentication and then use custom authentication for subsequent authentication attempts.
+
+4. `customWithoutSRP`: The `customWithoutSRP` flow is used to start authentication flow **WITHOUT** SRP and then use a series of challenge and response cycles that can be customized to meet different requirements.
+
+5. `userAuth`: The `userAuth` flow is a choice-based authentication flow that allows the user to choose from the list of available authentication methods. This flow is useful when you want to provide the user with the option to choose the authentication method. The choices that may be available to the user are `emailOTP`, `smsOTP`, `webAuthn`, `password` or `passwordSRP`.
+
+`Auth` can be configured to use the different flows at runtime by calling `signIn` with `AuthSignInOptions`'s `authFlowType` as `AuthFlowType.userPassword`, `AuthFlowType.customAuthWithoutSrp` or `AuthFlowType.customAuthWithSrp`. If you do not specify the `AuthFlowType` in `AuthSignInOptions`, the default flow (`AuthFlowType.userSRP`) will be used.
+
+
+
+Runtime configuration will take precedence and will override any auth flow type configuration present in amplify_outputs.json
+
+
+
+> For more information about authentication flows, please visit [Amazon Cognito developer documentation](https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-authentication-flow.html#amazon-cognito-user-pools-custom-authentication-flow)
+
+## USER_AUTH (Choice-based authentication) flow
+
+A use case for the `USER_AUTH` authentication flow is to provide the user with the option to choose the authentication method. The choices that may be available to the user are `emailOTP`, `smsOTP`, `webAuthn`, `password` or `passwordSRP`.
+
+```swift
+let pluginOptions = AWSAuthSignInOptions(
+ authFlowType: .userAuth)
+let signInResult = try await Amplify.Auth.signIn(
+ username: username,
+ password: password,
+ options: .init(pluginOptions: pluginOptions))
+guard case .continueSignInWithFirstFactorSelection(let availableFactors) = signInResult.nextStep else {
+ return
+}
+print("Available factors: \(availableFactors)")
+```
+
+The selection of the authentication method is done by the user. The user can choose from the available factors and proceed with the selected factor. You should call the `confirmSignIn` API with the selected factor to continue the sign-in process. Following is an example if you want to proceed with the `emailOTP` factor selection:
+
+```swift
+// Select emailOTP as the factor
+var confirmSignInResult = try await Amplify.Auth.confirmSignIn(
+ challengeResponse: AuthFactorType.emailOTP.challengeResponse)
+```
+
+## USER_PASSWORD_AUTH flow
+
+A use case for the `USER_PASSWORD_AUTH` authentication flow is migrating users into Amazon Cognito
+
+A user migration Lambda trigger helps migrate users from a legacy user management system into your user pool. If you choose the USER_PASSWORD_AUTH authentication flow, users don't have to reset their passwords during user migration. This flow sends your user's password to the service over an encrypted SSL connection during authentication.
+
+When you have migrated all your users, switch flows to the more secure SRP flow. The SRP flow doesn't send any passwords over the network.
+
+```swift
+func signIn(username: String, password: String) async throws {
+
+ let option = AWSAuthSignInOptions(authFlowType: .userPassword)
+ do {
+ let result = try await Amplify.Auth.signIn(
+ username: username,
+ password: password,
+ options: AuthSignInRequest.Options(pluginOptions: option))
+ print("Sign in succeeded with result: \(result)")
+ } catch {
+ print("Failed to sign in with error: \(error)")
+ }
+}
+```
+
+### Migrate users with Amazon Cognito
+
+Amazon Cognito provides a trigger to migrate users from your existing user directory seamlessly into Cognito. You achieve this by configuring your User Pool's "Migration" trigger which invokes a Lambda function whenever a user that does not already exist in the user pool authenticates, or resets their password.
+
+In short, the Lambda function will validate the user credentials against your existing user directory and return a response object containing the user attributes and status on success. An error message will be returned if an error occurs. There's documentation around [how to set up this migration flow](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-import-using-lambda.html) and more detailed instructions on [how the lambda should handle request and response objects](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-migrate-user.html#cognito-user-pools-lambda-trigger-syntax-user-migration).
+
+## CUSTOM_AUTH flow
+
+Amazon Cognito User Pools supports customizing the authentication flow to enable custom challenge types, in addition to a password in order to verify the identity of users. The custom authentication flow is a series of challenge and response cycles that can be customized to meet different requirements. These challenge types may include CAPTCHAs or dynamic challenge questions.
+
+To define your challenges for custom authentication flow, you need to implement three Lambda triggers for Amazon Cognito.
+
+The flow is initiated by calling `signIn` with `AuthSignInOptions` configured with `AuthFlowType.customAuthWithSrp` OR `AuthFlowType.customAuthWithoutSrp`.
+
+Follow the instructions in [Custom Auth Sign In](/gen1/[platform]/build-a-backend/auth/sign-in-custom-flow/) to learn about how to integrate custom authentication flow in your application with the Auth APIs.
+
+
+
+For client side authentication there are four different flows:
+
+1. `USER_SRP_AUTH`: The `USER_SRP_AUTH` flow uses the [SRP protocol (Secure Remote Password)](https://en.wikipedia.org/wiki/Secure_Remote_Password_protocol) where the password never leaves the client and is unknown to the server. This is the recommended flow and is used by default.
+
+2. `USER_PASSWORD_AUTH`: The `USER_PASSWORD_AUTH` flow will send user credentials to the backend without applying SRP encryption. If you want to migrate users to Cognito using the "Migration" trigger and avoid forcing users to reset their passwords, you will need to use this authentication type because the Lambda function invoked by the trigger needs to verify the supplied credentials.
+
+3. `CUSTOM_WITH_SRP` & `CUSTOM_WITHOUT_SRP`: Allows for a series of challenge and response cycles that can be customized to meet different requirements.
+
+4. `USER_AUTH`: The `USER_AUTH` flow is a choice-based authentication flow that allows the user to choose from the list of available authentication methods. This flow is useful when you want to provide the user with the option to choose the authentication method. The choices that may be available to the user are `EMAIL_OTP`, `SMS_OTP`, `WEB_AUTHN`, `PASSWORD` or `PASSWORD_SRP`.
+
+The Auth flow can be customized when calling `signIn`, for example:
+
+```ts title="src/main.ts"
+await signIn({
+ username: "hello@mycompany.com",
+ password: "hunter2",
+ options: {
+ authFlowType: 'USER_AUTH'
+ }
+})
+```
+
+> For more information about authentication flows, please visit [AWS Cognito developer documentation](https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-authentication-flow.html#amazon-cognito-user-pools-custom-authentication-flow)
+
+## USER_AUTH flow
+
+The `USER_AUTH` sign in flow supports the following methods as first factors for authentication: `WEB_AUTHN`, `EMAIL_OTP`, `SMS_OTP`, `PASSWORD`, and `PASSWORD_SRP`.
+
+If the desired first factor is known when authentication is initiated, it can be passed to the `signIn` API as the `preferredChallenge` to initiate the corresponding authentication flow.
+
+```ts
+// PASSWORD_SRP / PASSWORD
+// sign in with preferred challenge as password
+// note password must be provided in same step
+const { nextStep } = await signIn({
+ username: "hello@mycompany.com",
+ password: "hunter2",
+ options: {
+ authFlowType: "USER_AUTH",
+ preferredChallenge: "PASSWORD_SRP" // or "PASSWORD"
+ },
+});
+
+// WEB_AUTHN / EMAIL_OTP / SMS_OTP
+// sign in with preferred passwordless challenge
+// no additional user input required at this step
+const { nextStep } = await signIn({
+ username: "hello@example.com",
+ options: {
+ authFlowType: "USER_AUTH",
+ preferredChallenge: "WEB_AUTHN" // or "EMAIL_OTP" or "SMS_OTP"
+ },
+});
+```
+
+If the desired first factor is not known or you would like to provide users with the available options, `preferredChallenge` can be omitted from the initial `signIn` API call.
+
+This allows you to discover which authentication first factors are available for a user via the `CONTINUE_SIGN_IN_WITH_FIRST_FACTOR_SELECTION` step. You can then present the available options to the user and use the `confirmSignIn` API to respond with the user's selection.
+
+```ts
+const { nextStep: signInNextStep } = await signIn({
+ username: '+15551234567',
+ options: {
+ authFlowType: 'USER_AUTH',
+ },
+});
+
+if (
+ signInNextStep.signInStep === 'CONTINUE_SIGN_IN_WITH_FIRST_FACTOR_SELECTION'
+) {
+ // present user with list of available challenges
+ console.log(`Available Challenges: ${signInNextStep.availableChallenges}`);
+
+ // respond with user selection using `confirmSignIn` API
+ const { nextStep: nextConfirmSignInStep } = await confirmSignIn({
+ challengeResponse: 'SMS_OTP', // or 'EMAIL_OTP', 'WEB_AUTHN', 'PASSWORD', 'PASSWORD_SRP'
+ });
+}
+
+```
+Also, note that if the `preferredChallenge` passed to the initial `signIn` API call is unavailable for the user, Amplify will also respond with the `CONTINUE_SIGN_IN_WITH_FIRST_FACTOR_SELECTION` next step.
+
+
+For more information about determining a first factor, and signing in with passwordless authentication factors, please visit the [Passwordless](/[platform]/build-a-backend/auth/concepts/passwordless/) concepts page.
+
+
+## USER_PASSWORD_AUTH flow
+
+A use case for the `USER_PASSWORD_AUTH` authentication flow is migrating users into Amazon Cognito
+
+### Set up auth backend
+
+In order to use the authentication flow `USER_PASSWORD_AUTH`, your Cognito app client has to be configured to allow it. In the AWS Console, this is done by ticking the checkbox at General settings > App clients > Show Details (for the affected client) > Enable username-password (non-SRP) flow. If you're using the AWS CLI or CloudFormation, update your app client by adding `USER_PASSWORD_AUTH` to the list of "Explicit Auth Flows".
+
+### Migrate users with Amazon Cognito
+
+Amazon Cognito provides a trigger to migrate users from your existing user directory seamlessly into Cognito. You achieve this by configuring your User Pool's "Migration" trigger which invokes a Lambda function whenever a user that does not already exist in the user pool authenticates, or resets their password.
+
+In short, the Lambda function will validate the user credentials against your existing user directory and return a response object containing the user attributes and status on success. An error message will be returned if an error occurs. Visit [Amazon Cognito user pools import guide](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-import-using-lambda.html) for migration flow and more detailed instruction, and [Amazon Cognito Lambda trigger guide](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-migrate-user.html#cognito-user-pools-lambda-trigger-syntax-user-migration) on how to set up lambda to handle request and response objects.
+
+## `CUSTOM_WITH_SRP` & `CUSTOM_WITHOUT_SRP` flows
+
+Amazon Cognito user pools supports customizing the authentication flow to enable custom challenge types,
+in addition to a password in order to verify the identity of users. These challenge types may include CAPTCHAs
+or dynamic challenge questions. The `CUSTOM_WITH_SRP` flow requires a password when calling `signIn`. Both of
+these flows map to the `CUSTOM_AUTH` flow in Cognito.
+
+
+
+To define your challenges for custom authentication flow, you need to implement three Lambda triggers for Amazon Cognito. Please visit [AWS Amplify Custom Auth Challenge example](/[platform]/build-a-backend/functions/examples/custom-auth-flows/) for set up instructions.
+
+
+
+
+
+For more information about working with Lambda Triggers for custom authentication challenges, please visit [Amazon Cognito Developer Documentation](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-challenge.html).
+
+
+
+### Custom authentication flow
+
+To initiate a custom authentication flow in your app, call `signIn` without a password. A custom challenge needs to be answered using the `confirmSignIn` API:
+
+```ts title="src/main.ts"
+import { signIn, confirmSignIn } from 'aws-amplify/auth';
+
+const challengeResponse = 'the answer for the challenge';
+
+const { nextStep } = await signIn({
+ username,
+ options: {
+ authFlowType: 'CUSTOM_WITHOUT_SRP',
+ },
+});
+
+if (nextStep.signInStep === 'CONFIRM_SIGN_IN_WITH_CUSTOM_CHALLENGE') {
+ // to send the answer of the custom challenge
+ await confirmSignIn({ challengeResponse });
+}
+```
+
+### CAPTCHA authentication
+
+To create a CAPTCHA challenge with a Lambda Trigger, please visit [AWS Amplify Google reCAPTCHA challenge example](/[platform]/build-a-backend/functions/examples/google-recaptcha-challenge/) for detailed examples.
+
+
+
+`AWSCognitoAuthPlugin` allows you to switch between different auth flows while initiating signIn. You can configure the flow in the `amplify_outputs.json` file or pass the `authFlowType` as a option to the `signIn` api call.
+
+For client side authentication there are four different flows that can be configured during runtime:
+
+1. `USER_SRP_AUTH`: The `USER_SRP_AUTH` flow uses the [SRP protocol (Secure Remote Password)](https://en.wikipedia.org/wiki/Secure_Remote_Password_protocol) where the password never leaves the client and is unknown to the server. This is the recommended flow and is used by default.
+
+2. `USER_PASSWORD_AUTH`: The `USER_PASSWORD_AUTH` flow will send user credentials unencrypted to the back-end. If you want to migrate users to Cognito using the "Migration" trigger and avoid forcing users to reset their passwords, you will need to use this authentication type because the Lambda function invoked by the trigger needs to verify the supplied credentials.
+
+3. `CUSTOM_AUTH_WITH_SRP`: The `CUSTOM_AUTH_WITH_SRP` flow is used to start with SRP authentication and then switch to custom authentication. This is useful if you want to use SRP for the initial authentication and then use custom authentication for subsequent authentication attempts.
+
+4. `CUSTOM_AUTH_WITHOUT_SRP`: The `CUSTOM_AUTH_WITHOUT_SRP` flow is used to start authentication flow **WITHOUT** SRP and then use a series of challenge and response cycles that can be customized to meet different requirements.
+
+5. `USER_AUTH`: The `USER_AUTH` flow is a choice-based authentication flow that allows the user to choose from the list of available authentication methods. This flow is useful when you want to provide the user with the option to choose the authentication method. The choices that may be available to the user are `EMAIL_OTP`, `SMS_OTP`, `WEB_AUTHN`, `PASSWORD` or `PASSWORD_SRP`.
+
+`Auth` can be configured to use the different flows at runtime by calling `signIn` with `AWSCognitoAuthSignInOptions`'s `authFlowType` as `AuthFlowType.USER_PASSWORD_AUTH`, `AuthFlowType.CUSTOM_AUTH_WITHOUT_SRP`, `AuthFlowType.CUSTOM_AUTH_WITH_SRP`, or `AuthFlowType.USER_AUTH`. If you do not specify the `AuthFlowType` in `AWSCognitoAuthSignInOptions`, the default flow specified in `amplify_outputs.json` will be used.
+
+
+
+Runtime configuration will take precedence and will override any auth flow type configuration present in `amplify_outputs.json`.
+
+
+
+For more information about authentication flows, please visit [Amazon Cognito developer documentation](https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-authentication-flow.html#amazon-cognito-user-pools-custom-authentication-flow)
+
+## USER_AUTH (Choice-based authentication) flow
+
+A use case for the `USER_AUTH` authentication flow is to provide the user with the option to choose the authentication method. The choices that may be available to the user are `EMAIL_OTP`, `SMS_OTP`, `WEB_AUTHN`, `PASSWORD` or `PASSWORD_SRP`.
+
+
+Amplify requires an `Activity` reference to attach the PassKey UI to your Application's [Task](https://developer.android.com/guide/components/activities/tasks-and-back-stack) when using WebAuthn - if an `Activity` is not supplied then the UI will appear in a separate Task. For this reason, we strongly recommend passing the `callingActivity` option to both the `signIn` and `confirmSignIn` APIs if your application uses the `USER_AUTH` flow.
+
+
+If the desired first factor is known before the sign in flow is initiated it can be passed to the initial sign in call.
+
+#### [Java]
+
+```java
+// PASSWORD_SRP / PASSWORD
+// Sign in with preferred challenge as password
+// NOTE: Password must be provided in the same step
+AuthSignInOptions options = AWSCognitoAuthSignInOptions.builder()
+ .callingActivity(activity)
+ .authFlowType(AuthFlowType.USER_AUTH)
+ .preferredFirstFactor(AuthFactorType.PASSWORD_SRP) // or "PASSWORD"
+ .build();
+Amplify.Auth.signIn(
+ username,
+ password,
+ options,
+ result -> Log.i("AuthQuickStart", "Next step for sign in is " + result.getNextStep()),
+ error -> Log.e("AuthQuickStart", "Failed to confirm sign in", error)
+);
+
+// WEB_AUTHN / EMAIL_OTP / SMS_OTP
+// Sign in with preferred passwordless challenge
+// No user input is required at this step
+AuthSignInOptions options = AWSCognitoAuthSignInOptions.builder()
+ .callingActivity(activity)
+ .authFlowType(AuthFlowType.USER_AUTH)
+ .preferredFirstFactor(AuthFactorType.WEB_AUTHN) // or "EMAIL_OTP" or "SMS_OTP"
+ .build();
+Amplify.Auth.signIn(
+ username,
+ null,
+ options,
+ result -> Log.i("AuthQuickStart", "Next step for sign in is " + result.getNextStep()),
+ error -> Log.e("AuthQuickStart", "Failed to confirm sign in", error)
+);
+```
+
+#### [Kotlin - Callbacks]
+
+```kotlin
+// PASSWORD_SRP / PASSWORD
+// Sign in with preferred challenge as password
+// NOTE: Password must be provided in the same step
+val options = AWSCognitoAuthSignInOptions.builder()
+ .callingActivity(activity)
+ .authFlowType(AuthFlowType.USER_AUTH)
+ .preferredFirstFactor(AuthFactorType.PASSWORD_SRP) // or "PASSWORD"
+ .build()
+Amplify.Auth.signIn(
+ username,
+ password,
+ options,
+ { result -> Log.i("AuthQuickStart", "Next step for sign in is ${result.nextStep}") },
+ { error -> Log.e("AuthQuickStart", "Failed to confirm sign in", error) }
+)
+
+// WEB_AUTHN / EMAIL_OTP / SMS_OTP
+// Sign in with preferred passwordless challenge
+// No user input is required at this step
+val options = AWSCognitoAuthSignInOptions.builder()
+ .callingActivity(activity)
+ .authFlowType(AuthFlowType.USER_AUTH)
+ .preferredFirstFactor(AuthFactorType.WEB_AUTHN) // or "EMAIL_OTP" or "SMS_OTP"
+ .build()
+Amplify.Auth.signIn(
+ username,
+ null,
+ options,
+ { result -> Log.i("AuthQuickStart", "Next step for sign in is ${result.nextStep}") },
+ { error -> Log.e("AuthQuickStart", "Failed to confirm sign in", error) }
+)
+```
+
+#### [Kotlin - Coroutines]
+
+```kotlin
+// PASSWORD_SRP / PASSWORD
+// Sign in with preferred challenge as password
+// NOTE: Password must be provided in the same step
+try {
+ val options = AWSCognitoAuthSignInOptions.builder()
+ .callingActivity(activity)
+ .authFlowType(AuthFlowType.USER_AUTH)
+ .preferredFirstFactor(AuthFactorType.PASSWORD_SRP) // or "PASSWORD"
+ .build()
+ val result = Amplify.Auth.signIn(
+ username = "hello@example.com",
+ password = "password",
+ options = options
+ )
+ Log.i("AuthQuickstart", "Next step for sign in is ${result.nextStep}")
+} catch (error: AuthException) {
+ Log.e("AuthQuickstart", "Sign in failed", error)
+}
+
+// WEB_AUTHN / EMAIL_OTP / SMS_OTP
+// Sign in with preferred passwordless challenge
+// No user input is required at this step
+try {
+ val options = AWSCognitoAuthSignInOptions.builder()
+ .callingActivity(activity)
+ .authFlowType(AuthFlowType.USER_AUTH)
+ .preferredFirstFactor(AuthFactorType.WEB_AUTHN) // or "EMAIL_OTP" or "SMS_OTP"
+ .build()
+ val result = Amplify.Auth.signIn(
+ username = "hello@example.com",
+ password = null,
+ options = options
+ )
+ Log.i("AuthQuickstart", "Next step for sign in is ${result.nextStep}")
+} catch (error: AuthException) {
+ Log.e("AuthQuickstart", "Sign in failed", error)
+}
+```
+
+#### [RxJava]
+
+```java
+// PASSWORD_SRP / PASSWORD
+// Sign in with preferred challenge as password
+// NOTE: Password must be provided in the same step
+AuthSignInOptions options = AWSCognitoAuthSignInOptions.builder()
+ .callingActivity(activity)
+ .authFlowType(AuthFlowType.USER_AUTH)
+ .preferredFirstFactor(AuthFactorType.PASSWORD_SRP) // or "PASSWORD"
+ .build();
+RxAmplify.Auth.signIn(username, password, options)
+ .subscribe(
+ result -> Log.i("AuthQuickstart", "Next step for sign in is " + result.getNextStep()),
+ error -> Log.e("AuthQuickstart", "Failed to confirm sign in", error))
+ );
+
+// WEB_AUTHN / EMAIL_OTP / SMS_OTP
+// Sign in with preferred passwordless challenge
+// No user input is required at this step
+AuthSignInOptions options = AWSCognitoAuthSignInOptions.builder()
+ .callingActivity(activity)
+ .authFlowType(AuthFlowType.USER_AUTH)
+ .preferredFirstFactor(AuthFactorType.WEB_AUTHN) // or "EMAIL_OTP" or "SMS_OTP"
+ .build();
+RxAmplify.Auth.signIn(username, null, options)
+ .subscribe(
+ result -> Log.i("AuthQuickstart", "Next step for sign in is " + result.getNextStep()),
+ error -> Log.e("AuthQuickstart", "Failed to confirm sign in", error))
+ );
+```
+
+If the preferred first factor is not supplied or is unavailable, and the user has multiple factors available, the flow will continue to select an available first factor by returning an `AuthNextSignInStep.signInStep` value of `CONTINUE_SIGN_IN_WITH_FIRST_FACTOR_SELECTION`, and a list of `AuthNextSignInStep.availableFactors`.
+
+The selection of the authentication method is done by the user. The user can choose from the available factors and proceed with the selected factor. You should call the `confirmSignIn` API with the selected factor to continue the sign-in process. Following is an example if you want to proceed with the `WEB_AUTHN` factor selection:
+
+#### [Java]
+
+```java
+AuthConfirmSignInOptions options = AWSCognitoAuthConfirmSignInOptions.builder()
+ .callingActivity(activity)
+ .build();
+Amplify.Auth.confirmSignIn(
+ AuthFactorType.WEB_AUTHN.getChallengeResponse(),
+ options,
+ result -> Log.i("AuthQuickStart", "Next step for sign in is " + result.getNextStep()),
+ error -> Log.e("AuthQuickStart", "Failed to confirm sign in", error)
+);
+```
+
+#### [Kotlin - Callbacks]
+
+```kotlin
+val options = AWSCognitoAuthConfirmSignInOptions.builder()
+ .callingActivity(activity)
+ .build()
+Amplify.Auth.confirmSignIn(
+ AuthFactorType.WEB_AUTHN.challengeResponse,
+ options,
+ { result -> Log.i("AuthQuickStart", "Next step for sign in is ${result.nextStep}") },
+ { error -> Log.e("AuthQuickStart", "Failed to confirm sign in", error) }
+)
+```
+
+#### [Kotlin - Coroutines]
+
+```kotlin
+try {
+ val options = AWSCognitoAuthConfirmSignInOptions.builder()
+ .callingActivity(activity)
+ .build()
+ val result = Amplify.Auth.confirmSignIn(
+ challengeResponse = AuthFactorType.WEB_AUTHN.challengeResponse,
+ options = options
+ )
+ Log.i("AuthQuickstart", "Next step for sign in is ${result.nextStep}")
+} catch (error: AuthException) {
+ Log.e("AuthQuickstart", "Sign in failed", error)
+}
+```
+
+#### [RxJava]
+
+```java
+AuthConfirmSignInOptions options = AWSCognitoAuthConfirmSignInOptions.builder()
+ .callingActivity(activity)
+ .build();
+RxAmplify.Auth.confirmSignIn(AuthFactorType.WEB_AUTHN.getChallengeResponse(), options)
+ .subscribe(
+ result -> Log.i("AuthQuickstart", "Next step for sign in is " + result.getNextStep()),
+ error -> Log.e("AuthQuickstart", "Failed to confirm sign in", error))
+ );
+```
+
+## USER_PASSWORD_AUTH flow
+
+A use case for the `USER_PASSWORD_AUTH` authentication flow is migrating users into Amazon Cognito
+
+A user migration Lambda trigger helps migrate users from a legacy user management system into your user pool. If you choose the USER_PASSWORD_AUTH authentication flow, users don't have to reset their passwords during user migration. This flow sends your user's password to the service over an encrypted SSL connection during authentication.
+
+When you have migrated all your users, switch flows to the more secure SRP flow. The SRP flow doesn't send any passwords over the network.
+
+#### [Java]
+
+```java
+AuthSignInOptions options = AWSCognitoAuthSignInOptions.builder()
+ .authFlowType(AuthFlowType.USER_PASSWORD_AUTH)
+ .build();
+Amplify.Auth.signIn(
+ "hello@example.com",
+ "password",
+ options,
+ result -> Log.i("AuthQuickStart", "Sign in succeeded with result " + result),
+ error -> Log.e("AuthQuickStart", "Failed to sign in", error)
+);
+```
+
+#### [Kotlin - Callbacks]
+
+```kotlin
+val options = AWSCognitoAuthSignInOptions.builder()
+ .authFlowType(AuthFlowType.USER_PASSWORD_AUTH)
+ .build()
+Amplify.Auth.signIn(
+ "hello@example.com",
+ "password",
+ options,
+ { result ->
+ Log.i("AuthQuickstart", "Next step for sign in is ${result.nextStep}")
+ },
+ { error ->
+ Log.e("AuthQuickstart", "Failed to sign in", error)
+ }
+)
+```
+
+#### [Kotlin - Coroutines]
+
+```kotlin
+try {
+ val options = AWSCognitoAuthSignInOptions.builder()
+ .authFlowType(AuthFlowType.USER_PASSWORD_AUTH)
+ .build()
+ val result = Amplify.Auth.signIn(
+ username = "hello@example.com",
+ password = "password",
+ options = options
+ )
+ Log.i("AuthQuickstart", "Next step for sign in is ${result.nextStep}")
+} catch (error: AuthException) {
+ Log.e("AuthQuickstart", "Sign in failed", error)
+}
+```
+
+#### [RxJava]
+
+```java
+AuthSignInOptions options = AWSCognitoAuthSignInOptions.builder()
+ .authFlowType(AuthFlowType.USER_PASSWORD_AUTH)
+ .build();
+RxAmplify.Auth.signIn("hello@example.com", "password", options)
+ .subscribe(
+ result -> Log.i("AuthQuickstart", "Next step for sign in is " + result.getNextStep()),
+ error -> Log.e("AuthQuickstart", error.toString())
+ );
+```
+
+### Set up auth backend
+
+In order to use the authentication flow `USER_PASSWORD_AUTH`, your Cognito app client has to be configured to allow it. Amplify Gen 2 enables SRP auth by default. To enable USER_PASSWORD_AUTH, you can update the `backend.ts` file with the following changes:
+
+```ts title="amplify/backend.ts"
+import { defineBackend } from '@aws-amplify/backend'
+import { auth } from './auth/resource'
+import { data } from './data/resource'
+
+const backend = defineBackend({
+ auth,
+ data,
+});
+
+// highlight-start
+backend.auth.resources.cfnResources.cfnUserPoolClient.explicitAuthFlows = [
+ "ALLOW_USER_PASSWORD_AUTH",
+ "ALLOW_USER_SRP_AUTH",
+ "ALLOW_USER_AUTH",
+ "ALLOW_REFRESH_TOKEN_AUTH"
+];
+// highlight-end
+```
+
+### Migrate users with Amazon Cognito
+
+Amazon Cognito provides a trigger to migrate users from your existing user directory seamlessly into Cognito. You achieve this by configuring your User Pool's "Migration" trigger which invokes a Lambda function whenever a user that does not already exist in the user pool authenticates, or resets their password.
+
+In short, the Lambda function will validate the user credentials against your existing user directory and return a response object containing the user attributes and status on success. An error message will be returned if an error occurs. There's documentation around [how to set up this migration flow](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-import-using-lambda.html) and more detailed instructions on [how the lambda should handle request and response objects](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-migrate-user.html#cognito-user-pools-lambda-trigger-syntax-user-migration).
+
+## CUSTOM_AUTH flow
+
+Amazon Cognito User Pools supports customizing the authentication flow to enable custom challenge types, in addition to a password in order to verify the identity of users. The custom authentication flow is a series of challenge and response cycles that can be customized to meet different requirements. These challenge types may include CAPTCHAs or dynamic challenge questions.
+
+To define your challenges for custom authentication flow, you need to implement three Lambda triggers for Amazon Cognito.
+
+The flow is initiated by calling `signIn` with `AWSCognitoAuthSignInOptions` configured with `AuthFlowType.CUSTOM_AUTH_WITH_SRP` OR `AuthFlowType.CUSTOM_AUTH_WITHOUT_SRP`.
+
+Follow the instructions in [Custom Auth Sign In](/gen1/[platform]/build-a-backend/auth/sign-in-custom-flow/) to learn about how to integrate custom authentication flow in your application with the Auth APIs.
+
+
+
+
+For more information about working with Lambda Triggers for custom authentication challenges, please visit [Amazon Cognito Developer Documentation](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-challenge.html).
+
+
+
+---
+
+---
+title: "Sign-out"
+section: "build-a-backend/auth/connect-your-frontend"
+platforms: ["android", "angular", "flutter", "javascript", "nextjs", "react", "react-native", "swift", "vue"]
+gen: 2
+last-updated: "2024-05-21T15:34:09.000Z"
+url: "https://docs.amplify.aws/react/build-a-backend/auth/connect-your-frontend/sign-out/"
+---
+
+Amplify provides a client library that enables you to interact with backend resources such as Amplify Auth.
+
+
+> **Info:** The quickest way to get started with Amplify Auth in your frontend application is with the [Authenticator component](https://ui.docs.amplify.aws/react/connected-components/authenticator), which provides a customizable UI and complete authentication flows.
+
+
+
+> **Info:** The quickest way to get started with Amplify Auth in your frontend application is with the [Authenticator component](https://ui.docs.amplify.aws/swift/connected-components/authenticator), which provides a customizable UI and complete authentication flows.
+
+
+
+> **Info:** The quickest way to get started with Amplify Auth in your frontend application is with the [Authenticator component](https://ui.docs.amplify.aws/flutter/connected-components/authenticator), which provides a customizable UI and complete authentication flows.
+
+
+
+> **Info:** The quickest way to get started with Amplify Auth in your frontend application is with the [Authenticator component](https://ui.docs.amplify.aws/android/connected-components/authenticator), which provides a customizable UI and complete authentication flows.
+
+
+To sign a user out of your application use the `signOut` API.
+
+
+```ts
+import { signOut } from 'aws-amplify/auth';
+
+await signOut();
+```
+
+
+```dart
+Future signOutCurrentUser() async {
+ final result = await Amplify.Auth.signOut();
+ if (result is CognitoCompleteSignOut) {
+ safePrint('Sign out completed successfully');
+ } else if (result is CognitoFailedSignOut) {
+ safePrint('Error signing user out: ${result.exception.message}');
+ }
+}
+```
+
+
+
+#### [Java]
+
+```java
+Amplify.Auth.signOut( signOutResult -> {
+ if (signOutResult instanceof AWSCognitoAuthSignOutResult.CompleteSignOut) {
+ // Sign Out completed fully and without errors.
+ Log.i("AuthQuickStart", "Signed out successfully");
+ } else if (signOutResult instanceof AWSCognitoAuthSignOutResult.PartialSignOut) {
+ // Sign Out completed with some errors. User is signed out of the device.
+ AWSCognitoAuthSignOutResult.PartialSignOut partialSignOutResult =
+ (AWSCognitoAuthSignOutResult.PartialSignOut) signOutResult;
+
+ HostedUIError hostedUIError = partialSignOutResult.getHostedUIError();
+ if (hostedUIError != null) {
+ Log.e("AuthQuickStart", "HostedUI Error", hostedUIError.getException());
+ // Optional: Re-launch hostedUIError.getUrl() in a Custom tab to clear Cognito web session.
+ }
+
+ GlobalSignOutError globalSignOutError = partialSignOutResult.getGlobalSignOutError();
+ if (globalSignOutError != null) {
+ Log.e("AuthQuickStart", "GlobalSignOut Error", globalSignOutError.getException());
+ // Optional: Use escape hatch to retry revocation of globalSignOutError.getAccessToken().
+ }
+
+ RevokeTokenError revokeTokenError = partialSignOutResult.getRevokeTokenError();
+ if (revokeTokenError != null) {
+ Log.e("AuthQuickStart", "RevokeToken Error", revokeTokenError.getException());
+ // Optional: Use escape hatch to retry revocation of revokeTokenError.getRefreshToken().
+ }
+ } else if (signOutResult instanceof AWSCognitoAuthSignOutResult.FailedSignOut) {
+ AWSCognitoAuthSignOutResult.FailedSignOut failedSignOutResult =
+ (AWSCognitoAuthSignOutResult.FailedSignOut) signOutResult;
+ // Sign Out failed with an exception, leaving the user signed in.
+ Log.e("AuthQuickStart", "Sign out Failed", failedSignOutResult.getException());
+ }
+});
+```
+
+#### [Kotlin - Callbacks]
+
+```kotlin
+Amplify.Auth.signOut { signOutResult ->
+ when(signOutResult) {
+ is AWSCognitoAuthSignOutResult.CompleteSignOut -> {
+ // Sign Out completed fully and without errors.
+ Log.i("AuthQuickStart", "Signed out successfully")
+ }
+ is AWSCognitoAuthSignOutResult.PartialSignOut -> {
+ // Sign Out completed with some errors. User is signed out of the device.
+ signOutResult.hostedUIError?.let {
+ Log.e("AuthQuickStart", "HostedUI Error", it.exception)
+ // Optional: Re-launch it.url in a Custom tab to clear Cognito web session.
+
+ }
+ signOutResult.globalSignOutError?.let {
+ Log.e("AuthQuickStart", "GlobalSignOut Error", it.exception)
+ // Optional: Use escape hatch to retry revocation of it.accessToken.
+ }
+ signOutResult.revokeTokenError?.let {
+ Log.e("AuthQuickStart", "RevokeToken Error", it.exception)
+ // Optional: Use escape hatch to retry revocation of it.refreshToken.
+ }
+ }
+ is AWSCognitoAuthSignOutResult.FailedSignOut -> {
+ // Sign Out failed with an exception, leaving the user signed in.
+ Log.e("AuthQuickStart", "Sign out Failed", signOutResult.exception)
+ }
+ }
+}
+```
+
+#### [Kotlin - Coroutines]
+
+```kotlin
+val signOutResult = Amplify.Auth.signOut()
+when(signOutResult) {
+ is AWSCognitoAuthSignOutResult.CompleteSignOut -> {
+ // Sign Out completed fully and without errors.
+ Log.i("AuthQuickStart", "Signed out successfully")
+ }
+ is AWSCognitoAuthSignOutResult.PartialSignOut -> {
+ // Sign Out completed with some errors. User is signed out of the device.
+ signOutResult.hostedUIError?.let {
+ Log.e("AuthQuickStart", "HostedUI Error", it.exception)
+ // Optional: Re-launch it.url in a Custom tab to clear Cognito web session.
+
+ }
+ signOutResult.globalSignOutError?.let {
+ Log.e("AuthQuickStart", "GlobalSignOut Error", it.exception)
+ // Optional: Use escape hatch to retry revocation of it.accessToken.
+ }
+ signOutResult.revokeTokenError?.let {
+ Log.e("AuthQuickStart", "RevokeToken Error", it.exception)
+ // Optional: Use escape hatch to retry revocation of it.refreshToken.
+ }
+ }
+ is AWSCognitoAuthSignOutResult.FailedSignOut -> {
+ // Sign Out failed with an exception, leaving the user signed in.
+ Log.e("AuthQuickStart", "Sign out Failed", signOutResult.exception)
+ }
+}
+```
+
+#### [RxJava]
+
+```java
+RxAmplify.Auth.signOut()
+ .subscribe(signOutResult -> {
+ if (signOutResult instanceof AWSCognitoAuthSignOutResult.CompleteSignOut) {
+ // Sign Out completed fully and without errors.
+ Log.i("AuthQuickStart", "Signed out successfully");
+ } else if (signOutResult instanceof AWSCognitoAuthSignOutResult.PartialSignOut) {
+ // Sign Out completed with some errors. User is signed out of the device.
+ AWSCognitoAuthSignOutResult.PartialSignOut partialSignOutResult =
+ (AWSCognitoAuthSignOutResult.PartialSignOut) signOutResult;
+
+ HostedUIError hostedUIError = partialSignOutResult.getHostedUIError();
+ if (hostedUIError != null) {
+ Log.e("AuthQuickStart", "HostedUI Error", hostedUIError.getException());
+ // Optional: Re-launch hostedUIError.getUrl() in a Custom tab to clear Cognito web session.
+ }
+
+ GlobalSignOutError globalSignOutError = partialSignOutResult.getGlobalSignOutError();
+ if (globalSignOutError != null) {
+ Log.e("AuthQuickStart", "GlobalSignOut Error", globalSignOutError.getException());
+ // Optional: Use escape hatch to retry revocation of globalSignOutError.getAccessToken().
+ }
+
+ RevokeTokenError revokeTokenError = partialSignOutResult.getRevokeTokenError();
+ if (revokeTokenError != null) {
+ Log.e("AuthQuickStart", "RevokeToken Error", revokeTokenError.getException());
+ // Optional: Use escape hatch to retry revocation of revokeTokenError.getRefreshToken().
+ }
+ } else if (signOutResult instanceof AWSCognitoAuthSignOutResult.FailedSignOut) {
+ AWSCognitoAuthSignOutResult.FailedSignOut failedSignOutResult =
+ (AWSCognitoAuthSignOutResult.FailedSignOut) signOutResult;
+ // Sign Out failed with an exception, leaving the user signed in.
+ Log.e("AuthQuickStart", "Sign out Failed", failedSignOutResult.getException());
+ }
+ });
+```
+
+
+
+
+#### [Async/Await]
+
+```swift
+func signOutLocally() async {
+ let result = await Amplify.Auth.signOut()
+ guard let signOutResult = result as? AWSCognitoSignOutResult
+ else {
+ print("Signout failed")
+ return
+ }
+
+ print("Local signout successful: \(signOutResult.signedOutLocally)")
+ switch signOutResult {
+ case .complete:
+ // Sign Out completed fully and without errors.
+ print("Signed out successfully")
+
+ case let .partial(revokeTokenError, globalSignOutError, hostedUIError):
+ // Sign Out completed with some errors. User is signed out of the device.
+
+ if let hostedUIError = hostedUIError {
+ print("HostedUI error \(String(describing: hostedUIError))")
+ }
+
+ if let globalSignOutError = globalSignOutError {
+ // Optional: Use escape hatch to retry revocation of globalSignOutError.accessToken.
+ print("GlobalSignOut error \(String(describing: globalSignOutError))")
+ }
+
+ if let revokeTokenError = revokeTokenError {
+ // Optional: Use escape hatch to retry revocation of revokeTokenError.accessToken.
+ print("Revoke token error \(String(describing: revokeTokenError))")
+ }
+
+ case .failed(let error):
+ // Sign Out failed with an exception, leaving the user signed in.
+ print("SignOut failed with \(error)")
+ }
+}
+```
+
+#### [Combine]
+
+```swift
+func signOutLocally() -> AnyCancellable {
+ Amplify.Publisher.create {
+ await Amplify.Auth.signOut()
+ }.sink(receiveValue: { result in
+ guard let signOutResult = result as? AWSCognitoSignOutResult
+ else {
+ print("Signout failed")
+ return
+ }
+ print("Local signout successful: \(signOutResult.signedOutLocally)")
+ switch signOutResult {
+ case .complete:
+ // Sign Out completed fully and without errors.
+ print("Signed out successfully")
+
+ case let .partial(revokeTokenError, globalSignOutError, hostedUIError):
+ // Sign Out completed with some errors. User is signed out of the device.
+ if let hostedUIError = hostedUIError {
+ print("HostedUI error \(String(describing: hostedUIError))")
+ }
+
+ if let globalSignOutError = globalSignOutError {
+ // Optional: Use escape hatch to retry revocation of globalSignOutError.accessToken.
+ print("GlobalSignOut error \(String(describing: globalSignOutError))")
+ }
+
+ if let revokeTokenError = revokeTokenError {
+ // Optional: Use escape hatch to retry revocation of revokeTokenError.accessToken.
+ print("Revoke token error \(String(describing: revokeTokenError))")
+ }
+
+ case .failed(let error):
+ // Sign Out failed with an exception, leaving the user signed in.
+ print("SignOut failed with \(error)")
+ }
+ })
+}
+```
+
+
+
+You can also sign out users from all devices by performing a global sign-out. This will also invalidate all refresh tokens issued to a user. The user's current access and ID tokens will remain valid on other devices until the refresh token expires (access and ID tokens expire one hour after they are issued).
+
+
+```ts
+import { signOut } from 'aws-amplify/auth';
+
+await signOut({ global: true });
+```
+
+
+```dart
+Future signOutGlobally() async {
+ final result = await Amplify.Auth.signOut(
+ options: const SignOutOptions(globalSignOut: true),
+ );
+ if (result is CognitoCompleteSignOut) {
+ safePrint('Sign out completed successfully');
+ } else if (result is CognitoPartialSignOut) {
+ final globalSignOutException = result.globalSignOutException!;
+ final accessToken = globalSignOutException.accessToken;
+ // Retry the global sign out using the access token, if desired
+ // ...
+ safePrint('Error signing user out: ${globalSignOutException.message}');
+ } else if (result is CognitoFailedSignOut) {
+ safePrint('Error signing user out: ${result.exception.message}');
+ }
+}
+```
+
+
+
+#### [Java]
+
+```java
+AuthSignOutOptions options = AuthSignOutOptions.builder()
+ .globalSignOut(true)
+ .build();
+
+Amplify.Auth.signOut(options, signOutResult -> {
+ if (signOutResult instanceof AWSCognitoAuthSignOutResult.CompleteSignOut) {
+ // handle successful sign out
+ } else if (signOutResult instanceof AWSCognitoAuthSignOutResult.PartialSignOut) {
+ // handle partial sign out
+ } else if (signOutResult instanceof AWSCognitoAuthSignOutResult.FailedSignOut) {
+ // handle failed sign out
+ }
+});
+```
+
+#### [Kotlin - Callbacks]
+
+```kotlin
+val options = AuthSignOutOptions.builder()
+ .globalSignOut(true)
+ .build()
+
+Amplify.Auth.signOut(options) { signOutResult ->
+ when(signOutResult) {
+ is AWSCognitoAuthSignOutResult.CompleteSignOut -> {
+ // handle successful sign out
+ }
+ is AWSCognitoAuthSignOutResult.PartialSignOut -> {
+ // handle partial sign out
+ }
+ is AWSCognitoAuthSignOutResult.FailedSignOut -> {
+ // handle failed sign out
+ }
+ }
+}
+```
+
+#### [Kotlin - Coroutines]
+
+```kotlin
+val options = AuthSignOutOptions.builder()
+ .globalSignOut(true)
+ .build()
+
+val signOutResult = Amplify.Auth.signOut(options)
+
+when(signOutResult) {
+ is AWSCognitoAuthSignOutResult.CompleteSignOut -> {
+ // handle successful sign out
+ }
+ is AWSCognitoAuthSignOutResult.PartialSignOut -> {
+ // handle partial sign out
+ }
+ is AWSCognitoAuthSignOutResult.FailedSignOut -> {
+ // handle failed sign out
+ }
+}
+```
+
+#### [RxJava]
+
+```java
+AuthSignOutOptions options = AuthSignOutOptions.builder()
+ .globalSignOut(true)
+ .build();
+
+RxAmplify.Auth.signOut(options)
+ .subscribe(signOutResult -> {
+ if (signOutResult instanceof AWSCognitoAuthSignOutResult.CompleteSignOut) {
+ // handle successful sign out
+ } else if (signOutResult instanceof AWSCognitoAuthSignOutResult.PartialSignOut) {
+ // handle partial sign out
+ } else if (signOutResult instanceof AWSCognitoAuthSignOutResult.FailedSignOut) {
+ // handle failed sign out
+ }
+ });
+```
+
+
+
+
+#### [Async/Await]
+
+```swift
+import AWSCognitoAuthPlugin
+
+func signOutGlobally() async {
+ let result = await Amplify.Auth.signOut(options: .init(globalSignOut: true))
+ guard let signOutResult = result as? AWSCognitoSignOutResult
+ else {
+ print("Signout failed")
+ return
+ }
+
+ print("Local signout successful: \(signOutResult.signedOutLocally)")
+ switch signOutResult {
+ case .complete:
+ // handle successful sign out
+ case .failed(let error):
+ // handle failed sign out
+ case let .partial(revokeTokenError, globalSignOutError, hostedUIError):
+ // handle partial sign out
+ }
+}
+```
+
+#### [Combine]
+
+```swift
+func signOutGlobally() -> AnyCancellable {
+ Amplify.Publisher.create {
+ await Amplify.Auth.signOut(options: .init(globalSignOut: true))
+ }.sink(receiveValue: { result in
+ guard let signOutResult = result as? AWSCognitoSignOutResult
+ else {
+ print("Signout failed")
+ return
+ }
+ print("Local signout successful: \(signOutResult.signedOutLocally)")
+ switch signOutResult {
+ case .complete:
+ // handle successful sign out
+ case .failed(let error):
+ // handle failed sign out
+ case let .partial(revokeTokenError, globalSignOutError, hostedUIError):
+ // handle partial sign out
+ }
+ })
+}
+```
+
+
+
+
+## Practical Example
+
+
+```tsx title="src/App.tsx"
+import { Amplify } from "aws-amplify"
+// highlight-next-line
+import { signOut } from "aws-amplify/auth"
+import outputs from "../amplify_outputs.json"
+
+Amplify.configure(outputs)
+
+export default function App() {
+ async function handleSignOut() {
+ // highlight-next-line
+ await signOut()
+ }
+
+ return (
+
+ Sign out
+
+ )
+}
+```
+
+
+
+---
+
+---
+title: "Manage user sessions"
+section: "build-a-backend/auth/connect-your-frontend"
+platforms: ["android", "angular", "flutter", "javascript", "nextjs", "react", "react-native", "swift", "vue"]
+gen: 2
+last-updated: "2024-10-25T16:39:44.000Z"
+url: "https://docs.amplify.aws/react/build-a-backend/auth/connect-your-frontend/manage-user-sessions/"
+---
+
+Amplify Auth provides access to current user sessions and tokens to help you retrieve your user's information to determine if they are signed in with a valid session and control their access to your app.
+
+
+## Retrieve your current authenticated user
+
+You can use the `getCurrentUser` API to get information about the currently authenticated user including the `username`, `userId` and `signInDetails`.
+
+```ts
+import { getCurrentUser } from 'aws-amplify/auth';
+
+const { username, userId, signInDetails } = await getCurrentUser();
+
+console.log("username", username);
+console.log("user id", userId);
+console.log("sign-in details", signInDetails);
+```
+
+This method can be used to check if a user is signed in. It throws an error if the user is not authenticated.
+
+> **Info:** The user's `signInDetails` are not supported when using the `Hosted UI` or the `signInWithRedirect` API.
+
+## Retrieve a user session
+
+Your user's session is their signed-in state, which grants them access to your app. When your users sign in, their credentials are exchanged for temporary access tokens. You can get session details to access these tokens and use this information to validate user access or perform actions unique to that user.
+
+If you only need the session details, you can use the `fetchAuthSession` API which returns a `tokens` object containing the JSON Web Tokens (JWT).
+
+```ts
+import { fetchAuthSession } from 'aws-amplify/auth';
+
+const session = await fetchAuthSession();
+
+console.log("id token", session.tokens.idToken)
+console.log("access token", session.tokens.accessToken)
+```
+
+### Refreshing sessions
+
+The `fetchAuthSession` API automatically refreshes the user's session when the authentication tokens have expired and a valid `refreshToken` is present. Additionally, you can also refresh the session explicitly by calling the `fetchAuthSession` API with the `forceRefresh` flag enabled.
+
+```ts
+import { fetchAuthSession } from 'aws-amplify/auth';
+
+await fetchAuthSession({ forceRefresh: true });
+```
+
+> **Warning:** **Warning:** by default, sessions from external identity providers cannot be refreshed.
+
+
+An intentional decision with Amplify Auth was to avoid any public methods exposing credentials or manipulating them.
+
+With Auth, you simply sign in and it handles everything else needed to keep the credentials up to date and vend them to the other categories.
+
+However, if you need to access them in relation to working with an API outside Amplify or want access to AWS specific identifying information (e.g. IdentityId), you can access these implementation details by calling `fetchAuthSession` on the Cognito Auth Plugin. This will return a `CognitoAuthSession`, which has additional attributes compared to `AuthSession`, which is typically returned by `fetchAuthSession`. See the example below:
+
+```dart
+Future fetchAuthSession() async {
+ try {
+ final result = await Amplify.Auth.fetchAuthSession();
+ safePrint('User is signed in: ${result.isSignedIn}');
+ } on AuthException catch (e) {
+ safePrint('Error retrieving auth session: ${e.message}');
+ }
+}
+```
+
+## 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.
+
+```dart
+Future fetchCognitoAuthSession() async {
+ try {
+ final cognitoPlugin = Amplify.Auth.getPlugin(AmplifyAuthCognito.pluginKey);
+ final result = await cognitoPlugin.fetchAuthSession();
+ final identityId = result.identityIdResult.value;
+ safePrint("Current user's identity ID: $identityId");
+ } on AuthException catch (e) {
+ safePrint('Error retrieving auth session: ${e.message}');
+ }
+}
+```
+
+
+An intentional decision with Amplify Auth was to avoid any public methods exposing credentials or manipulating them.
+
+With Auth, you simply sign in and it handles everything else needed to keep the credentials up to date and vend them to the other categories.
+
+However, if you need to access them in relation to working with an API outside Amplify or want access to AWS specific identifying information (e.g. IdentityId), you can access these implementation details by casting the result of `fetchAuthSession` as follows:
+
+#### [Java]
+
+```java
+Amplify.Auth.fetchAuthSession(
+ result -> {
+ AWSCognitoAuthSession cognitoAuthSession = (AWSCognitoAuthSession) result;
+ switch(cognitoAuthSession.getIdentityIdResult().getType()) {
+ case SUCCESS:
+ Log.i("AuthQuickStart", "IdentityId: " + cognitoAuthSession.getIdentityIdResult().getValue());
+ break;
+ case FAILURE:
+ Log.i("AuthQuickStart", "IdentityId not present because: " + cognitoAuthSession.getIdentityIdResult().getError().toString());
+ }
+ },
+ error -> Log.e("AuthQuickStart", error.toString())
+);
+```
+
+#### [Kotlin - Callbacks]
+
+```kotlin
+Amplify.Auth.fetchAuthSession(
+ {
+ val session = it as AWSCognitoAuthSession
+ when (session.identityIdResult.type) {
+ AuthSessionResult.Type.SUCCESS ->
+ Log.i("AuthQuickStart", "IdentityId = ${session.identityIdResult.value}")
+ AuthSessionResult.Type.FAILURE ->
+ Log.w("AuthQuickStart", "IdentityId not found", session.identityIdResult.error)
+ }
+ },
+ { Log.e("AuthQuickStart", "Failed to fetch session", it) }
+)
+```
+
+#### [Kotlin - Coroutines]
+
+```kotlin
+try {
+ val session = Amplify.Auth.fetchAuthSession() as AWSCognitoAuthSession
+ val id = session.identityIdResult
+ if (id.type == AuthSessionResult.Type.SUCCESS) {
+ Log.i("AuthQuickStart", "IdentityId: ${id.value}")
+ } else if (id.type == AuthSessionResult.Type.FAILURE) {
+ Log.i("AuthQuickStart", "IdentityId not present: ${id.error}")
+ }
+} catch (error: AuthException) {
+ Log.e("AuthQuickStart", "Failed to fetch session", error)
+}
+```
+
+#### [RxJava]
+
+```java
+RxAmplify.Auth.fetchAuthSession()
+ .subscribe(
+ result -> {
+ AWSCognitoAuthSession cognitoAuthSession = (AWSCognitoAuthSession) result;
+
+ switch (cognitoAuthSession.getIdentityIdResult().getType()) {
+ case SUCCESS:
+ Log.i("AuthQuickStart", "IdentityId: " + cognitoAuthSession.getIdentityIdResult().getValue());
+ break;
+ case FAILURE:
+ Log.i("AuthQuickStart", "IdentityId not present because: " + cognitoAuthSession.getIdentityIdResult().getError().toString());
+ }
+ },
+ error -> Log.e("AuthQuickStart", error.toString())
+ );
+```
+
+## Force refreshing session
+
+Through the plugin, you can force refresh the internal session by setting the `forceRefresh` option when calling the fetchAuthSession API.
+
+#### [Java]
+
+```java
+AuthFetchSessionOptions options = AuthFetchSessionOptions.builder().forceRefresh(true).build();
+```
+
+#### [Kotlin - Callbacks]
+
+```kotlin
+val option = AuthFetchSessionOptions.builder().forceRefresh(true).build()
+```
+
+#### [Kotlin - Coroutines]
+
+```kotlin
+val option = AuthFetchSessionOptions.builder().forceRefresh(true).build()
+```
+
+#### [RxJava]
+
+```java
+AuthFetchSessionOptions options = AuthFetchSessionOptions.builder().forceRefresh(true).build();
+```
+
+
+
+An intentional decision with Amplify Auth was to avoid any public methods exposing credentials or manipulating them.
+
+With Auth, you simply sign in and it handles everything else needed to keep the credentials up to date and vend them to the other categories.
+
+However, if you need to access them in relation to working with an API outside Amplify or want access to AWS specific identifying information (e.g. IdentityId), you can access these implementation details by casting the result of `fetchAuthSession` as follows:
+
+```swift
+import AWSPluginsCore
+
+do {
+ let session = try await Amplify.Auth.fetchAuthSession()
+
+ // Get user sub or identity id
+ if let identityProvider = session as? AuthCognitoIdentityProvider {
+ let usersub = try identityProvider.getUserSub().get()
+ let identityId = try identityProvider.getIdentityId().get()
+ print("User sub - \(usersub) and identity id \(identityId)")
+ }
+
+ // Get AWS credentials
+ if let awsCredentialsProvider = session as? AuthAWSCredentialsProvider {
+ let credentials = try awsCredentialsProvider.getAWSCredentials().get()
+ // Do something with the credentials
+ }
+
+ // Get cognito user pool token
+ if let cognitoTokenProvider = session as? AuthCognitoTokensProvider {
+ let tokens = try cognitoTokenProvider.getCognitoTokens().get()
+ // Do something with the JWT tokens
+ }
+} catch let error as AuthError {
+ print("Fetch auth session failed with error - \(error)")
+} catch {
+}
+```
+If you have enabled guest user in Cognito Identity Pool and no user is signed in, you will be able to access only identityId and AWS credentials. All other session details will give you an error.
+
+```swift
+import AWSPluginsCore
+
+do {
+ let session = try await Amplify.Auth.fetchAuthSession()
+
+ // Get identity id
+ if let identityProvider = session as? AuthCognitoIdentityProvider {
+ let identityId = try identityProvider.getIdentityId().get()
+ print("Identity id \(identityId)")
+ }
+
+ // Get AWS credentials
+ if let awsCredentialsProvider = session as? AuthAWSCredentialsProvider {
+ let credentials = try awsCredentialsProvider.getAWSCredentials().get()
+ // Do something with the credentials
+ }
+} catch let error as AuthError {
+ print("Fetch auth session failed with error - \(error)")
+} catch {
+ print("Unexpected error: \(error)")
+}
+```
+
+## Force refreshing session
+
+Through the plugin, you can force refresh the internal session by passing an api options `forceRefresh` while calling the fetchAuthSession api.
+
+```swift
+Amplify.Auth.fetchAuthSession(options: .forceRefresh())
+
+```
+
+
+---
+
+---
+title: "Manage user attributes"
+section: "build-a-backend/auth/connect-your-frontend"
+platforms: ["android", "angular", "flutter", "javascript", "nextjs", "react", "react-native", "swift", "vue"]
+gen: 2
+last-updated: "2024-11-14T19:12:03.000Z"
+url: "https://docs.amplify.aws/react/build-a-backend/auth/connect-your-frontend/manage-user-attributes/"
+---
+
+User attributes such as email address, phone number help you identify individual users. Defining the user attributes you include for your user profiles makes user data easy to manage at scale. This information will help you personalize user journeys, tailor content, provide intuitive account control, and more. You can capture information upfront during sign-up or enable customers to update their profile after sign-up. In this section we take a closer look at working with user attributes, how to set them up and manage them.
+
+
+## Pass user attributes during sign-up
+
+You can create user attributes during sign-up or when the user is authenticated. To do this as part of sign-up you can pass them in the `userAttributes` object of the `signUp` API:
+
+```ts
+import { signUp } from "aws-amplify/auth";
+
+await signUp({
+ username: "jdoe",
+ password: "mysecurerandompassword#123",
+ options: {
+ userAttributes: {
+ email: "me@domain.com",
+ phone_number: "+12128601234", // E.164 number convention
+ given_name: "Jane",
+ family_name: "Doe",
+ nickname: "Jane",
+ },
+ },
+});
+```
+
+
+
+## Configure custom user attributes during sign-up
+
+Custom attributes can be passed in with the `userAttributes` option of the `signUp` API:
+
+
+```ts
+import { signUp } from "aws-amplify/auth";
+
+await signUp({
+ username: 'john.doe@example.com',
+ password: 'hunter2',
+ options: {
+ userAttributes: {
+ 'custom:display_name': 'john_doe123',
+ }
+ }
+});
+```
+
+
+```dart
+Future _signUp({
+ required String username,
+ required String password,
+ required String email,
+ required String customValue,
+}) async {
+ final userAttributes = {
+ AuthUserAttributeKey.email: email,
+ // Create and pass a custom attribute
+ const CognitoUserAttributeKey.custom('my-custom-attribute'): customValue
+ };
+ await Amplify.Auth.signUp(
+ username: username,
+ password: password,
+ options: SignUpOptions(
+ userAttributes: userAttributes,
+ ),
+ );
+}
+```
+
+
+```swift
+func signUp(username: String, password: String, email: String) async {
+ do {
+ let signUpResult = try await Amplify.Auth.signUp(
+ username: username,
+ password: password,
+ options: .init(userAttributes: [
+ AuthUserAttribute(.email, value: email),
+ AuthUserAttribute(.custom("my-custom-attribute"), value: )
+ ])
+ )
+ 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)")
+ }
+}
+```
+
+
+
+## Retrieve user attributes
+
+You can retrieve user attributes for your users to read in their profile using the `fetchUserAttributes` API. This helps you personalize their frontend experience as well as control what they will see.
+
+
+```ts
+import { fetchUserAttributes } from 'aws-amplify/auth';
+
+await fetchUserAttributes();
+```
+
+
+
+#### [Async/Await]
+
+```swift
+func fetchAttributes() async {
+ do {
+ let attributes = try await Amplify.Auth.fetchUserAttributes()
+ print("User attributes - \(attributes)")
+ } catch let error as AuthError{
+ print("Fetching user attributes failed with error \(error)")
+ } catch {
+ print("Unexpected error: \(error)")
+ }
+}
+```
+
+#### [Combine]
+
+```swift
+func fetchAttributes() -> AnyCancellable {
+ Amplify.Publisher.create {
+ try await Amplify.Auth.fetchUserAttributes()
+ }.sink {
+ if case let .failure(authError) = $0 {
+ print("Fetch user attributes failed with error \(authError)")
+ }
+ }
+ receiveValue: { attributes in
+ print("User attributes - \(attributes)")
+ }
+}
+```
+
+
+
+
+#### [Java]
+
+```java
+Amplify.Auth.fetchUserAttributes(
+ attributes -> Log.i("AuthDemo", "User attributes = " + attributes.toString()),
+ error -> Log.e("AuthDemo", "Failed to fetch user attributes.", error)
+);
+```
+
+#### [Kotlin - Callbacks]
+
+```kotlin
+Amplify.Auth.fetchUserAttributes(
+ { Log.i("AuthDemo", "User attributes = $it") },
+ { Log.e("AuthDemo", "Failed to fetch user attributes", it) }
+)
+```
+
+#### [Kotlin - Coroutines]
+
+```kotlin
+try {
+ val attributes = Amplify.Auth.fetchUserAttributes()
+ Log.i("AuthDemo", "User attributes = $attributes")
+} catch (error: AuthException) {
+ Log.e("AuthDemo", "Failed to fetch user attributes", error)
+}
+```
+
+#### [RxJava]
+
+```java
+RxAmplify.Auth.fetchUserAttributes()
+ .doOnSubscribe(() -> Log.i("AuthDemo", "Attributes:"))
+ .flatMapObservable(Observable::fromIterable)
+ .subscribe(
+ eachAttribute -> Log.i("AuthDemo", eachAttribute.toString()),
+ error -> Log.e("AuthDemo", "Failed to fetch attributes.", error)
+ );
+```
+
+
+
+```dart
+Future fetchCurrentUserAttributes() async {
+ try {
+ final result = await Amplify.Auth.fetchUserAttributes();
+ for (final element in result) {
+ safePrint('key: ${element.userAttributeKey}; value: ${element.value}');
+ }
+ } on AuthException catch (e) {
+ safePrint('Error fetching user attributes: ${e.message}');
+ }
+}
+```
+
+
+## Update user attribute
+
+You can use the `updateUserAttribute` API to create or update existing user attributes.
+
+
+
+#### [TypeScript]
+
+```typescript
+import {
+ updateUserAttribute,
+ type UpdateUserAttributeOutput
+} from 'aws-amplify/auth';
+
+async function handleUpdateUserAttribute(attributeKey: string, value: string) {
+ try {
+ const output = await updateUserAttribute({
+ userAttribute: {
+ attributeKey,
+ value
+ }
+ });
+ handleUpdateUserAttributeNextSteps(output);
+ } catch (error) {
+ console.log(error);
+ }
+}
+
+function handleUpdateUserAttributeNextSteps(output: UpdateUserAttributeOutput) {
+ const { nextStep } = output;
+
+ switch (nextStep.updateAttributeStep) {
+ case 'CONFIRM_ATTRIBUTE_WITH_CODE':
+ const codeDeliveryDetails = nextStep.codeDeliveryDetails;
+ console.log(
+ `Confirmation code was sent to ${codeDeliveryDetails?.deliveryMedium}.`
+ );
+ // Collect the confirmation code from the user and pass to confirmUserAttribute.
+ break;
+ case 'DONE':
+ console.log(`attribute was successfully updated.`);
+ break;
+ }
+}
+```
+
+#### [JavaScript]
+
+```javascript
+import { updateUserAttribute } from 'aws-amplify/auth';
+
+async function handleUpdateUserAttribute(attributeKey, value) {
+ try {
+ const output = await updateUserAttribute({
+ userAttribute: {
+ attributeKey,
+ value
+ }
+ });
+ handleUpdateUserAttributeNextSteps(output);
+ } catch (error) {
+ console.log(error);
+ }
+}
+
+function handleUpdateUserAttributeNextSteps(output) {
+ const { nextStep } = output;
+
+ switch (nextStep.updateAttributeStep) {
+ case 'CONFIRM_ATTRIBUTE_WITH_CODE':
+ const codeDeliveryDetails = nextStep.codeDeliveryDetails;
+ console.log(
+ `Confirmation code was sent to ${codeDeliveryDetails?.deliveryMedium}.`
+ );
+ // Collect the confirmation code from the user and pass to confirmUserAttribute.
+ break;
+ case 'DONE':
+ console.log(`attribute was successfully updated.`);
+ break;
+ }
+}
+```
+
+
+ Note: If you change an attribute that requires confirmation (i.e. email or phone_number), the user will receive a confirmation code either to their email or cellphone. This code can be used with the confirmUserAttribute API to confirm the change.
+
+
+
+
+
+#### [Async/Await]
+
+```swift
+func updateAttribute() async {
+ do {
+ let updateResult = try await Amplify.Auth.update(
+ userAttribute: AuthUserAttribute(.phoneNumber, value: "+2223334444")
+ )
+
+ switch updateResult.nextStep {
+ case .confirmAttributeWithCode(let deliveryDetails, let info):
+ print("Confirm the attribute with details send to - \(deliveryDetails) \(String(describing: info))")
+ case .done:
+ print("Update completed")
+ }
+ } catch let error as AuthError {
+ print("Update attribute failed with error \(error)")
+ } catch {
+ print("Unexpected error: \(error)")
+ }
+}
+```
+
+#### [Combine]
+
+```swift
+func updateAttribute() -> AnyCancellable {
+ Amplify.Publisher.create {
+ try await Amplify.Auth.update(
+ userAttribute: AuthUserAttribute(.phoneNumber, value: "+2223334444")
+ )
+ }.sink {
+ if case let .failure(authError) = $0 {
+ print("Update attribute failed with error \(authError)")
+ }
+ }
+ receiveValue: { updateResult in
+ switch updateResult.nextStep {
+ case .confirmAttributeWithCode(let deliveryDetails, let info):
+ print("Confirm the attribute with details send to - \(deliveryDetails) \(info)")
+ case .done:
+ print("Update completed")
+ }
+ }
+}
+```
+
+
+
+
+
+#### [Java]
+
+```java
+AuthUserAttribute userEmail =
+ new AuthUserAttribute(AuthUserAttributeKey.email(), "email@email.com");
+Amplify.Auth.updateUserAttribute(userEmail,
+ result -> Log.i("AuthDemo", "Updated user attribute = " + result.toString()),
+ error -> Log.e("AuthDemo", "Failed to update user attribute.", error)
+);
+```
+
+#### [Kotlin - Callbacks]
+
+```kotlin
+Amplify.Auth.updateUserAttribute(
+ AuthUserAttribute(AuthUserAttributeKey.email(), "email@email.com"),
+ { Log.i("AuthDemo", "Updated user attribute = $it") },
+ { Log.e("AuthDemo", "Failed to update user attribute.", it) }
+)
+```
+
+#### [Kotlin - Coroutines]
+
+```kotlin
+val attribute =
+ AuthUserAttribute(AuthUserAttributeKey.email(), "email@email.com")
+try {
+ val result = Amplify.Auth.updateUserAttribute(attribute)
+ Log.i("AuthDemo", "Updated user attribute = $result")
+} catch (error: AuthException) {
+ Log.e("AuthDemo", "Failed to update user attribute.", error)
+}
+```
+
+#### [RxJava]
+
+```java
+AuthUserAttribute userEmail =
+ new AuthUserAttribute(AuthUserAttributeKey.email(), "email@email.com");
+RxAmplify.Auth.updateUserAttribute(userEmail)
+ .subscribe(
+ result -> Log.i("AuthDemo", "Updated user attribute = " + result.toString()),
+ error -> Log.e("AuthDemo", "Failed to update user attribute.", error)
+ );
+```
+
+
+
+
+```dart
+Future updateUserEmail({
+ required String newEmail,
+}) async {
+ try {
+ final result = await Amplify.Auth.updateUserAttribute(
+ userAttributeKey: AuthUserAttributeKey.email,
+ value: newEmail,
+ );
+ _handleUpdateUserAttributeResult(result);
+ } on AuthException catch (e) {
+ safePrint('Error updating user attribute: ${e.message}');
+ }
+}
+```
+
+User attribute updates may require additional verification before they're complete. Check the
+`UpdateUserAttributeResult` returned from `Amplify.Auth.updateUserAttribute` to see which next
+step, if any, is required. When the update is complete, the next step will be `done`.
+
+```dart
+void _handleUpdateUserAttributeResult(
+ UpdateUserAttributeResult result,
+) {
+ switch (result.nextStep.updateAttributeStep) {
+ case AuthUpdateAttributeStep.confirmAttributeWithCode:
+ final codeDeliveryDetails = result.nextStep.codeDeliveryDetails!;
+ _handleCodeDelivery(codeDeliveryDetails);
+ break;
+ case AuthUpdateAttributeStep.done:
+ safePrint('Successfully updated attribute');
+ break;
+ }
+}
+
+void _handleCodeDelivery(AuthCodeDeliveryDetails codeDeliveryDetails) {
+ safePrint(
+ 'A confirmation code has been sent to ${codeDeliveryDetails.destination}. '
+ 'Please check your ${codeDeliveryDetails.deliveryMedium.name} for the code.',
+ );
+}
+```
+
+To update multiple user attributes at a time, call `updateUserAttributes`:
+
+```dart
+Future updateUserAttributes() async {
+ const attributes = [
+ AuthUserAttribute(
+ userAttributeKey: AuthUserAttributeKey.email,
+ value: 'email@email.com',
+ ),
+ AuthUserAttribute(
+ userAttributeKey: AuthUserAttributeKey.familyName,
+ value: 'MyFamilyName',
+ ),
+ ];
+ try {
+ final result = await Amplify.Auth.updateUserAttributes(
+ attributes: attributes,
+ );
+ result.forEach((key, value) {
+ switch (value.nextStep.updateAttributeStep) {
+ case AuthUpdateAttributeStep.confirmAttributeWithCode:
+ final destination = value.nextStep.codeDeliveryDetails?.destination;
+ safePrint('Confirmation code sent to $destination for $key');
+ break;
+ case AuthUpdateAttributeStep.done:
+ safePrint('Update completed for $key');
+ break;
+ }
+ });
+ } on AuthException catch (e) {
+ safePrint('Error updating user attributes: ${e.message}');
+ }
+}
+```
+
+
+
+## Update user attributes
+
+You can use the `updateUserAttributes` API to create or update multiple existing user attributes.
+
+
+```typescript
+import { updateUserAttributes, type UpdateUserAttributesOutput } from "aws-amplify/auth";
+
+await updateUserAttributes({
+ userAttributes: {
+ email: "me@domain.com",
+ name: "Jon Doe",
+ },
+});
+```
+
+
+
+
+#### [Java]
+
+```java
+Amplify.Auth.updateUserAttributes(
+ attributes, // attributes is a list of AuthUserAttribute
+ result -> Log.i("AuthDemo", "Updated user attributes = " + result.toString()),
+ error -> Log.e("AuthDemo", "Failed to update user attributes.", error)
+);
+```
+
+#### [Kotlin - Callbacks]
+
+```kotlin
+Amplify.Auth.updateUserAttributes(
+ attributes, // attributes is a list of AuthUserAttribute
+ { Log.i("AuthDemo", "Updated user attributes = $it") },
+ { Log.e("AuthDemo", "Failed to update user attributes", it) }
+)
+```
+
+#### [Kotlin - Coroutines]
+
+```kotlin
+try {
+ val result = Amplify.Auth.updateUserAttributes(attributes)
+ Log.i("AuthDemo", "Updated user attributes = $result")
+} catch (error: AuthException) {
+ Log.e("AuthDemo", "Failed to update user attributes", error)
+}
+```
+
+#### [RxJava]
+
+```java
+// attributes is a list of AuthUserAttribute
+RxAmplify.Auth.updateUserAttributes(attributes)
+ .subscribe(
+ result -> Log.i("AuthDemo", "Updated user attributes = " + result.toString()),
+ error -> Log.e("AuthDemo", "Failed to update user attributes.", error)
+ );
+```
+
+
+
+
+## Verify user attribute
+
+
+Some attributes require confirmation for the attribute update to complete. If the attribute needs to be confirmed, part of the result of the `updateUserAttribute` or `updateUserAttributes` APIs will be `CONFIRM_ATTRIBUTE_WITH_CODE`. A confirmation code will be sent to the delivery medium mentioned in the delivery details. When the user gets the confirmation code, you can present a UI to the user to enter the code and invoke the `confirmUserAttribute` API with their input:
+
+
+
+Some attributes require confirmation for the attribute update to complete. If the attribute needs to be confirmed, part of the result of the `updateUserAttribute` or `updateUserAttributes` APIs will be `confirmAttributeWithCode`. A confirmation code will be sent to the delivery medium mentioned in the delivery details. When the user gets the confirmation code, you can present a UI to the user to enter the code and invoke the `confirmUserAttribute` API with their input:
+
+
+
+```typescript
+import {
+ confirmUserAttribute,
+ type ConfirmUserAttributeInput
+} from 'aws-amplify/auth';
+
+async function handleConfirmUserAttribute({
+ userAttributeKey,
+ confirmationCode
+}: ConfirmUserAttributeInput) {
+ try {
+ await confirmUserAttribute({ userAttributeKey, confirmationCode });
+ } catch (error) {
+ console.log(error);
+ }
+}
+```
+
+
+
+
+#### [Async/Await]
+
+```swift
+func confirmAttribute() async {
+ do {
+ try await Amplify.Auth.confirm(userAttribute: .email, confirmationCode: "390739")
+ print("Attribute verified")
+ } catch let error as AuthError {
+ print("Update attribute failed with error \(error)")
+ } catch {
+ print("Unexpected error: \(error)")
+ }
+}
+```
+
+#### [Combine]
+
+```swift
+func confirmAttribute() -> AnyCancellable {
+ Amplify.Publisher.create {
+ try await Amplify.Auth.confirm(userAttribute: .email, confirmationCode: "390739")
+ }.sink {
+ if case let .failure(authError) = $0 {
+ print("Update attribute failed with error \(authError)")
+ }
+ }
+ receiveValue: { _ in
+ print("Attribute verified")
+ }
+}
+```
+
+
+
+
+
+#### [Java]
+
+```java
+Amplify.Auth.confirmUserAttribute(AuthUserAttributeKey.email(), "344299",
+ () -> Log.i("AuthDemo", "Confirmed user attribute with correct code."),
+ error -> Log.e("AuthDemo", "Failed to confirm user attribute. Bad code?", error)
+);
+```
+
+#### [Kotlin - Callbacks]
+
+```kotlin
+Amplify.Auth.confirmUserAttribute(AuthUserAttributeKey.email(), "344299",
+ { Log.i("AuthDemo", "Confirmed user attribute with correct code.") },
+ { Log.e("AuthDemo", "Failed to confirm user attribute. Bad code?", it) }
+)
+```
+
+#### [Kotlin - Coroutines]
+
+```kotlin
+try {
+ Amplify.Auth.confirmUserAttribute(AuthUserAttributeKey.email(), "344299")
+ Log.i("AuthDemo", "Confirmed user attribute with correct code.")
+} catch (error: AuthException) {
+ Log.e("AuthDemo", "Failed to confirm user attribute. Bade code?", error)
+}
+```
+
+#### [RxJava]
+
+```java
+RxAmplify.Auth.confirmUserAttribute(AuthUserAttributeKey.email(), "344299")
+ .subscribe(
+ () -> Log.i("AuthDemo", "Confirmed user attribute using correct code."),
+ error -> Log.e("AuthDemo", "Failed to confirm user attribute. Bad code?", error)
+ );
+```
+
+
+
+
+```dart
+Future verifyAttributeUpdate() async {
+ try {
+ await Amplify.Auth.confirmUserAttribute(
+ userAttributeKey: AuthUserAttributeKey.email,
+ confirmationCode: '390739',
+ );
+ } on AuthException catch (e) {
+ safePrint('Error confirming attribute update: ${e.message}');
+ }
+}
+```
+
+
+## Send user attribute verification code
+
+If an attribute needs to be verified while the user is authenticated, invoke the `sendUserAttributeVerificationCode` API as shown below:
+
+
+```ts
+import {
+ sendUserAttributeVerificationCode,
+ type VerifiableUserAttributeKey
+} from 'aws-amplify/auth';
+
+async function handleSendUserAttributeVerificationCode(
+ key: VerifiableUserAttributeKey
+) {
+ try {
+ await sendUserAttributeVerificationCode({
+ userAttributeKey: key
+ });
+ } catch (error) {
+ console.log(error);
+ }
+}
+```
+
+
+
+
+#### [Async/Await]
+
+```swift
+func sendVerificationCode() async {
+ do {
+ let deliveryDetails = try await Amplify.Auth.sendVerificationCode(forUserAttributeKey: .email)
+ print("Resend code send to - \(deliveryDetails)")
+ } catch let error as AuthError {
+ print("Resend code failed with error \(error)")
+ } catch {
+ print("Unexpected error: \(error)")
+ }
+}
+```
+
+#### [Combine]
+
+```swift
+func sendVerificationCode() -> AnyCancellable {
+ Amplify.Publisher.create {
+ try await Amplify.Auth.sendVerificationCode(forUserAttributeKey: .email)
+ }.sink {
+ if case let .failure(authError) = $0 {
+ print("Resend code failed with error \(authError)")
+ }
+ }
+ receiveValue: { deliveryDetails in
+ print("Resend code sent to - \(deliveryDetails)")
+ }
+}
+```
+
+
+
+
+
+#### [Java]
+
+```java
+Amplify.Auth.resendUserAttributeConfirmationCode(AuthUserAttributeKey.email(),
+ result -> Log.i("AuthDemo", "Code was sent again: " + result.toString()),
+ error -> Log.e("AuthDemo", "Failed to resend code.", error)
+);
+```
+
+#### [Kotlin - Callbacks]
+
+```kotlin
+Amplify.Auth.resendUserAttributeConfirmationCode(
+ AuthUserAttributeKey.email(),
+ { Log.i("AuthDemo", "Code was sent again: $it") },
+ { Log.e("AuthDemo", "Failed to resend code", it) }
+)
+```
+
+#### [Kotlin - Coroutines]
+
+```kotlin
+try {
+ val attr = AuthUserAttributeKey.email()
+ val result = Amplify.Auth.resendUserAttributeConfirmationCode(attr)
+ Log.i("AuthDemo", "Code was sent again: $result."),
+} catch (error: AuthException) {
+ Log.e("AuthDemo", "Failed to resend code.", error)
+}
+```
+
+#### [RxJava]
+
+```java
+RxAmplify.Auth.resendUserAttributeConfirmationCode(AuthUserAttributeKey.email())
+ .subscribe(
+ result -> Log.i("AuthDemo", "Code was resent: " + result.toString()),
+ error -> Log.e("AuthDemo", "Failed to resend code.", error)
+ );
+```
+
+
+
+
+```dart
+Future resendVerificationCode() async {
+ try {
+ final result = await Amplify.Auth.resendUserAttributeConfirmationCode(
+ userAttributeKey: AuthUserAttributeKey.email,
+ );
+ _handleCodeDelivery(result.codeDeliveryDetails);
+ } on AuthException catch (e) {
+ safePrint('Error resending code: ${e.message}');
+ }
+}
+```
+
+
+
+## Delete user attributes
+
+The `deleteUserAttributes` API allows to delete one or more user attributes.
+
+```ts
+import {
+ deleteUserAttributes,
+ type DeleteUserAttributesInput
+} from 'aws-amplify/auth';
+
+async function handleDeleteUserAttributes(
+ keys: DeleteUserAttributesInput['userAttributeKeys']
+) {
+ try {
+ await deleteUserAttributes({
+ userAttributeKeys: ['custom:my_custom_attribute', ...keys]
+ });
+ } catch (error) {
+ console.log(error);
+ }
+}
+```
+
+
+## Next Steps
+
+- [Learn how to set up password change and recovery](/[platform]/build-a-backend/auth/manage-users/manage-passwords/)
+- [Learn how to set up custom attributes](/[platform]/build-a-backend/auth/concepts/user-attributes#custom-attributes)
+
+---
+
+---
+title: "Listen to auth events"
+section: "build-a-backend/auth/connect-your-frontend"
+platforms: ["android", "angular", "flutter", "javascript", "nextjs", "react", "react-native", "swift", "vue"]
+gen: 2
+last-updated: "2024-05-16T15:59:30.000Z"
+url: "https://docs.amplify.aws/react/build-a-backend/auth/connect-your-frontend/listen-to-auth-events/"
+---
+
+Amplify Auth emits events during authentication flows, which enables you to react to user flows in real time and trigger custom business logic. For example, you may want to capture data, synchronize your app's state, and personalize the user's experience. You can listen to and respond to events across the Auth lifecycle such as sign-in and sign-out.
+
+
+## Expose hub events triggered in response to auth actions
+
+You can use Amplify Hub with its built in Amplify Auth events to subscribe a listener using a publish-subscribe pattern and capture events between different parts of your application. The Amplify Auth category publishes in the `auth` channel when auth events such as `signedIn` or `signedOut` happen independent from your app code.
+
+You can review the Amplify Hub guide to [learn more](/gen1/react/build-a-backend/utilities/hub/).
+
+> **Warning:** Channels are logical group names that help you organize dispatching and listening. However, some channels are protected and cannot be used to publish custom events, and `auth` is one of these channels. Sending unexpected payloads to protected channels can have undesirable side effects such as impacting authentication flows. See the [Amplify Hub](/gen1/react/build-a-backend/utilities/hub/) guide for more protected channels.
+
+Here is a basic example of setting up a listener that logs an event emitted through the `auth` channel:
+
+```js
+import { Hub } from 'aws-amplify/utils';
+
+Hub.listen('auth', (data) => {
+ console.log(data)
+});
+```
+
+Once your app is set up to subscribe and listen to specific event types from the `auth` channel, the listeners will be notified asynchronously when an event occurs. This pattern allows for a one-to-many relationship where one auth event can be shared with many different listeners that have been subscribed. This lets your app react based on the event rather than proactively poll for information.
+
+Additionally, you can set up your listener to extract data from the event payload and execute a callback that you define. For example, you might update UI elements in your app to reflect your user's authenticated state after the `signedIn` or `signedOut` events.
+
+### Listen to and log auth events
+
+One of the most common workflows will be to log events. In this example you can see how you can listen and target specific `auth` events using a `switch` to log your own messages.
+
+```js
+import { Hub } from 'aws-amplify/utils';
+
+Hub.listen('auth', ({ payload }) => {
+ switch (payload.event) {
+ case 'signedIn':
+ console.log('user have been signedIn successfully.');
+ break;
+ case 'signedOut':
+ console.log('user have been signedOut successfully.');
+ break;
+ case 'tokenRefresh':
+ console.log('auth tokens have been refreshed.');
+ break;
+ case 'tokenRefresh_failure':
+ console.log('failure while refreshing auth tokens.');
+ break;
+ case 'signInWithRedirect':
+ console.log('signInWithRedirect API has successfully been resolved.');
+ break;
+ case 'signInWithRedirect_failure':
+ console.log('failure while trying to resolve signInWithRedirect API.');
+ break;
+ case 'customOAuthState':
+ logger.info('custom state returned from CognitoHosted UI');
+ break;
+ }
+});
+```
+
+### Stop listening to events
+
+You can also stop listening for messages by calling the result of the `Hub.listen()` function. This may be useful if you no longer need to receive messages in your application flow. This can also help you avoid any memory leaks on low powered devices when you are sending large amounts of data through Amplify Hub on multiple channels.
+
+To stop listening to a certain event, you need to wrap the listener function with a variable and call it once you no longer need it:
+
+```js
+/* start listening for messages */
+const hubListenerCancelToken = Hub.listen('auth', (data) => {
+ console.log('Listening for all auth events: ', data.payload.data);
+});
+
+/* later */
+hubListenerCancelToken(); // stop listening for messages
+```
+
+You now have a few use cases and examples for listening to and responding to auth events.
+
+
+AWS Cognito Auth Plugin sends important events through Amplify Hub. You can listen to these events like the following:
+
+```dart
+final subscription = Amplify.Hub.listen(HubChannel.Auth, (AuthHubEvent event) {
+ switch (event.type) {
+ case AuthHubEventType.signedIn:
+ safePrint('User is signed in.');
+ break;
+ case AuthHubEventType.signedOut:
+ safePrint('User is signed out.');
+ break;
+ case AuthHubEventType.sessionExpired:
+ safePrint('The session has expired.');
+ break;
+ case AuthHubEventType.userDeleted:
+ safePrint('The user has been deleted.');
+ break;
+ }
+});
+```
+
+
+AWS Cognito Auth Plugin sends important events through Amplify Hub. You can listen to these events like the following:
+
+#### [Java]
+
+```java
+Amplify.Hub.subscribe(HubChannel.AUTH,
+ hubEvent -> {
+ if (hubEvent.getName().equals(InitializationStatus.SUCCEEDED.name())) {
+ Log.i("AuthQuickstart", "Auth successfully initialized");
+ } else if (hubEvent.getName().equals(InitializationStatus.FAILED.name())){
+ Log.i("AuthQuickstart", "Auth failed to succeed");
+ } else {
+ String eventName = hubEvent.getName();
+ if (eventName.equals(SIGNED_IN.name())) {
+ Log.i("AuthQuickstart", "Auth just became signed in.");
+ }
+ else if (eventName.equals(SIGNED_OUT.name())) {
+ Log.i("AuthQuickstart", "Auth just became signed out.");
+ }
+ else if (eventName.equals(SESSION_EXPIRED.name())) {
+ Log.i("AuthQuickstart", "Auth session just expired.");
+ }
+ else if (eventName.equals(USER_DELETED.name())) {
+ Log.i("AuthQuickstart", "User has been deleted.");
+ }
+ else {
+ Log.w("AuthQuickstart", "Unhandled Auth Event: " + eventName);
+ }
+ }
+ }
+);
+
+```
+
+#### [Kotlin - Callbacks]
+
+```kotlin
+Amplify.Hub.subscribe(HubChannel.AUTH) { event ->
+ when (event.name) {
+ InitializationStatus.SUCCEEDED.name ->
+ Log.i("AuthQuickstart", "Auth successfully initialized")
+ InitializationStatus.FAILED.name ->
+ Log.i("AuthQuickstart", "Auth failed to succeed")
+ else -> when (event.name) {
+ AuthChannelEventName.SIGNED_IN.name ->
+ Log.i("AuthQuickstart", "Auth just became signed in")
+ AuthChannelEventName.SIGNED_OUT.name ->
+ Log.i("AuthQuickstart", "Auth just became signed out")
+ AuthChannelEventName.SESSION_EXPIRED.name ->
+ Log.i("AuthQuickstart", "Auth session just expired")
+ AuthChannelEventName.USER_DELETED.name ->
+ Log.i("AuthQuickstart", "User has been deleted")
+ else ->
+ Log.w("AuthQuickstart", "Unhandled Auth Event: ${event.name}")
+ }
+ }
+}
+```
+
+#### [Kotlin - Coroutines]
+
+```kotlin
+Amplify.Hub.subscribe(HubChannel.AUTH).collect {
+ when (it.name) {
+ InitializationStatus.SUCCEEDED.name ->
+ Log.i("AuthQuickstart", "Auth successfully initialized")
+ InitializationStatus.FAILED.name ->
+ Log.i("AuthQuickstart", "Auth failed to succeed")
+ else -> when (it.name) {
+ AuthChannelEventName.SIGNED_IN.name ->
+ Log.i("AuthQuickstart", "Auth just became signed in.")
+ AuthChannelEventName.SIGNED_OUT.name ->
+ Log.i("AuthQuickstart", "Auth just became signed out.")
+ AuthChannelEventName.SESSION_EXPIRED.name ->
+ Log.i("AuthQuickstart", "Auth session just expired.")
+ AuthChannelEventName.USER_DELETED.name ->
+ Log.i("AuthQuickstart", "User has been deleted.")
+ else ->
+ Log.w("AuthQuickstart", "Unhandled Auth Event: ${it.name}")
+ }
+ }
+}
+```
+
+#### [RxJava]
+
+```java
+RxAmplify.Hub.on(HubChannel.AUTH)
+ .map(HubEvent::getName)
+ .subscribe(name -> {
+ if (name.equals(InitializationStatus.SUCCEEDED.name())) {
+ Log.i("AuthQuickstart", "Auth successfully initialized");
+ return;
+ } else if (name.equals(InitializationStatus.FAILED.name())) {
+ Log.i("AuthQuickstart", "Auth failed to succeed");
+ return;
+ } else {
+ if (name.equals(SIGNED_IN.name())) {
+ Log.i("AuthQuickstart", "Auth just became signed in.");
+ }
+ else if (name.equals(SIGNED_OUT.name())) {
+ Log.i("AuthQuickstart", "Auth just became signed out.");
+ }
+ else if (name.equals(SESSION_EXPIRED.name())) {
+ Log.i("AuthQuickstart", "Auth session just expired.");
+ }
+ else if (name.equals(USER_DELETED.name())) {
+ Log.i("AuthQuickstart", "User has been deleted.");
+ }
+ else {
+ Log.w("AuthQuickstart", "Unhandled Auth Event: " + hubEvent.getName());
+ }
+ }
+ });
+```
+
+
+
+AWS Cognito Auth Plugin sends important events through Amplify Hub. You can listen to these events like the following:
+
+#### [Listener]
+
+```swift
+override func viewDidLoad() {
+ super.viewDidLoad()
+ // Do any additional setup after loading the view.
+
+ // Assumes `unsubscribeToken` is declared as an instance variable in your view
+ unsubscribeToken = Amplify.Hub.listen(to: .auth) { payload in
+ switch payload.eventName {
+ case HubPayload.EventName.Auth.signedIn:
+ print("User signed in")
+ // Update UI
+
+ case HubPayload.EventName.Auth.sessionExpired:
+ print("Session expired")
+ // Re-authenticate the user
+
+ case HubPayload.EventName.Auth.signedOut:
+ print("User signed out")
+ // Update UI
+
+ case HubPayload.EventName.Auth.userDeleted:
+ print("User deleted")
+ // Update UI
+
+ default:
+ break
+ }
+ }
+}
+```
+
+#### [Combine]
+
+```swift
+override func viewDidLoad() {
+ super.viewDidLoad()
+ // Do any additional setup after loading the view.
+
+ // Assumes `sink` is declared as an instance variable in your view controller
+ sink = Amplify.Hub
+ .publisher(for: .auth)
+ .sink { payload in
+ switch payload.eventName {
+ case HubPayload.EventName.Auth.signedIn:
+ print("User signed in")
+ // Update UI
+
+ case HubPayload.EventName.Auth.sessionExpired:
+ print("Session expired")
+ // Re-authenticate the user
+
+ case HubPayload.EventName.Auth.signedOut:
+ print("User signed out")
+ // Update UI
+
+ case HubPayload.EventName.Auth.userDeleted:
+ print("User deleted")
+ // Update UI
+
+ default:
+ break
+ }
+ }
+}
+```
+
+
+
+---
+
+---
+title: "Delete user account"
+section: "build-a-backend/auth/connect-your-frontend"
+platforms: ["android", "angular", "flutter", "javascript", "nextjs", "react", "react-native", "swift", "vue"]
+gen: 2
+last-updated: "2024-05-16T15:59:30.000Z"
+url: "https://docs.amplify.aws/react/build-a-backend/auth/connect-your-frontend/delete-user-account/"
+---
+
+export async function getStaticPaths() {
+ return getCustomStaticPath(meta.platforms);
+}
+
+Empowering users to delete their account can improve trust and transparency. You can programmatically enable self-service account deletion with Amplify Auth.
+
+If you have not yet created an Amplify Gen 2 app, visit the [quickstart](/[platform]/start/quickstart).
+
+## Allow users to delete their account
+
+You can quickly set up account deletion for your users with the Amplify Libraries. Invoking the `deleteUser` API to delete a user from the Auth category will also sign out your user.
+
+If your application uses a Cognito User Pool, which is the default configuration, this action will only delete the user from the Cognito User Pool. It will have no effect if you are federating with a Cognito Identity Pool alone.
+
+> **Warning:** Before invoking the `deleteUser` API, you may need to first delete associated user data that is not stored in Cognito. For example, if you are using Amplify Data to persist user data, you could follow [these instructions](https://gist.github.com/aws-amplify-ops/27954c421bd72930874d48c15c284807) to delete associated user data. This allows you to address any guidelines (such as GDPR) that require your app to delete data associated with a user who deletes their account.
+
+You can enable account deletion using the following method:
+
+
+```ts
+import { deleteUser } from 'aws-amplify/auth';
+
+async function handleDeleteUser() {
+ try {
+ await deleteUser();
+ } catch (error) {
+ console.log(error);
+ }
+}
+```
+
+
+```dart
+Future deleteUser() async {
+ try {
+ await Amplify.Auth.deleteUser();
+ safePrint('Delete user succeeded');
+ } on AuthException catch (e) {
+ safePrint('Delete user failed with error: $e');
+ }
+}
+```
+
+
+
+#### [Java]
+
+```java
+Amplify.Auth.deleteUser(
+ () -> Log.i("AuthQuickStart", "Delete user succeeded"),
+ error -> Log.e("AuthQuickStart", "Delete user failed with error " + error.toString())
+);
+```
+
+#### [Kotlin - Callbacks]
+
+```kotlin
+Amplify.Auth.deleteUser(
+ { Log.i("AuthQuickStart", "Delete user succeeded") },
+ { Log.e("AuthQuickStart", "Delete user failed with error", it) }
+)
+```
+
+#### [Kotlin - Coroutines]
+
+```kotlin
+try {
+ Amplify.Auth.deleteUser()
+ Log.i("AuthQuickStart", "Delete user succeeded")
+} catch (error: AuthException) {
+ Log.e("AuthQuickStart", "Delete user failed with error", error)
+}
+```
+
+#### [RxJava]
+
+```java
+RxAmplify.Auth.deleteUser()
+ .subscribe(
+ () -> Log.i("AuthQuickStart", "Delete user succeeded"),
+ error -> Log.e("AuthQuickStart", "Delete user failed with error " + error.toString())
+ );
+```
+
+
+
+
+#### [Async/Await]
+
+```swift
+func deleteUser() async {
+ do {
+ try await Amplify.Auth.deleteUser()
+ print("Successfully deleted user")
+ } catch let error as AuthError {
+ print("Delete user failed with error \(error)")
+ } catch {
+ print("Unexpected error: \(error)")
+ }
+}
+```
+
+#### [Combine]
+
+```swift
+func deleteUser() -> AnyCancellable {
+ Amplify.Publisher.create {
+ try await Amplify.Auth.deleteUser()
+ }.sink {
+ if case let .failure(authError) = $0 {
+ print("Delete user failed with error \(authError)")
+ }
+ }
+ receiveValue: {
+ print("Successfully deleted user")
+ }
+}
+```
+
+
+
+We recommend you update your UI to let your users know that their account is deleted and test the functionality with a test user. Note that your user will be signed out of your application when they delete their account.
+
+---
+
+---
+title: "Multi-step sign-in"
+section: "build-a-backend/auth/connect-your-frontend"
+platforms: ["android", "swift", "flutter", "react", "nextjs", "javascript", "react-native", "vue", "angular"]
+gen: 2
+last-updated: "2024-12-09T19:54:14.000Z"
+url: "https://docs.amplify.aws/react/build-a-backend/auth/connect-your-frontend/multi-step-sign-in/"
+---
+
+
+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_PASSWORD') {
+ // collect password from user
+ await confirmSignIn({
+ challengeResponse: 'hunter2',
+ });
+}
+
+if (nextStep.signInStep === 'CONTINUE_SIGN_IN_WITH_FIRST_FACTOR_SELECTION') {
+ // present nextStep.availableChallenges to user
+ // collect user selection
+ await confirmSignIn({
+ challengeResponse: 'SMS_OTP', // or 'EMAIL_OTP', 'WEB_AUTHN', 'PASSWORD', 'PASSWORD_SRP'
+ });
+}
+
+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 Password
+
+If the next step is `CONFIRM_SIGN_IN_WITH_PASSWORD`, the user must provide their password as the first factor authentication method. To handle this step, your implementation should prompt the user to enter their password. After the user enters the password, pass the value to the `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_PASSWORD': {
+ // Prompt user to enter their password
+ console.log(`Please enter your password.`);
+ break;
+ }
+ }
+}
+
+async function confirmWithPassword(password: string) {
+ const result = await confirmSignIn({ challengeResponse: password });
+
+ return handleSignInResult(result);
+}
+```
+
+## Continue sign-in with First Factor Selection
+
+If the next step is `CONTINUE_SIGN_IN_WITH_FIRST_FACTOR_SELECTION`, the user must select a first factor method for authentication. After the user selects an option, your implementation should pass the selected method to the `confirmSignIn` API.
+
+The first factor types which are currently supported by Amplify Auth are:
+- `SMS_OTP`
+- `EMAIL_OTP`
+- `WEB_AUTHN`
+- `PASSWORD`
+- `PASSWORD_SRP`
+
+Depending on your configuration and what factors the user has previously setup, not all options may be available. Only the available options will be presented in `availableChallenges` for selection.
+
+Once Amplify receives the user's selection via the `confirmSignIn` API, you can expect to handle a follow up `nextStep` corresponding with the first factor type selected:
+- If `SMS_OTP` is selected, `CONFIRM_SIGN_IN_WITH_SMS_CODE` will be the next step.
+- If `EMAIL_OTP` is selected, `CONFIRM_SIGN_IN_WITH_EMAIL_CODE` will be the next step.
+- If `PASSWORD` or `PASSWORD_SRP` is selected, `CONFIRM_SIGN_IN_WITH_PASSWORD` will be the next step.
+- If `WEB_AUTHN` is selected, Amplify Auth will initiate the authentication ceremony on the user's device. If successful, the next step will be `DONE`.
+
+```ts
+import { type SignInOutput, confirmSignIn } from '@aws-amplify/auth';
+
+async function handleSignInResult(result: SignInOutput) {
+ switch (result.nextStep.signInStep) {
+ case 'CONTINUE_SIGN_IN_WITH_FIRST_FACTOR_SELECTION': {
+ const { availableChallenges } = result.nextStep;
+ // Present available first factor options to user
+ // Prompt for selection
+ console.log(
+ `There are multiple first factor options available for sign in.`,
+ );
+ console.log(
+ `Select a first factor type from the availableChallenges list.`,
+ );
+ break;
+ }
+ }
+}
+
+async function handleFirstFactorSelection(firstFactorType: string) {
+ const result = await confirmSignIn({ challengeResponse: firstFactorType });
+
+ 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);
+}
+```
+
+> **Warning:** **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.
+
+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 in the signin result.
+
+> **Warning:** *New enumeration values*
+>
+> When Amplify adds a new enumeration value (e.g., a new enum class entry or sealed class subtype in Kotlin, or a new enum value in Swift/Dart/Kotlin), it will publish a new minor version of the Amplify Library. Plugins that switch over enumeration values should include default handlers (an else branch in Kotlin or a default statement in Swift/Dart/Kotlin) to ensure that they are not impacted by new enumeration values.
+
+The `Amplify.Auth.signIn` API returns a `SignInResult` object which indicates whether the sign-in flow is
+complete or whether additional steps are required before the user is signed in.
+
+To see if additional signin steps are required, inspect the sign in result's `nextStep.signInStep` property.
+- If the sign-in step is `done`, the flow is complete and the user is signed in.
+- If the sign-in step is not `done`, one or more additional steps are required. These are explained in detail below.
+
+
+
+The `signInStep` property is an enum of type `AuthSignInStep`. Depending on its value, your code should take one of the actions mentioned on this page.
+
+
+
+```dart
+Future signInWithCognito(
+ String username,
+ String password,
+) async {
+ final SignInResult result = await Amplify.Auth.signIn(
+ username: username,
+ password: password,
+ );
+ return _handleSignInResult(result);
+}
+
+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:
+ // Handle TOTP MFA case
+ case AuthSignInStep.confirmSignInWithSmsMfaCode:
+ // Handle SMS MFA case
+ case AuthSignInStep.confirmSignInWithNewPassword:
+ // Handle new password case
+ case AuthSignInStep.confirmSignInWithCustomChallenge:
+ // Handle custom challenge case
+ case AuthSignInStep.resetPassword:
+ // Handle reset password case
+ case AuthSignInStep.confirmSignUp:
+ // Handle confirm sign up case
+ case AuthSignInStep.done:
+ safePrint('Sign in is complete');
+ }
+}
+```
+## 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.
+
+
+
+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.
+
+
+
+```dart
+Future _handleSignInResult(SignInResult result) async {
+ switch (result.nextStep.signInStep) {
+ case AuthSignInStep.confirmSignInWithSmsMfaCode:
+ 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}');
+ }
+}
+```
+
+## 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.
+
+After the user enters the code, your implementation must pass the value to Amplify Auth `confirmSignIn` API.
+
+```dart
+Future _handleSignInResult(SignInResult result) async {
+ switch (result.nextStep.signInStep) {
+ // Β·Β·Β·
+ case AuthSignInStep.confirmSignInWithTotpMfaCode:
+ safePrint('Enter a one-time code from your registered authenticator app');
+ // Β·Β·Β·
+ }
+}
+
+// Then, pass the TOTP code to `confirmSignIn`
+
+Future confirmTotpUser(String totpCode) async {
+ try {
+ final result = await Amplify.Auth.confirmSignIn(
+ confirmationValue: totpCode,
+ );
+ return _handleSignInResult(result);
+ } on AuthException catch (e) {
+ safePrint('Error confirming TOTP code: ${e.message}');
+ }
+}
+```
+
+## 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.
+
+
+
+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 {
+ 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 resending code: ${e.message}');
+ }
+}
+```
+
+## 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.
+
+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.
+
+```dart
+Future _handleSignInResult(SignInResult result) async {
+ switch (result.nextStep.signInStep) {
+ // Β·Β·Β·
+ case AuthSignInStep.continueSignInWithTotpSetup:
+ final totpSetupDetails = result.nextStep.totpSetupDetails!;
+ final setupUri = totpSetupDetails.getSetupUri(appName: 'MyApp');
+ safePrint('Open URI to complete setup: $setupUri');
+ // Β·Β·Β·
+ }
+}
+
+// Then, pass the TOTP code to `confirmSignIn`
+
+Future confirmTotpUser(String totpCode) async {
+ try {
+ final result = await Amplify.Auth.confirmSignIn(
+ confirmationValue: totpCode,
+ );
+ return _handleSignInResult(result);
+ } on AuthException catch (e) {
+ safePrint('Error confirming TOTP code: ${e.message}');
+ }
+}
+```
+
+## 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).
+
+For example, your custom challenge Lambda may pass a prompt to the frontend which requires the user to enter a secret code.
+
+```dart
+Future _handleSignInResult(SignInResult result) async {
+ switch (result.nextStep.signInStep) {
+ // ...
+ case AuthSignInStep.confirmSignInWithCustomChallenge:
+ final parameters = result.nextStep.additionalInfo;
+ final hint = parameters['hint']!;
+ safePrint(hint); // "Enter the secret code"
+ // ...
+ }
+}
+```
+
+To complete this step, you should prompt the user for the custom challenge answer, and pass the answer to the `confirmSignIn` API.
+
+```dart
+Future confirmCustomChallenge(String answer) async {
+ try {
+ final result = await Amplify.Auth.confirmSignIn(
+ confirmationValue: answer,
+ );
+ return _handleSignInResult(result);
+ } on AuthException catch (e) {
+ safePrint('Error confirming custom challenge: ${e.message}');
+ }
+}
+```
+
+> **Warning:** **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 `Amplify.Auth.signIn` again.
+
+## 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.
+
+```dart
+Future _handleSignInResult(SignInResult result) async {
+ switch (result.nextStep.signInStep) {
+ // ...
+ case AuthSignInStep.confirmSignInWithNewPassword:
+ safePrint('Please enter a new password');
+ // ...
+ }
+}
+```
+
+```dart
+Future confirmNewPassword(String newPassword) async {
+ try {
+ final result = await Amplify.Auth.confirmSignIn(
+ confirmationValue: newPassword,
+ );
+ return _handleSignInResult(result);
+ } on AuthException catch (e) {
+ safePrint('Error confirming new password: ${e.message}');
+ }
+}
+```
+
+## 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.
+
+See the [reset password](/[platform]/build-a-backend/auth/manage-users/manage-passwords/) docs for more information.
+
+```dart
+Future _handleSignInResult(SignInResult result) async {
+ switch (result.nextStep.signInStep) {
+ // ...
+ case AuthSignInStep.resetPassword:
+ final resetResult = await Amplify.Auth.resetPassword(
+ username: username,
+ );
+ await _handleResetPasswordResult(resetResult);
+ // ...
+ }
+}
+
+Future _handleResetPasswordResult(ResetPasswordResult result) async {
+ switch (result.nextStep.updateStep) {
+ case AuthResetPasswordStep.confirmResetPasswordWithCode:
+ final codeDeliveryDetails = result.nextStep.codeDeliveryDetails!;
+ _handleCodeDelivery(codeDeliveryDetails);
+ case AuthResetPasswordStep.done:
+ safePrint('Successfully reset password');
+ }
+}
+
+void _handleCodeDelivery(AuthCodeDeliveryDetails codeDeliveryDetails) {
+ safePrint(
+ 'A confirmation code has been sent to ${codeDeliveryDetails.destination}. '
+ 'Please check your ${codeDeliveryDetails.deliveryMedium.name} for the code.',
+ );
+}
+```
+## 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.
+
+See the [confirm sign up](/[platform]/build-a-backend/auth/connect-your-frontend/sign-up/#confirm-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.
+
+
+
+```dart
+Future _handleSignInResult(SignInResult result) async {
+ switch (result.nextStep.signInStep) {
+ // ...
+ case AuthSignInStep.confirmSignUp:
+ // Resend the sign up code to the registered device.
+ final resendResult = await Amplify.Auth.resendSignUpCode(
+ username: username,
+ );
+ _handleCodeDelivery(resendResult.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 confirmSignUp({
+ required String username,
+ required String confirmationCode,
+}) async {
+ try {
+ await Amplify.Auth.confirmSignUp(
+ username: username,
+ confirmationCode: confirmationCode,
+ );
+ } on AuthException catch (e) {
+ safePrint('Error confirming sign up: ${e.message}');
+ }
+}
+```
+
+Once the sign up is confirmed, call `Amplify.Auth.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`.
+
+```dart
+Future _handleSignInResult(SignInResult result) async {
+ switch (result.nextStep.signInStep) {
+ // ...
+ case AuthSignInStep.done:
+ // Could also check that `result.isSignedIn` is `true`
+ safePrint('Sign in is complete');
+ }
+}
+```
+
+
+
+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.
+
+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 in the signin result.
+
+> **Warning:** *New enumeration values*
+>
+> When Amplify adds a new enumeration value (e.g., a new enum class entry or sealed class subtype in Kotlin, or a new enum value in Swift/Dart/Kotlin), it will publish a new minor version of the Amplify Library. Plugins that switch over enumeration values should include default handlers (an else branch in Kotlin or a default statement in Swift/Dart/Kotlin) to ensure that they are not impacted by new enumeration values.
+
+When called successfully, the signin APIs will return an `AuthSignInResult`. Inspect the `nextStep` property in the result to see if additional signin steps are required.
+The `nextStep` property is of enum type `AuthSignInStep`. Depending on its value, your code should take one of the following actions:
+
+#### [Java]
+
+```java
+try {
+ Amplify.Auth.signIn(
+ "hello@example.com",
+ "password",
+ result ->
+ {
+ AuthNextSignInStep nextStep = result.getNextStep();
+ switch (nextStep.getSignInStep()) {
+ 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_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: {
+ 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
+ // Then invoke `confirmSignIn` api with the MFA type
+ break;
+ }
+ case CONTINUE_SIGN_IN_WITH_FIRST_FACTOR_SELECTION: {
+ Log.i("AuthQuickstart", "Available authentication factors for this user: " + result.getNextStep().getAvailableFactors());
+ // Prompt the user to select which authentication factor they want to use to sign-in
+ // Then invoke `confirmSignIn` api with that selection
+ break;
+ }
+ case CONFIRM_SIGN_IN_WITH_SMS_MFA_CODE: {
+ Log.i("AuthQuickstart", "SMS code sent to " + nextStep.getCodeDeliveryDetails().getDestination());
+ Log.i("AuthQuickstart", "Additional Info :" + nextStep.getAdditionalInfo());
+ // Prompt the user to enter the SMS MFA code they received
+ // 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_PASSWORD: {
+ Log.i("AuthQuickstart", "Received next step as confirm sign in with password");
+ // Prompt the user to enter their password
+ // Then invoke `confirmSignIn` api with that password
+ 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
+ // Then invoke `confirmSignIn` api with the answer
+ break;
+ }
+ case CONFIRM_SIGN_IN_WITH_NEW_PASSWORD: {
+ Log.i("AuthQuickstart", "Sign in with new password, additional info: " + nextStep.getAdditionalInfo());
+ // Prompt the user to enter a new password
+ // Then invoke `confirmSignIn` api with new password
+ break;
+ }
+ case DONE: {
+ Log.i("AuthQuickstart", "SignIn complete");
+ // User has successfully signed in to the app
+ break;
+ }
+ }
+ },
+ error -> {
+ if (error instanceof UserNotConfirmedException) {
+ // User was not confirmed during the signup process.
+ // Invoke `confirmSignUp` api to confirm the user if
+ // they have the confirmation code. If they do not have the
+ // confirmation code, invoke `resendSignUpCode` to send the
+ // code again.
+ // After the user is confirmed, invoke the `signIn` api again.
+ Log.i("AuthQuickstart", "Signup confirmation required" + error);
+ } else if (error instanceof PasswordResetRequiredException) {
+ // User needs to reset their password.
+ // Invoke `resetPassword` api to start the reset password
+ // flow, and once reset password flow completes, invoke
+ // `signIn` api to trigger signIn flow again.
+ Log.i("AuthQuickstart", "Password reset required" + error);
+ } else {
+ Log.e("AuthQuickstart", "SignIn failed: " + error);
+ }
+ }
+ );
+} catch (Exception error) {
+ Log.e("AuthQuickstart", "Unexpected error occurred: " + error);
+}
+```
+
+#### [Kotlin - Callbacks]
+
+```kotlin
+try {
+ Amplify.Auth.signIn(
+ "hello@example.com",
+ "password",
+ { result ->
+ 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
+ }
+ 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.allowedMFATypes}")
+ // 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}")
+ // 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_SELECTION -> {
+ Log.i("AuthQuickstart", "Received next step as continue sign in by selecting MFA type")
+ Log.i("AuthQuickstart", "Allowed MFA types ${nextStep.allowedMFATypes}")
+ // Prompt the user to select the MFA type they want to use
+ // Then invoke `confirmSignIn` api with the MFA type
+ }
+ AuthSignInStep.CONTINUE_SIGN_IN_WITH_FIRST_FACTOR_SELECTION -> {
+ Log.i("AuthQuickstart", "Available authentication factors for this user: ${result.nextStep.availableFactors}")
+ // Prompt the user to select which authentication factor they want to use to sign-in
+ // Then invoke `confirmSignIn` api with that selection
+ }
+ AuthSignInStep.CONFIRM_SIGN_IN_WITH_SMS_MFA_CODE -> {
+ Log.i("AuthQuickstart", "SMS code sent to ${nextStep.codeDeliveryDetails?.destination}")
+ Log.i("AuthQuickstart", "Additional Info ${nextStep.additionalInfo}")
+ // 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_PASSWORD -> {
+ Log.i("AuthQuickstart", "Received next step as confirm sign in with password")
+ // Prompt the user to enter their password
+ // Then invoke `confirmSignIn` api with that password
+ }
+ AuthSignInStep.CONFIRM_SIGN_IN_WITH_CUSTOM_CHALLENGE -> {
+ Log.i("AuthQuickstart","Custom challenge, additional info: ${nextStep.additionalInfo}")
+ // Prompt the user to enter custom challenge answer
+ // Then invoke `confirmSignIn` api with the answer
+ }
+ AuthSignInStep.CONFIRM_SIGN_IN_WITH_NEW_PASSWORD -> {
+ Log.i("AuthQuickstart", "Sign in with new password, additional info: ${nextStep.additionalInfo}")
+ // Prompt the user to enter a new password
+ // Then invoke `confirmSignIn` api with new password
+ }
+ AuthSignInStep.DONE -> {
+ Log.i("AuthQuickstart", "SignIn complete")
+ // User has successfully signed in to the app
+ }
+ }
+
+ }
+ ) { error ->
+ when (error) {
+ is UserNotConfirmedException -> {
+ // User was not confirmed during the signup process.
+ // Invoke `confirmSignUp` api to confirm the user if
+ // they have the confirmation code. If they do not have the
+ // confirmation code, invoke `resendSignUpCode` to send the
+ // code again.
+ // After the user is confirmed, invoke the `signIn` api again.
+ Log.e("AuthQuickstart", "Signup confirmation required", error)
+ }
+ is PasswordResetRequiredException -> {
+ // User needs to reset their password.
+ // Invoke `resetPassword` api to start the reset password
+ // flow, and once reset password flow completes, invoke
+ // `signIn` api to trigger signIn flow again.
+ Log.e("AuthQuickstart", "Password reset required", error)
+ }
+ else -> {
+ Log.e("AuthQuickstart", "Unexpected error occurred: $error")
+ }
+ }
+ }
+} catch (error: Exception) {
+ Log.e("AuthQuickstart", "Unexpected error occurred: $error")
+}
+```
+
+#### [Kotlin - Coroutines]
+
+```kotlin
+try {
+ val result = Amplify.Auth.signIn(
+ "hello@example.com",
+ "password"
+ )
+ 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
+ }
+ 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.allowedMFATypes}")
+ // 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}")
+ // 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_SELECTION -> {
+ Log.i("AuthQuickstart", "Received next step as continue sign in by selecting MFA type")
+ Log.i("AuthQuickstart", "Allowed MFA types ${nextStep.allowedMFATypes}")
+ // Prompt the user to select the MFA type they want to use
+ // Then invoke `confirmSignIn` api with the MFA type
+ }
+ AuthSignInStep.CONTINUE_SIGN_IN_WITH_FIRST_FACTOR_SELECTION -> {
+ Log.i("AuthQuickstart", "Available authentication factors for this user: ${result.nextStep.availableFactors}")
+ // Prompt the user to select which authentication factor they want to use to sign-in
+ // Then invoke `confirmSignIn` api with that selection
+ }
+ AuthSignInStep.CONFIRM_SIGN_IN_WITH_SMS_MFA_CODE -> {
+ Log.i("AuthQuickstart", "SMS code sent to ${nextStep.codeDeliveryDetails?.destination}")
+ Log.i("AuthQuickstart", "Additional Info ${nextStep.additionalInfo}")
+ // 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_PASSWORD -> {
+ Log.i("AuthQuickstart", "Received next step as confirm sign in with password")
+ // Prompt the user to enter their password
+ // Then invoke `confirmSignIn` api with that password
+ }
+ AuthSignInStep.CONFIRM_SIGN_IN_WITH_CUSTOM_CHALLENGE -> {
+ Log.i("AuthQuickstart","Custom challenge, additional info: ${nextStep.additionalInfo}")
+ // Prompt the user to enter custom challenge answer
+ // Then invoke `confirmSignIn` api with the answer
+ }
+ AuthSignInStep.CONFIRM_SIGN_IN_WITH_NEW_PASSWORD -> {
+ Log.i("AuthQuickstart", "Sign in with new password, additional info: ${nextStep.additionalInfo}")
+ // Prompt the user to enter a new password
+ // Then invoke `confirmSignIn` api with new password
+ }
+ AuthSignInStep.DONE -> {
+ Log.i("AuthQuickstart", "SignIn complete")
+ // User has successfully signed in to the app
+ }
+ }
+} catch (error: Exception) {
+ when (error) {
+ is UserNotConfirmedException -> {
+ // User was not confirmed during the signup process.
+ // Invoke `confirmSignUp` api to confirm the user if
+ // they have the confirmation code. If they do not have the
+ // confirmation code, invoke `resendSignUpCode` to send the
+ // code again.
+ // After the user is confirmed, invoke the `signIn` api again.
+ Log.e("AuthQuickstart", "Signup confirmation required", error)
+ }
+ is PasswordResetRequiredException -> {
+ // User needs to reset their password.
+ // Invoke `resetPassword` api to start the reset password
+ // flow, and once reset password flow completes, invoke
+ // `signIn` api to trigger signIn flow again.
+ Log.e("AuthQuickstart", "Password reset required", error)
+ }
+ else -> {
+ Log.e("AuthQuickstart", "Unexpected error occurred: $error")
+ }
+ }
+}
+```
+
+#### [RxJava]
+
+```java
+RxAmplify.Auth.signIn("hello@example.com", "password").subscribe(
+ result ->
+ {
+ AuthNextSignInStep nextStep = result.getNextStep();
+ switch (nextStep.getSignInStep()) {
+ 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_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: {
+ 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
+ // Then invoke `confirmSignIn` api with the MFA type
+ break;
+ }
+ case CONTINUE_SIGN_IN_WITH_FIRST_FACTOR_SELECTION: {
+ Log.i("AuthQuickstart", "Available authentication factors for this user: " + result.getNextStep().getAvailableFactors());
+ // Prompt the user to select which authentication factor they want to use to sign-in
+ // Then invoke `confirmSignIn` api with that selection
+ break;
+ }
+ case CONFIRM_SIGN_IN_WITH_SMS_MFA_CODE: {
+ Log.i("AuthQuickstart", "SMS code sent to " + nextStep.getCodeDeliveryDetails().getDestination());
+ Log.i("AuthQuickstart", "Additional Info :" + nextStep.getAdditionalInfo());
+ // Prompt the user to enter the SMS MFA code they received
+ // 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_PASSWORD: {
+ Log.i("AuthQuickstart", "Received next step as confirm sign in with password");
+ // Prompt the user to enter their password
+ // Then invoke `confirmSignIn` api with that password
+ 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
+ // Then invoke `confirmSignIn` api with the answer
+ break;
+ }
+ case CONFIRM_SIGN_IN_WITH_NEW_PASSWORD: {
+ Log.i("AuthQuickstart", "Sign in with new password, additional info: " + nextStep.getAdditionalInfo());
+ // Prompt the user to enter a new password
+ // Then invoke `confirmSignIn` api with new password
+ break;
+ }
+ case DONE: {
+ Log.i("AuthQuickstart", "SignIn complete");
+ // User has successfully signed in to the app
+ break;
+ }
+ }
+ },
+ error -> {
+ if (error instanceof UserNotConfirmedException) {
+ // User was not confirmed during the signup process.
+ // Invoke `confirmSignUp` api to confirm the user if
+ // they have the confirmation code. If they do not have the
+ // confirmation code, invoke `resendSignUpCode` to send the
+ // code again.
+ // After the user is confirmed, invoke the `signIn` api again.
+ Log.i("AuthQuickstart", "Signup confirmation required" + error);
+ } else if (error instanceof PasswordResetRequiredException) {
+ // User needs to reset their password.
+ // Invoke `resetPassword` api to start the reset password
+ // flow, and once reset password flow completes, invoke
+ // `signIn` api to trigger signIn flow again.
+ Log.i("AuthQuickstart", "Password reset required" + error);
+ } else {
+ Log.e("AuthQuickstart", "SignIn failed: " + error);
+ }
+ }
+);
+```
+
+## 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.
+
+
+
+**Note:** The result also includes an `AuthCodeDeliveryDetails` member. It includes additional information about the code delivery such as the partial phone number of the SMS recipient.
+
+
+
+#### [Java]
+
+```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 `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);
+}
+```
+
+#### [Kotlin - Callbacks]
+
+```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 `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")
+}
+```
+
+#### [Kotlin - Coroutines]
+
+```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 `signInResult.isSignedIn` is true, the next step
+ // is 'done', and the user is now signed in.
+ }
+} catch (error: Exception) {
+ Log.e("AuthQuickstart", "Unexpected error: $error")
+}
+```
+
+#### [RxJava]
+
+```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 `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)
+ );
+```
+
+## 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.
+
+## Confirm sign-in with Email MFA
+
+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.
+
+
+
+**Note:** The result also includes an `AuthCodeDeliveryDetails` member. It includes additional information about the code delivery such as the partial email address of the recipient.
+
+
+
+## Confirm sign-in with OTP
+
+If the next step is `CONFIRM_SIGN_IN_WITH_OTP`, Amplify Auth has sent the user a random code to the medium of the user's choosing (e.g. SMS or email) 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.
+
+
+
+**Note:** 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.
+
+
+
+## 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.
+
+## 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.
+
+## Continue sign-in with First Factor Selection
+
+If the next step is `CONTINUE_SIGN_IN_WITH_FIRST_FACTOR_SELECTION`, the user must select an authentication factor to use either because they did not specify one or because the one they chose is not supported (e.g. selecting SMS when they don't have a phone number registered to their account). Amplify Auth currently supports SMS, email, password, and webauthn as authentication factors. After the user selects an authentication method, your implementation must pass the selected authentication method to Amplify Auth using `confirmSignIn` API.
+
+Visit the [sign-in documentation](/[platform]/build-a-backend/auth/connect-your-frontend/sign-in/#sign-in-with-passwordless-methods) to see examples on how to call the `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.
+
+#### [Java]
+
+```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)
+ );
+} catch (Exception error) {
+ Log.e("AuthQuickstart", "Unexpected error: " + error);
+}
+```
+
+#### [Kotlin - Callbacks]
+
+```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")
+ }
+} catch (error: Exception) {
+ Log.e("AuthQuickstart", "Unexpected error: $error")
+}
+```
+
+#### [Kotlin - Coroutines]
+
+```kotlin
+try {
+ val result = Amplify.Auth.confirmSignIn(
+ "challenge answer"
+ )
+ 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.
+ }
+} catch (error: Exception) {
+ Log.e("AuthQuickstart", "Unexpected error: $error")
+}
+```
+
+#### [RxJava]
+
+```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)
+);
+```
+
+> **Warning:** **Special Handling on `confirmSignIn`**
+>
+> During a confirmSignIn call if `failAuthentication=true` is returned by the Lambda the session of the request gets invalidated by cognito, a NotAuthorizedException is returned and a new signIn call is expected via Amplify.Auth.signIn
+>
+> ```java
+NotAuthorizedException{message=Failed since user is not authorized., cause=NotAuthorizedException(message=Invalid session for the user.), recoverySuggestion=Check whether the given values are correct and the user is authorized to perform the operation.}
+```
+
+## 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.
+
+#### [Java]
+
+```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 `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);
+}
+```
+
+#### [Kotlin - Callbacks]
+
+```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}")
+ }
+ }
+ ) { error ->
+ Log.e("AuthQuickstart", "Confirm sign in failed: $error")
+ }
+} catch (error: Exception) {
+ Log.e("AuthQuickstart", "Unexpected error: $error")
+}
+}
+```
+
+#### [Kotlin - Coroutines]
+
+```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}")
+ }
+} catch (error: Exception) {
+ Log.e("AuthQuickstart", "Unexpected error: $error")
+}
+```
+
+#### [RxJava]
+
+```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());
+ }
+ },
+ error -> Log.e("AuthQuickstart", "Confirm sign in failed: " + error)
+ );
+```
+
+## 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.
+
+#### [Java]
+
+```java
+try {
+ Amplify.Auth.resetPassword(
+ "username",
+ result -> Log.i("AuthQuickstart", "Reset password succeeded"),
+ error -> Log.e("AuthQuickstart", "Reset password failed : " + error)
+ );
+} catch (Exception error) {
+ Log.e("AuthQuickstart", "Unexpected error: " + error);
+}
+```
+
+#### [Kotlin - Callbacks]
+
+```kotlin
+try {
+ Amplify.Auth.resetPassword(
+ "username",
+ {
+ Log.i("AuthQuickstart", "Reset password succeeded")
+ }
+ ) { error ->
+ Log.e("AuthQuickstart", "Reset password failed : $error")
+ }
+} catch (error: Exception) {
+ Log.e("AuthQuickstart", "Unexpected error: $error")
+}
+```
+
+#### [Kotlin - Coroutines]
+
+```kotlin
+try {
+ Amplify.Auth.resetPassword("username")
+ Log.i("AuthQuickstart", "Reset password succeeded")
+} catch (error: Exception) {
+ Log.e("AuthQuickstart", "Unexpected error: $error")
+}
+```
+
+#### [RxJava]
+
+```java
+RxAmplify.Auth.resetPassword(
+ "username").subscribe(
+ result -> Log.i("AuthQuickstart", "Reset password succeeded"),
+ error -> Log.e("AuthQuickstart", "Reset password failed : " + error)
+);
+```
+
+## 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.
+
+#### [Java]
+
+```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 - Callbacks]
+
+```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 - Coroutines]
+
+```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")
+}
+```
+
+#### [RxJava]
+
+```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)
+);
+```
+
+## 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.
+
+
+**Note:** An empty string will be assigned to userId and/or username, if the values are not present in the accessToken.
+
+
+#### [Java]
+
+```java
+ try {
+ Amplify.Auth.getCurrentUser(
+ result -> Log.i("AuthQuickstart", "Current user details are:" + result.toString(),
+ error -> Log.e("AuthQuickstart", "getCurrentUser failed with an exception: " + error)
+ );
+ } catch (Exception error) {
+ Log.e("AuthQuickstart", "unexpected error: " + error);
+ }
+```
+
+#### [Kotlin - Callbacks]
+
+```kotlin
+Amplify.Auth.getCurrentUser({
+ Log.i("AuthQuickStart", "Current user details are: $it")},{
+ Log.e("AuthQuickStart", "getCurrentUser failed with an exception: $it")
+})
+```
+
+#### [Kotlin - Coroutines]
+
+```kotlin
+try {
+ val result = Amplify.Auth.getCurrentUser()
+ Log.i("AuthQuickstart", "Current user details are: $result")
+} catch (error: Exception) {
+ Log.e("AuthQuickstart", "getCurrentUser failed with an exception: $error")
+}
+```
+
+#### [RxJava]
+
+```java
+ RxAmplify.Auth.getCurrentUser().subscribe(
+ result -> Log.i("AuthQuickStart getCurrentUser: " + result.toString()),
+ error -> Log.e("AuthQuickStart", error.toString())
+ );
+```
+
+## 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`.
+
+
+
+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.
+
+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 in the signin result.
+
+> **Warning:** *New enumeration values*
+>
+> When Amplify adds a new enumeration value (e.g., a new enum class entry or sealed class subtype in Kotlin, or a new enum value in Swift/Dart/Kotlin), it will publish a new minor version of the Amplify Library. Plugins that switch over enumeration values should include default handlers (an else branch in Kotlin or a default statement in Swift/Dart/Kotlin) to ensure that they are not impacted by new enumeration values.
+
+When called successfully, the signin APIs will return an `AuthSignInResult`. Inspect the `nextStep` property in the result to see if additional signin steps are required.
+
+```swift
+func signIn(username: String, password: String) async {
+ do {
+ let signInResult = try await Amplify.Auth.signIn(username: username, password: password)
+ switch signInResult.nextStep {
+ case .confirmSignInWithSMSMFACode(let deliveryDetails, let info):
+ print("SMS code sent to \(deliveryDetails.destination)")
+ print("Additional info \(String(describing: info))")
+
+ // Prompt the user to enter the SMSMFA code they received
+ // Then invoke `confirmSignIn` api with the code
+
+ case .confirmSignInWithTOTPCode:
+ print("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
+
+ 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 .continueSignInWithFirstFactorSelection(let allowedFactors):
+ print("Received next step as continue sign in by selecting first factor")
+ print("Allowed factors \(allowedFactors)")
+
+ // Prompt the user to select the first factor they want to use
+ // Then invoke `confirmSignIn` api with the factor
+
+ case .confirmSignInWithPassword:
+ print("Received next step as confirm sign in with password")
+
+ // Prompt the user to enter the password
+ // Then invoke `confirmSignIn` api with the password
+
+ case .continueSignInWithTOTPSetup(let setUpDetails):
+ print("Received next step as continue sign in by setting up TOTP")
+ print("Shared secret that will be used to set up TOTP in the authenticator app \(setUpDetails.sharedSecret)")
+
+ // 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)")
+
+ // Prompt the user to select the MFA type they want to use
+ // Then invoke `confirmSignIn` api with the MFA type
+
+ case .confirmSignInWithCustomChallenge(let info):
+ print("Custom challenge, additional info \(String(describing: info))")
+
+ // Prompt the user to enter custom challenge answer
+ // Then invoke `confirmSignIn` api with the answer
+
+ case .confirmSignInWithNewPassword(let info):
+ print("New password additional info \(String(describing: info))")
+
+ // Prompt the user to enter a new password
+ // Then invoke `confirmSignIn` api with new password
+
+ case .resetPassword(let info):
+ print("Reset password additional info \(String(describing: info))")
+
+ // User needs to reset their password.
+ // Invoke `resetPassword` api to start the reset password
+ // flow, and once reset password flow completes, invoke
+ // `signIn` api to trigger signin flow again.
+
+ case .confirmSignUp(let info):
+ print("Confirm signup additional info \(String(describing: info))")
+
+ // User was not confirmed during the signup process.
+ // Invoke `confirmSignUp` api to confirm the user if
+ // they have the confirmation code. If they do not have the
+ // confirmation code, invoke `resendSignUpCode` to send the
+ // code again.
+ // After the user is confirmed, invoke the `signIn` api again.
+ case .done:
+
+ // Use has successfully signed in to the app
+ print("Signin complete")
+ }
+ } catch let error as AuthError{
+ print ("Sign in failed \(error)")
+ } catch {
+ print("Unexpected error: \(error)")
+ }
+}
+```
+
+The `nextStep` property is of enum type `AuthSignInStep`. Depending on its value, your code should take one of the following actions:
+
+## 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.
+
+#### [Async/Await]
+
+```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)")
+ }
+}
+```
+
+#### [Combine]
+
+```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.
+ }
+ }
+}
+```
+
+## 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.
+
+After the user enters the code, your implementation must pass the value to Amplify Auth `confirmSignIn` API.
+
+#### [Async/Await]
+
+```swift
+func confirmSignIn(totpCode: String) async {
+ do {
+ let signInResult = try await Amplify.Auth.confirmSignIn(challengeResponse: totpCode)
+ 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 {
+ print("Confirm sign in failed \(error)")
+ }
+}
+```
+
+#### [Combine]
+
+```swift
+func confirmSignIn(totpCode: String) -> AnyCancellable {
+ Amplify.Publisher.create {
+ try await Amplify.Auth.confirmSignIn(challengeResponse: totpCode)
+ }.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.
+ }
+ }
+}
+```
+
+## 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.
+
+> **Info:** **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.
+
+#### [Async/Await]
+
+```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)")
+ }
+}
+```
+
+#### [Combine]
+
+```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.
+
+#### [Async/Await]
+
+```swift
+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)")
+ }
+}
+```
+
+#### [Combine]
+
+```swift
+func confirmSignInWithTOTPAsMFASelection() -> AnyCancellable {
+ Amplify.Publisher.create {
+ try await Amplify.Auth.confirmSignIn(
+ challengeResponse: MFAType.totp.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")
+ }
+ }
+}
+```
+
+## 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.
+
+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.
+
+```swift
+// Confirm sign in with TOTP setup
+case .continueSignInWithTOTPSetup(let setUpDetails):
+
+ /// appName parameter will help distinguish the account in the Authenticator app
+ let setupURI = try setUpDetails.getSetupURI(appName: ">")
+
+ print("TOTP Setup URI: \(setupURI)")
+```
+
+#### [Async/Await]
+
+```swift
+func confirmSignInWithTOTPSetup(totpCodeFromAuthenticatorApp: String) async {
+ do {
+ let signInResult = try await Amplify.Auth.confirmSignIn(
+ challengeResponse: totpCodeFromAuthenticatorApp)
+
+ 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 {
+ print("Confirm sign in failed \(error)")
+ }
+}
+```
+
+#### [Combine]
+
+```swift
+func confirmSignInWithTOTPSetup(totpCodeFromAuthenticatorApp: String) -> AnyCancellable {
+ Amplify.Publisher.create {
+ try await Amplify.Auth.confirmSignIn(
+ challengeResponse: totpCodeFromAuthenticatorApp)
+ }.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 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.
+
+#### [Async/Await]
+
+```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)")
+ }
+}
+```
+
+#### [Combine]
+
+```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.
+
+#### [Async/Await]
+
+```swift
+func confirmSignIn(challengeAnswerFromUser: String) async {
+ do {
+ let signInResult = try await Amplify.Auth.confirmSignIn(challengeResponse: challengeAnswerFromUser)
+ 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)")
+ }
+}
+```
+
+#### [Combine]
+
+```swift
+func confirmSignIn(challengeAnswerFromUser: String) -> AnyCancellable {
+ Amplify.Publisher.create {
+ try await Amplify.Auth.confirmSignIn(challengeResponse: challengeAnswerFromUser)
+ }.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.
+ }
+ }
+}
+```
+
+> **Warning:** **Special Handling on `confirmSignIn`**
+>
+> During a confirmSignIn call if `failAuthentication=true` is returned by the Lambda function the session of the request gets invalidated by cognito, a NotAuthorizedException is returned and a new signIn call is expected via Amplify.Auth.signIn
+>
+> ```swift
+Exception: notAuthorized{message=Failed since user is not authorized., cause=NotAuthorizedException(message=Invalid session for the user.), recoverySuggestion=Check whether the given values are correct and the user is authorized to perform the operation.}
+```
+
+## 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.
+
+#### [Async/Await]
+
+```swift
+func confirmSignIn(newPasswordFromUser: String) async {
+ do {
+ let signInResult = try await Amplify.Auth.confirmSignIn(challengeResponse: newPasswordFromUser)
+ 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)")
+ }
+}
+```
+
+#### [Combine]
+
+```swift
+func confirmSignIn(newPasswordFromUser: String) -> AnyCancellable {
+ Amplify.Publisher.create {
+ try await Amplify.Auth.confirmSignIn(challengeResponse: newPasswordFromUser)
+ }.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.
+ }
+ }
+}
+```
+
+## 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.
+
+#### [Async/Await]
+
+```swift
+func resetPassword(username: String) async {
+ do {
+ let resetPasswordResult = try await Amplify.Auth.resetPassword(for: username)
+ print("Reset password succeeded.")
+ print("Next step: \(resetPasswordResult.nextStep)")
+ } catch let error as AuthError {
+ print("Reset password failed \(error)")
+ } catch {
+ print("Unexpected error: \(error)")
+ }
+}
+```
+
+#### [Combine]
+
+```swift
+func resetPassword(username: String) -> AnyCancellable {
+ Amplify.Publisher.create {
+ try await Amplify.Auth.resetPassword(for: username)
+ }.sink {
+ if case let .failure(authError) = $0 {
+ print("Reset password failed \(authError)")
+ }
+ }
+ receiveValue: { resetPasswordResult in
+ print("Reset password succeeded.")
+ print("Next step: \(resetPasswordResult.nextStep)")
+ }
+}
+```
+
+## 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.
+
+#### [Async/Await]
+
+```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)")
+ }
+}
+```
+
+#### [Combine]
+
+```swift
+func confirmSignUp(for username: String, with confirmationCode: String) -> AnyCancellable {
+ Amplify.Publisher.create {
+ try await Amplify.Auth.confirmSignUp(for: username, confirmationCode: confirmationCode)
+ }.sink {
+ if case let .failure(authError) = $0 {
+ print("An error occurred while confirming sign up \(authError)")
+ }
+ }
+ receiveValue: { _ in
+ print("Confirm signUp succeeded")
+ }
+}
+```
+
+## 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`.
+
+
+---
+
+---
+title: "Manage users"
+section: "build-a-backend/auth"
+platforms: ["android", "angular", "flutter", "javascript", "nextjs", "react", "react-native", "swift", "vue"]
+gen: 2
+last-updated: "2024-05-01T21:28:13.000Z"
+url: "https://docs.amplify.aws/react/build-a-backend/auth/manage-users/"
+---
+
+
+
+---
+
+---
+title: "With admin actions"
+section: "build-a-backend/auth/manage-users"
+platforms: ["android", "angular", "flutter", "javascript", "nextjs", "react", "react-native", "swift", "vue"]
+gen: 2
+last-updated: "2024-05-02T01:41:16.000Z"
+url: "https://docs.amplify.aws/react/build-a-backend/auth/manage-users/with-admin-actions/"
+---
+
+Amplify Auth can be managed with the [AWS SDK's `@aws-sdk/client-cognito-identity-provider` package](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/cognito-identity-provider/). This package is intended to use server-side, and can be used within a Function. This example focuses on the `addUserToGroup` action and will be defined as a [custom mutation](/[platform]/build-a-backend/data/custom-business-logic/#step-1---define-a-custom-query-or-mutation).
+
+To get started, create an "ADMINS" group that will be used to authorize the mutation:
+
+```ts title="amplify/auth/resource.ts"
+import { defineAuth } from "@aws-amplify/backend"
+
+export const auth = defineAuth({
+ loginWith: {
+ email: true,
+ },
+ // highlight-next-line
+ groups: ["ADMINS"]
+})
+```
+
+Next, create the Function resource:
+
+```ts title="amplify/data/add-user-to-group/resource.ts"
+import { defineFunction } from "@aws-amplify/backend"
+
+export const addUserToGroup = defineFunction({
+ name: "add-user-to-group",
+})
+```
+
+Then, in your auth resources, grant access for the function to perform the `addUserToGroup` action. [Learn more about granting access to auth resources](/[platform]/build-a-backend/auth/grant-access-to-auth-resources).
+
+```ts title="amplify/auth/resource.ts"
+import { defineAuth } from "@aws-amplify/backend"
+// highlight-next-line
+import { addUserToGroup } from "../data/add-user-to-group/resource"
+
+export const auth = defineAuth({
+ loginWith: {
+ email: true,
+ },
+ groups: ["ADMINS"],
+ // highlight-start
+ access: (allow) => [
+ allow.resource(addUserToGroup).to(["addUserToGroup"])
+ ],
+ // highlight-end
+})
+```
+
+You're now ready to define the custom mutation. Here you will use the newly-created `addUserToGroup` function resource to handle the `addUserToGroup` mutation. This mutation can only be called by a user in the "ADMINS" group.
+
+```ts title="amplify/data/resource.ts"
+import type { ClientSchema } from "@aws-amplify/backend"
+import { a, defineData } from "@aws-amplify/backend"
+import { addUserToGroup } from "./resource"
+
+const schema = a.schema({
+ addUserToGroup: a
+ .mutation()
+ .arguments({
+ userId: a.string().required(),
+ groupName: a.string().required(),
+ })
+ .authorization((allow) => [allow.group("ADMINS")])
+ .handler(a.handler.function(addUserToGroup))
+ .returns(a.json())
+})
+
+export type Schema = ClientSchema
+
+export const data = defineData({
+ schema,
+ authorizationModes: {
+ defaultAuthorizationMode: "iam",
+ },
+})
+```
+
+Lastly, create the function's handler using the exported client schema to type the handler function, and the generated `env` to specify the user pool ID you'd like to interact with:
+
+```ts title="amplify/data/add-user-to-group/handler.ts"
+import type { Schema } from "../resource"
+import { env } from "$amplify/env/add-user-to-group"
+import {
+ AdminAddUserToGroupCommand,
+ CognitoIdentityProviderClient,
+} from "@aws-sdk/client-cognito-identity-provider"
+
+type Handler = Schema["addUserToGroup"]["functionHandler"]
+const client = new CognitoIdentityProviderClient()
+
+export const handler: Handler = async (event) => {
+ const { userId, groupName } = event.arguments
+ const command = new AdminAddUserToGroupCommand({
+ Username: userId,
+ GroupName: groupName,
+ UserPoolId: env.AMPLIFY_AUTH_USERPOOL_ID,
+ })
+ const response = await client.send(command)
+ return response
+}
+```
+
+
+In your frontend, use the generated client to call your mutation using the group name and the user's ID.
+
+
+```ts title="src/client.ts"
+import type { Schema } from "../amplify/data/resource"
+import { generateClient } from "aws-amplify/data"
+
+const client = generateClient()
+
+await client.mutations.addUserToGroup({
+ groupName: "ADMINS",
+ userId: "5468d468-4061-70ed-8870-45c766d26225",
+})
+```
+
+
+
+
+
+
+
+
+
+
+
+
+---
+
+---
+title: "Manage passwords"
+section: "build-a-backend/auth/manage-users"
+platforms: ["android", "angular", "flutter", "javascript", "nextjs", "react", "react-native", "swift", "vue"]
+gen: 2
+last-updated: "2024-10-14T15:02:39.000Z"
+url: "https://docs.amplify.aws/react/build-a-backend/auth/manage-users/manage-passwords/"
+---
+
+Amplify Auth provides a secure way for your users to change their password or recover a forgotten password.
+
+## Understand password default settings
+
+By default, your users can retrieve access to their accounts if they forgot their password by using either their phone or email. The following are the default account recovery methods used when either `phone` or `email` are used as login options.
+
+| Login option | User account verification channel |
+| ------------------- | --------------------------------- |
+| `phone` | Phone Number |
+| `email` | Email |
+| `email` and `phone` | Email |
+
+## Reset Password
+
+To reset a user's password, use the `resetPassword` API which will send a reset code to the destination (e.g. email or SMS) based on the user's settings.
+
+
+```ts
+import { resetPassword } from 'aws-amplify/auth';
+
+const output = await resetPassword({
+ username: "hello@mycompany.com"
+});
+
+const { nextStep } = output;
+switch (nextStep.resetPasswordStep) {
+ case 'CONFIRM_RESET_PASSWORD_WITH_CODE':
+ const codeDeliveryDetails = nextStep.codeDeliveryDetails;
+ console.log(
+ `Confirmation code was sent to ${codeDeliveryDetails.deliveryMedium}`
+ );
+ // Collect the confirmation code from the user and pass to confirmResetPassword.
+ break;
+ case 'DONE':
+ console.log('Successfully reset password.');
+ break;
+}
+```
+
+
+```dart
+Future resetPassword(String username) async {
+ try {
+ final result = await Amplify.Auth.resetPassword(
+ username: username,
+ );
+ await _handleResetPasswordResult(result);
+ } on AuthException catch (e) {
+ safePrint('Error resetting password: ${e.message}');
+ }
+}
+```
+
+```dart
+Future _handleResetPasswordResult(ResetPasswordResult result) async {
+ switch (result.nextStep.updateStep) {
+ case AuthResetPasswordStep.confirmResetPasswordWithCode:
+ final codeDeliveryDetails = result.nextStep.codeDeliveryDetails!;
+ _handleCodeDelivery(codeDeliveryDetails);
+ break;
+ case AuthResetPasswordStep.done:
+ safePrint('Successfully reset password');
+ break;
+ }
+}
+```
+
+
+
+#### [Java]
+
+```java
+Amplify.Auth.resetPassword(
+ "username",
+ result -> Log.i("AuthQuickstart", result.toString()),
+ error -> Log.e("AuthQuickstart", error.toString())
+);
+```
+
+#### [Kotlin - Callbacks]
+
+```kotlin
+Amplify.Auth.resetPassword("username",
+ { Log.i("AuthQuickstart", "Password reset OK: $it") },
+ { Log.e("AuthQuickstart", "Password reset failed", it) }
+)
+```
+
+#### [Kotlin - Coroutines]
+
+```kotlin
+try {
+ val result = Amplify.Auth.resetPassword("username")
+ Log.i("AuthQuickstart", "Password reset OK: $result")
+} catch (error: AuthException) {
+ Log.e("AuthQuickstart", "Password reset failed", error)
+}
+```
+
+#### [RxJava]
+
+```java
+RxAmplify.Auth.resetPassword("username")
+ .subscribe(
+ result -> Log.i("AuthQuickstart", result.toString()),
+ error -> Log.e("AuthQuickstart", error.toString())
+ );
+```
+
+
+
+
+#### [Async/Await]
+
+```swift
+func resetPassword(username: String) async {
+ do {
+ let resetResult = try await Amplify.Auth.resetPassword(for: username)
+ switch resetResult.nextStep {
+ case .confirmResetPasswordWithCode(let deliveryDetails, let info):
+ print("Confirm reset password with code send to - \(deliveryDetails) \(String(describing: info))")
+ case .done:
+ print("Reset completed")
+ }
+ } catch let error as AuthError {
+ print("Reset password failed with error \(error)")
+ } catch {
+ print("Unexpected error: \(error)")
+ }
+}
+```
+
+#### [Combine]
+
+```swift
+func resetPassword(username: String) -> AnyCancellable {
+ Amplify.Publisher.create {
+ try await Amplify.Auth.resetPassword(for: username)
+ }.sink {
+ if case let .failure(authError) = $0 {
+ print("Reset password failed with error \(authError)")
+ }
+ }
+ receiveValue: { resetResult in
+ switch resetResult.nextStep {
+ case .confirmResetPasswordWithCode(let deliveryDetails, let info):
+ print("Confirm reset password with code send to - \(deliveryDetails) \(String(describing: info))")
+ case .done:
+ print("Reset completed")
+ }
+ }
+}
+```
+
+Usually, resetting the password require you to verify that it is the actual user that tried to reset the password. The next step above will be `.confirmResetPasswordWithCode`.
+
+If you would like to display a more specific view or messaging to your users based the error that occurred, you can handle this by downcasting the `underlyingError` to `AWSCognitoAuthError`.
+
+```swift
+if let authError = error as? AuthError,
+ let cognitoAuthError = authError.underlyingError as? AWSCognitoAuthError {
+ switch cognitoAuthError {
+ case .userNotFound:
+ print("User not found")
+ case .invalidParameter:
+ print("Invalid Parameter)
+ default:
+ break
+ }
+}
+```
+
+
+To complete the password reset process, invoke the `confirmResetPassword` API with the code your user received and the new password they want to set.
+
+
+```ts
+import { confirmResetPassword } from 'aws-amplify/auth';
+
+await confirmResetPassword({
+ username: "hello@mycompany.com",
+ confirmationCode: "123456",
+ newPassword: "hunter3",
+});
+```
+
+
+```dart
+Future confirmResetPassword({
+ required String username,
+ required String newPassword,
+ required String confirmationCode,
+}) async {
+ try {
+ final result = await Amplify.Auth.confirmResetPassword(
+ username: username,
+ newPassword: newPassword,
+ confirmationCode: confirmationCode,
+ );
+ safePrint('Password reset complete: ${result.isPasswordReset}');
+ } on AuthException catch (e) {
+ safePrint('Error resetting password: ${e.message}');
+ }
+}
+```
+
+
+
+#### [Java]
+
+```java
+Amplify.Auth.confirmResetPassword(
+ "Username",
+ "NewPassword123",
+ "confirmation code you received",
+ () -> Log.i("AuthQuickstart", "New password confirmed"),
+ error -> Log.e("AuthQuickstart", error.toString())
+);
+```
+
+#### [Kotlin - Callbacks]
+
+```kotlin
+Amplify.Auth.confirmResetPassword("Username", "NewPassword123", "confirmation code",
+ { Log.i("AuthQuickstart", "New password confirmed") },
+ { Log.e("AuthQuickstart", "Failed to confirm password reset", it) }
+)
+```
+
+#### [Kotlin - Coroutines]
+
+```kotlin
+try {
+ Amplify.Auth.confirmResetPassword("Username", "NewPassword123", "code you received")
+ Log.i("AuthQuickstart", "New password confirmed")
+} catch (error: AuthException) {
+ Log.e("AuthQuickstart", "Failed to confirm password reset", error)
+}
+```
+
+#### [RxJava]
+
+```java
+RxAmplify.Auth.confirmResetPassword("Username","NewPassword123", "confirmation code")
+ .subscribe(
+ () -> Log.i("AuthQuickstart", "New password confirmed"),
+ error -> Log.e("AuthQuickstart", error.toString())
+ );
+```
+
+
+
+
+#### [Async/Await]
+
+```swift
+func confirmResetPassword(
+ username: String,
+ newPassword: String,
+ confirmationCode: String
+) async {
+ do {
+ try await Amplify.Auth.confirmResetPassword(
+ for: username,
+ with: newPassword,
+ confirmationCode: confirmationCode
+ )
+ print("Password reset confirmed")
+ } catch let error as AuthError {
+ print("Reset password failed with error \(error)")
+ } catch {
+ print("Unexpected error: \(error)")
+ }
+}
+```
+
+#### [Combine]
+
+```swift
+func confirmResetPassword(
+ username: String,
+ newPassword: String,
+ confirmationCode: String
+) -> AnyCancellable {
+ Amplify.Publisher.create {
+ try await Amplify.Auth.confirmResetPassword(
+ for: username,
+ with: newPassword,
+ confirmationCode: confirmationCode
+ )
+ }.sink {
+ if case let .failure(authError) = $0 {
+ print("Reset password failed with error \(authError)")
+ }
+ }
+ receiveValue: {
+ print("Password reset confirmed")
+ }
+}
+```
+
+
+
+## Update password
+
+You can update a signed in user's password using the `updatePassword` API.
+
+
+```ts
+import { updatePassword } from 'aws-amplify/auth';
+
+await updatePassword({
+ oldPassword: "hunter2",
+ newPassword: "hunter3",
+});
+```
+
+
+```dart
+Future updatePassword({
+ required String oldPassword,
+ required String newPassword,
+}) async {
+ try {
+ await Amplify.Auth.updatePassword(
+ oldPassword: oldPassword,
+ newPassword: newPassword,
+ );
+ } on AuthException catch (e) {
+ safePrint('Error updating password: ${e.message}');
+ }
+}
+```
+
+
+
+#### [Java]
+
+```java
+Amplify.Auth.updatePassword(
+ "existingPassword",
+ "newPassword",
+ () -> Log.i("AuthQuickstart", "Updated password successfully"),
+ error -> Log.e("AuthQuickstart", error.toString())
+);
+```
+
+#### [Kotlin - Callbacks]
+
+```kotlin
+Amplify.Auth.updatePassword("existingPassword", "newPassword",
+ { Log.i("AuthQuickstart", "Updated password successfully") },
+ { Log.e("AuthQuickstart", "Password update failed", it) }
+)
+```
+
+#### [Kotlin - Coroutines]
+
+```kotlin
+try {
+ Amplify.Auth.updatePassword("existingPassword", "newPassword")
+ Log.i("AuthQuickstart", "Updated password successfully")
+} catch (error: AuthException) {
+ Log.e("AuthQuickstart", "Password update failed", error)
+}
+```
+
+#### [RxJava]
+
+```java
+RxAmplify.Auth.updatePassword("existingPassword", "newPassword")
+ .subscribe(
+ () -> Log.i("AuthQuickstart", "Updated password successfully"),
+ error -> Log.e("AuthQuickstart", error.toString())
+ );
+```
+
+
+
+
+#### [Async/Await]
+
+```swift
+func changePassword(oldPassword: String, newPassword: String) async {
+ do {
+ try await Amplify.Auth.update(oldPassword: oldPassword, to: newPassword)
+ print("Change password succeeded")
+ } catch let error as AuthError {
+ print("Change password failed with error \(error)")
+ } catch {
+ print("Unexpected error: \(error)")
+ }
+}
+```
+
+#### [Combine]
+
+```swift
+func changePassword(oldPassword: String, newPassword: String) -> AnyCancellable {
+ Amplify.Publisher.create {
+ try await Amplify.Auth.update(oldPassword: oldPassword, to: newPassword)
+ }.sink {
+ if case let .failure(authError) = $0 {
+ print("Change password failed with error \(authError)")
+ }
+ }
+ receiveValue: {
+ print("Change password succeeded")
+ }
+}
+```
+
+
+
+### Override default user account verification channel
+
+You can always change the channel used by your authentication resources by overriding the following setting.
+
+```ts title="amplify/auth/resource.ts"
+import { defineAuth } from '@aws-amplify/backend';
+
+export const auth = defineAuth({
+ loginWith: {
+ email: true
+ },
+// highlight-start
+ accountRecovery: 'EMAIL_ONLY'
+// highlight-end
+});
+```
+
+## Override default password policy
+
+By default your password policy is set to the following:
+
+- `MinLength`: 8 characters
+- `requireLowercase`: true
+- `requireUppercase`: true
+- `requireNumbers`: true
+- `requireSymbols`: true
+- `tempPasswordValidity`: 3 days
+
+You can customize the password format acceptable by your auth resource by modifying the underlying `cfnUserPool` resource:
+
+```ts title="amplify/backend.ts"
+import { defineBackend } from '@aws-amplify/backend';
+import { auth } from './auth/resource';
+
+const backend = defineBackend({
+ auth,
+});
+// extract L1 CfnUserPool resources
+const { cfnUserPool } = backend.auth.resources.cfnResources;
+// modify cfnUserPool policies directly
+cfnUserPool.policies = {
+ passwordPolicy: {
+ minimumLength: 32,
+ requireLowercase: true,
+ requireNumbers: true,
+ requireSymbols: true,
+ requireUppercase: true,
+ temporaryPasswordValidityDays: 20,
+ },
+};
+```
+
+---
+
+---
+title: "Manage WebAuthn credentials"
+section: "build-a-backend/auth/manage-users"
+platforms: ["android", "angular", "javascript", "nextjs", "react", "react-native", "swift", "vue"]
+gen: 2
+last-updated: "2025-06-24T13:29:28.000Z"
+url: "https://docs.amplify.aws/react/build-a-backend/auth/manage-users/manage-webauthn-credentials/"
+---
+
+
+> **Warning:** WebAuthn registration and authentication are not currently supported on React Native, other passwordless features are fully supported.
+
+
+Amplify Auth uses passkeys as the credential mechanism for WebAuthn. The following APIs allow users to register, keep track of, and delete the passkeys associated with their Cognito account.
+
+[Learn more about using passkeys with Amplify](/[platform]/build-a-backend/auth/concepts/passwordless/#webauthn-passkey).
+
+## Associate WebAuthn credentials
+
+
+> **Warning:** Registering a passkey is supported on Android 9 (API level 28) and above.
+
+
+Note that users must be authenticated to register a passkey. That also means users cannot create a passkey during sign up; consequently, they must have at least one other first factor authentication mechanism associated with their account to use WebAuthn.
+
+You can associate a passkey using the following API:
+
+
+```ts
+import { associateWebAuthnCredential} from 'aws-amplify/auth';
+
+await associateWebAuthnCredential();
+
+```
+
+
+
+#### [Java]
+
+```java
+Amplify.Auth.associateWebAuthnCredential(
+ activity,
+ () -> Log.i("AuthQuickstart", "Associated credential"),
+ error -> Log.e("AuthQuickstart", "Failed to associate credential", error)
+);
+```
+
+#### [Kotlin - Callbacks]
+
+```kotlin
+Amplify.Auth.associateWebAuthnCredential(
+ activity,
+ { Log.i("AuthQuickstart", "Associated credential") },
+ { Log.e("AuthQuickstart", "Failed to associate credential", error) }
+)
+```
+
+#### [Kotlin - Coroutines]
+
+```kotlin
+try {
+ val result = Amplify.Auth.associateWebAuthnCredential(activity)
+ Log.i("AuthQuickstart", "Associated credential")
+} catch (error: AuthException) {
+ Log.e("AuthQuickstart", "Failed to associate credential", error)
+}
+```
+
+#### [RxJava]
+
+```java
+RxAmplify.Auth.associateWebAuthnCredential(activity)
+ .subscribe(
+ result -> Log.i("AuthQuickstart", "Associated credential"),
+ error -> Log.e("AuthQuickstart", "Failed to associate credential", error)
+ );
+```
+
+You must supply an `Activity` instance so that Amplify can display the PassKey UI in your application's [Task](https://developer.android.com/guide/components/activities/tasks-and-back-stack).
+
+
+
+#### [Async/Await]
+
+```swift
+func associateWebAuthNCredentials() async {
+ do {
+ try await Amplify.Auth.associateWebAuthnCredential()
+ print("WebAuthn credential was associated")
+ } catch {
+ print("Associate WebAuthn Credential failed: \(error)")
+ }
+}
+```
+
+#### [Combine]
+
+```swift
+func associateWebAuthNCredentials() -> AnyCancellable {
+ Amplify.Publisher.create {
+ try await Amplify.Auth.associateWebAuthnCredential()
+ }.sink {
+ print("Associate WebAuthn Credential failed: \($0)")
+ }
+ receiveValue: { _ in
+ print("WebAuthn credential was associated")
+ }
+}
+```
+
+
+
+The user will be prompted to register a passkey using their local authenticator. Amplify will then associate that passkey with Cognito.
+
+## List WebAuthn credentials
+
+You can list registered passkeys using the following API:
+
+
+```ts
+import { listWebAuthnCredentials } from 'aws-amplify/auth';
+
+const result = await listWebAuthnCredentials();
+
+for (const credential of result.credentials) {
+ console.log(`Credential ID: ${credential.credentialId}`);
+ console.log(`Friendly Name: ${credential.friendlyCredentialName}`);
+ console.log(`Relying Party ID: ${credential.relyingPartyId}`);
+ console.log(`Created At: ${credential.createdAt}`);
+}
+
+```
+
+
+
+#### [Async/Await]
+
+```swift
+func listWebAuthNCredentials() async {
+ do {
+ let result = try await Amplify.Auth.listWebAuthnCredentials(
+ options: .init(pageSize: 5))
+
+ for credential in result.credentials {
+ print("Credential ID: \(credential.credentialId)")
+ print("Created At: \(credential.createdAt)")
+ print("Relying Party Id: \(credential.relyingPartyId)")
+ if let friendlyName = credential.friendlyName {
+ print("Friendly name: \(friendlyName)")
+ }
+ }
+
+ // Fetch the next page
+ if let nextToken = result.nextToken {
+ let nextResult = try await Amplify.Auth.listWebAuthnCredentials(
+ options: .init(
+ pageSize: 5,
+ nextToken: nextToken))
+ }
+ } catch {
+ print("Associate WebAuthn Credential failed: \(error)")
+ }
+}
+```
+
+#### [Combine]
+
+```swift
+func listWebAuthNCredentials() -> AnyCancellable {
+ Amplify.Publisher.create {
+ try await Amplify.Auth.listWebAuthnCredentials(
+ options: .init(pageSize: 5))
+ }.sink {
+ print("List WebAuthn Credential failed: \($0)")
+ }
+ receiveValue: { result in
+ for credential in result.credentials {
+ print("Credential ID: \(credential.credentialId)")
+ print("Created At: \(credential.createdAt)")
+ print("Relying Party Id: \(credential.relyingPartyId)")
+ if let friendlyName = credential.friendlyName {
+ print("Friendly name: \(friendlyName)")
+ }
+ }
+
+ if let nextToken = result.nextToken {
+ // Fetch the next page
+ }
+ }
+}
+```
+
+
+
+
+#### [Java]
+
+```java
+Amplify.Auth.listWebAuthnCredentials(
+ result -> result.getCredentials().forEach(credential -> {
+ Log.i("AuthQuickstart", "Credential ID: " + credential.getCredentialId());
+ Log.i("AuthQuickstart", "Friendly Name: " + credential.getFriendlyName());
+ Log.i("AuthQuickstart", "Relying Party ID: " + credential.getRelyingPartyId());
+ Log.i("AuthQuickstart", "Created At: " + credential.getCreatedAt());
+ }),
+ error -> Log.e("AuthQuickstart", "Failed to list credentials", error)
+);
+```
+
+#### [Kotlin - Callbacks]
+
+```kotlin
+Amplify.Auth.listWebAuthnCredentials(
+ { result ->
+ result.credentials.forEach { credential ->
+ Log.i("AuthQuickstart", "Credential ID: ${credential.credentialId}")
+ Log.i("AuthQuickstart", "Friendly Name: ${credential.friendlyName}")
+ Log.i("AuthQuickstart", "Relying Party ID: ${credential.relyingPartyId}")
+ Log.i("AuthQuickstart", "Created At: ${credential.createdAt}")
+ }
+ },
+ { error -> Log.e("AuthQuickstart", "Failed to list credentials", error) }
+)
+```
+
+#### [Kotlin - Coroutines]
+
+```kotlin
+try {
+ val result = Amplify.Auth.listWebAuthnCredentials()
+ result.credentials.forEach { credential ->
+ Log.i("AuthQuickstart", "Credential ID: ${credential.credentialId}")
+ Log.i("AuthQuickstart", "Friendly Name: ${credential.friendlyName}")
+ Log.i("AuthQuickstart", "Relying Party ID: ${credential.relyingPartyId}")
+ Log.i("AuthQuickstart", "Created At: ${credential.createdAt}")
+ }
+} catch (error: AuthException) {
+ Log.e("AuthQuickstart", "Failed to list credentials", error)
+}
+```
+
+#### [RxJava]
+
+```java
+RxAmplify.Auth.listWebAuthnCredentials()
+ .subscribe(
+ result -> result.getCredentials().forEach(credential -> {
+ Log.i("AuthQuickstart", "Credential ID: " + credential.getCredentialId());
+ Log.i("AuthQuickstart", "Friendly Name: " + credential.getFriendlyName());
+ Log.i("AuthQuickstart", "Relying Party ID: " + credential.getRelyingPartyId());
+ Log.i("AuthQuickstart", "Created At: " + credential.getCreatedAt());
+ }),
+ error -> Log.e("AuthQuickstart", "Failed to list credentials", error)
+ );
+```
+
+
+
+## Delete WebAuthn credentials
+
+You can delete a passkey with the following API:
+
+
+```ts
+import { deleteWebAuthnCredential } from 'aws-amplify/auth';
+
+const id = "credential-id-to-delete";
+
+await deleteWebAuthnCredential({
+ credentialId: id
+});
+```
+
+
+
+#### [Async/Await]
+
+```swift
+func deleteWebAuthNCredentials(credentialId: String) async {
+ do {
+ try await Amplify.Auth.deleteWebAuthnCredential(credentialId: credentialId)
+ print("WebAuthn credential was deleted")
+ } catch {
+ print("Delete WebAuthn Credential failed: \(error)")
+ }
+}
+```
+
+#### [Combine]
+
+```swift
+func deleteWebAuthNCredentials(credentialId: String) -> AnyCancellable {
+ Amplify.Publisher.create {
+ try await Amplify.Auth.deleteWebAuthnCredential(credentialId: credentialId)
+ }.sink {
+ print("Delete WebAuthn Credential failed: \($0)")
+ }
+ receiveValue: { _ in
+ print("WebAuthn credential was deleted")
+ }
+}
+```
+
+
+
+
+#### [Java]
+
+```java
+Amplify.Auth.deleteWebAuthnCredential(
+ credentialId,
+ (result) -> Log.i("AuthQuickstart", "Deleted credential"),
+ error -> Log.e("AuthQuickstart", "Failed to delete credential", error)
+);
+```
+
+#### [Kotlin - Callbacks]
+
+```kotlin
+Amplify.Auth.deleteWebAuthnCredential(
+ credentialId,
+ { Log.i("AuthQuickstart", "Deleted credential") },
+ { Log.e("AuthQuickstart", "Failed to delete credential", error) }
+)
+```
+
+#### [Kotlin - Coroutines]
+
+```kotlin
+try {
+ val result = Amplify.Auth.deleteWebAuthnCredential(credentialId)
+ Log.i("AuthQuickstart", "Deleted credential")
+} catch (error: AuthException) {
+ Log.e("AuthQuickstart", "Failed to delete credential", error)
+}
+```
+
+#### [RxJava]
+
+```java
+RxAmplify.Auth.deleteWebAuthnCredential(credentialId)
+ .subscribe(
+ result -> Log.i("AuthQuickstart", "Deleted credential"),
+ error -> Log.e("AuthQuickstart", "Failed to delete credential", error)
+ );
+```
+
+The delete passkey API has only the required `credentialId` as input, and it does not return a value.
+
+
+
+## Practical example
+
+Here is a code example that uses the list and delete APIs together. In this example, the user has 3 passkeys registered. They want to list all passkeys while using a `pageSize` of 2 as well as delete the first passkey in the list.
+
+```ts
+import {
+ listWebAuthnCredentials,
+ deleteWebAuthnCredential
+} from 'aws-amplify/auth';
+
+let passkeys = [];
+
+const result = await listWebAuthnCredentials({ pageSize: 2 });
+
+passkeys.push(...result.credentials);
+
+const nextPage = await listWebAuthnCredentials({
+ pageSize: 2,
+ nextToken: result.nextToken,
+});
+
+passkeys.push(...nextPage.credentials);
+
+const id = passkeys[0].credentialId;
+
+await deleteWebAuthnCredential({
+ credentialId: id
+});
+```
+
+
+---
+
+---
+title: "Manage devices"
+section: "build-a-backend/auth/manage-users"
+platforms: ["android", "angular", "flutter", "javascript", "nextjs", "react", "react-native", "swift", "vue"]
+gen: 2
+last-updated: "2024-08-20T18:34:28.000Z"
+url: "https://docs.amplify.aws/react/build-a-backend/auth/manage-users/manage-devices/"
+---
+
+Amplify Auth enables you to track devices your users use for auditing, MFA, and more. Before you begin it is important to understand the terminology for device statuses:
+
+- **Tracked:** Every time the user signs in with a new device, the client is given the device key at the end of a successful authentication event. We use this device key to generate a salt and password verifier which is used to call the ConfirmDevice API. At this point, the device is considered to be _tracked_. Once the device is in a tracked state, you can use the Amazon Cognito console to see the time it started to be tracked, last authentication time, and other information about that device.
+- **Remembered:** Remembered devices are also tracked. During user authentication, the device key and secret pair assigned to a remembered device is used to authenticate the device to verify that it is the same device that the user previously used to sign in.
+- **Not Remembered:** A not-remembered device is a tracked device where Cognito has been configured to require users to "Opt-in" to remember a device, but the user has not opt-ed in to having the device remembered. This use case is used for users signing into their application from a device that they don't own.
+- **Forgotten:** a forgotten device is one removed from being remembered
+
+> **Info:** **Note:** [device tracking and remembering](https://aws.amazon.com/blogs/mobile/tracking-and-remembering-devices-using-amazon-cognito-your-user-pools/) features are not available when using federating sign-in with external providers as devices are tracked on the upstream identity provider. These features are also not available when using Cognito's Hosted UI.
+
+## Remember devices
+
+You can remember devices using the following:
+
+
+```ts
+import { rememberDevice } from 'aws-amplify/auth';
+
+await rememberDevice();
+```
+
+
+```dart
+Future rememberCurrentDevice() async {
+ try {
+ await Amplify.Auth.rememberDevice();
+ safePrint('Remember device succeeded');
+ } on AuthException catch (e) {
+ safePrint('Remember device failed with error: $e');
+ }
+}
+```
+
+
+
+#### [Java]
+
+```java
+Amplify.Auth.rememberDevice(
+ () -> Log.i("AuthQuickStart", "Remember device succeeded"),
+ error -> Log.e("AuthQuickStart", "Remember device failed with error " + error.toString())
+);
+```
+
+#### [Kotlin - Callbacks]
+
+```kotlin
+Amplify.Auth.rememberDevice(
+ { Log.i("AuthQuickStart", "Remember device succeeded") },
+ { Log.e("AuthQuickStart", "Remember device failed with error", it) }
+)
+```
+
+#### [Kotlin - Coroutines]
+
+```kotlin
+try {
+ Amplify.Auth.rememberDevice()
+ Log.i("AuthQuickStart", "Remember device succeeded")
+} catch (error: AuthException) {
+ Log.e("AuthQuickStart", "Remember device failed with error", error)
+}
+```
+
+#### [RxJava]
+
+```java
+RxAmplify.Auth.rememberDevice()
+ .subscribe(
+ () -> Log.i("AuthQuickStart", "Remember device succeeded"),
+ error -> Log.e("AuthQuickStart", "Remember device failed with error " + error.toString())
+ );
+```
+
+
+
+
+#### [Async/Await]
+
+```swift
+func rememberDevice() async {
+ do {
+ try await Amplify.Auth.rememberDevice()
+ print("Remember device succeeded")
+ } catch let error as AuthError {
+ print("Remember device failed with error \(error)")
+ } catch {
+ print("Unexpected error: \(error)")
+ }
+}
+```
+
+#### [Combine]
+
+```swift
+func rememberDevice() -> AnyCancellable {
+ Amplify.Publisher.create {
+ try await Amplify.Auth.rememberDevice()
+ }.sink {
+ if case let .failure(authError) = $0 {
+ print("Remember device failed with error \(authError)")
+ }
+ }
+ receiveValue: {
+ print("Remember device succeeded")
+ }
+}
+```
+
+
+
+## Forget devices
+
+You can also forget devices but note that forgotten devices are neither remembered nor tracked.
+
+
+```ts
+import { forgetDevice } from 'aws-amplify/auth';
+
+await forgetDevice();
+```
+
+
+
+#### [Current Device]
+
+```dart
+Future forgetCurrentDevice() async {
+ try {
+ await Amplify.Auth.forgetDevice();
+ safePrint('Forget device succeeded');
+ } on AuthException catch (e) {
+ safePrint('Forget device failed with error: $e');
+ }
+}
+```
+
+#### [Specific Device]
+
+```dart
+// A device that was fetched via Amplify.Auth.fetchDevices()
+Future forgetSpecificDevice(AuthDevice myDevice) async {
+ try {
+ await Amplify.Auth.forgetDevice(myDevice);
+ safePrint('Forget device succeeded');
+ } on AuthException catch (e) {
+ safePrint('Forget device failed with error: $e');
+ }
+}
+```
+
+
+
+
+#### [Java]
+
+```java
+Amplify.Auth.forgetDevice(
+ () -> Log.i("AuthQuickStart", "Forget device succeeded"),
+ error -> Log.e("AuthQuickStart", "Forget device failed with error " + error.toString())
+);
+```
+
+#### [Kotlin - Callbacks]
+
+```kotlin
+Amplify.Auth.forgetDevice(
+ { Log.i("AuthQuickStart", "Forget device succeeded") },
+ { Log.e("AuthQuickStart", "Forget device failed with error", it) }
+)
+```
+
+#### [Kotlin - Coroutines]
+
+```kotlin
+try {
+ Amplify.Auth.forgetDevice()
+ Log.i("AuthQuickStart", "Forget device succeeded")
+} catch (error: AuthException) {
+ Log.e("AuthQuickStart", "Forget device failed with error", error)
+}
+```
+
+#### [RxJava]
+
+```java
+RxAmplify.Auth.forgetDevice()
+ .subscribe(
+ () -> Log.i("AuthQuickStart", "Forget device succeeded"),
+ error -> Log.e("AuthQuickStart", "Forget device failed with error " + error.toString())
+ );
+```
+
+
+
+
+#### [Async/Await]
+
+```swift
+func forgetDevice() async {
+ do {
+ try await Amplify.Auth.forgetDevice()
+ print("Forget device succeeded")
+ } catch let error as AuthError {
+ print("Forget device failed with error \(error)")
+ } catch {
+ print("Unexpected error: \(error)")
+ }
+}
+```
+
+#### [Combine]
+
+```swift
+func forgetDevice() -> AnyCancellable {
+ Amplify.Publisher.create {
+ try await Amplify.Auth.forgetDevice()
+ }.sink {
+ if case let .failure(authError) = $0 {
+ print("Forget device failed with error \(authError)")
+ }
+ }
+ receiveValue: {
+ print("Forget device succeeded")
+ }
+}
+```
+
+
+
+## Fetch devices
+
+You can fetch a list of remembered devices by using the following:
+
+
+```ts
+import { fetchDevices } from 'aws-amplify/auth';
+
+const output = await fetchDevices();
+```
+
+
+```dart
+Future fetchAllDevices() async {
+ try {
+ final devices = await Amplify.Auth.fetchDevices();
+ for (final device in devices) {
+ safePrint('Device: $device');
+ }
+ } on AuthException catch (e) {
+ safePrint('Fetch devices failed with error: $e');
+ }
+}
+```
+
+
+
+
+#### [Java]
+
+```java
+Amplify.Auth.fetchDevices(
+ devices -> {
+ for (AuthDevice device : devices) {
+ Log.i("AuthQuickStart", "Device: " + device);
+ }
+ },
+ error -> Log.e("AuthQuickStart", "Fetch devices failed with error: " + error.toString()));
+```
+
+#### [Kotlin - Callbacks]
+
+```kotlin
+Amplify.Auth.fetchDevices(
+ { devices ->
+ devices.forEach { Log.i("AuthQuickStart", "Device: " + it) }
+ },
+ { Log.e("AuthQuickStart", "Fetch devices failed with error", it) }
+)
+```
+
+#### [Kotlin - Coroutines]
+
+```kotlin
+try {
+ Amplify.Auth.fetchDevices().forEach { device ->
+ Log.i("AuthQuickStart", "Device: $device")
+ }
+} catch (error: AuthException) {
+ Log.e("AuthQuickStart", "Fetch devices failed with error", error)
+}
+```
+
+#### [RxJava]
+
+```java
+RxAmplify.Auth.fetchDevices()
+ .subscribe(
+ device -> Log.i("AuthQuickStart", "Device: " + device);
+ error -> Log.e("AuthQuickStart", "Fetch devices failed with error: " + error.toString())
+ );
+```
+
+
+
+
+#### [Async/Await]
+
+```swift
+func fetchDevices() async {
+ do {
+ let fetchDeviceResult = try await Amplify.Auth.fetchDevices()
+ for device in fetchDeviceResult {
+ print(device.id)
+ }
+ } catch let error as AuthError {
+ print("Fetch devices failed with error \(error)")
+ } catch {
+ print("Unexpected error: \(error)")
+ }
+}
+```
+
+#### [Combine]
+
+```swift
+func fetchDevices() -> AnyCancellable {
+ Amplify.Publisher.create {
+ try await Amplify.Auth.fetchDevices()
+ }.sink {
+ if case let .failure(authError) = $0 {
+ print("Fetch devices failed with error \(authError)")
+ }
+ }
+ receiveValue: { fetchDeviceResult in
+ for device in fetchDeviceResult {
+ print(device.id)
+ }
+ }
+}
+```
+
+
+
+
+## Fetch the current device
+
+You can fetch the current device by using the following:
+
+```dart
+Future fetchCurrentUserDevice() async {
+ try {
+ final device = await Amplify.Auth.fetchCurrentDevice();
+ safePrint('Device: $device');
+ } on AuthException catch (e) {
+ safePrint('Get current device failed with error: $e');
+ }
+}
+```
+
+
+You can now set up devices to be remembered, forgotten, and fetched.
+
+---
+
+---
+title: "Manage users with Amplify console"
+section: "build-a-backend/auth/manage-users"
+platforms: ["android", "angular", "flutter", "javascript", "nextjs", "react", "react-native", "swift", "vue"]
+gen: 2
+last-updated: "2024-08-06T19:20:15.000Z"
+url: "https://docs.amplify.aws/react/build-a-backend/auth/manage-users/with-amplify-console/"
+---
+
+The **User management** page in the Amplify console provides a user-friendly interface for managing your application's users. You can create and manage users and groups, edit user attributes, and suspend users.
+
+If you have not yet created an **auth** resource, visit the [Auth setup guide](/[platform]/build-a-backend/auth/set-up-auth/).
+
+## Access User management
+
+After you've deployed your auth resource, you can access the manager on Amplify Console.
+
+1. Log in to the [Amplify console](https://console.aws.amazon.com/amplify/home) and choose your app.
+2. Select the branch you would like to access.
+3. Select **Authentication** from the left navigation bar.
+4. Then, select **User management**.
+
+### To create a user
+
+1. On the **User management** page, select **Users** tab.
+2. Select **Create user**.
+3. In the **Create user** window, for Unique identifier enter a email address, username, or phone number. For Temporary password enter a password.
+4. Choose Create user.
+
+
+
+A user can be confirmed by using the [pre-built UI components](/[platform]/build-a-backend/auth/connect-your-frontend/using-the-authenticator/) and [Amplify libraries](/[platform]/build-a-backend/auth/connect-your-frontend/sign-up/).
+
+
+
+## To create a group
+
+1. On the **User management** page, choose the **Groups** tab and then choose **Create group**.
+2. In the **Create group** window, for **Title** enter a name for the group.
+3. Choose **Create group**.
+
+## To add a users to a group
+
+1. On the **User management** page, choose the **Groups** tab.
+2. Select the name of the group to add users to.
+3. Choose **Add users**.
+4. In the **Add users to group** window, choose how you want to search for users to add from the **Search** menu. You can choose _Email_, _Phone number_, or _Username_.
+5. Add one user or multiple users to add to the group and then choose **Add users**.
+
+## To delete a group
+
+1. On the **User management** page, choose the **Groups** tab.
+2. In the **Groups** section, select the name of the group to delete.
+3. Choose **Delete**.
+4. A confirmation window is displayed. Enter _Delete_ and choose, **Confirm deletion**.
+
+---
+
+---
+title: "Customize auth lifecycle"
+section: "build-a-backend/auth"
+platforms: ["android", "angular", "flutter", "javascript", "nextjs", "react", "react-native", "swift", "vue"]
+gen: 2
+last-updated: "2024-05-01T23:11:32.000Z"
+url: "https://docs.amplify.aws/react/build-a-backend/auth/customize-auth-lifecycle/"
+---
+
+
+
+---
+
+---
+title: "Custom auth flows"
+section: "build-a-backend/auth/customize-auth-lifecycle"
+platforms: ["android", "flutter", "swift"]
+gen: 2
+last-updated: "2024-10-31T15:49:20.000Z"
+url: "https://docs.amplify.aws/react/build-a-backend/auth/customize-auth-lifecycle/custom-auth-flows/"
+---
+
+
+The Auth category can be configured to perform a [custom authentication flow](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-challenge.html) defined by you. The following guide shows how to setup a simple passwordless authentication flow.
+
+## Prerequisites
+An application with Amplify libraries integrated and a minimum target of any of the following:
+- **iOS 13.0**, using **Xcode 14.1** or later.
+- **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** 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 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.
+
+
+
+
+
+To use Auth in a macOS project, you'll need to enable the Keychain Sharing capability. In Xcode, navigate to **your application target** > **Signing & Capabilities** > **+ Capability**, then select **Keychain Sharing.**
+
+This capability is required because Auth uses the Data Protection Keychain on macOS as a platform best practice. See [TN3137: macOS keychain APIs and implementations](https://developer.apple.com/documentation/technotes/tn3137-on-mac-keychains) for more information on how Keychain works on macOS and the Keychain Sharing entitlement.
+
+For more information on adding capabilities to your application, see [Xcode Capabilities](https://developer.apple.com/documentation/xcode/capabilities).
+
+
+
+## Configure Auth
+
+The custom auth flow can be [configured manually](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-challenge.html).
+
+## Sign in a user
+
+Implement a UI to get the username from the user. After the user enters the username you can start the sign in flow by calling the following method:
+
+#### [Async/Await]
+
+```swift
+func signIn(username: String) async {
+ do {
+ let options = AWSAuthSignInOptions(authFlowType: .customWithoutSRP)
+ let signInResult = try await Amplify.Auth.signIn(username: username,
+ options: .init(pluginOptions: options))
+ if case .confirmSignInWithCustomChallenge(_) = signInResult.nextStep {
+ // Ask the user to enter the custom challenge.
+ } else {
+ print("Sign in succeeded")
+ }
+ } catch let error as AuthError {
+ print("Sign in failed \(error)")
+ } catch {
+ print("Unexpected error: \(error)")
+ }
+}
+```
+
+#### [Combine]
+
+```swift
+func signIn(username: String) -> AnyCancellable {
+ Amplify.Publisher.create {
+ let options = AWSAuthSignInOptions(authFlowType: .customWithoutSRP)
+ try await Amplify.Auth.signIn(username: username,
+ options: .init(pluginOptions: options))
+ }.sink {
+ if case let .failure(authError) = $0 {
+ print("Sign in failed \(authError)")
+ }
+ }
+ receiveValue: { result in
+ if case .confirmSignInWithCustomChallenge(_) = result.nextStep {
+ // Ask the user to enter the custom challenge.
+ } else {
+ print("Sign in succeeded")
+ }
+ }
+}
+```
+
+Since this is a custom authentication flow with a challenge, the result of the signin process has a next step `.confirmSignInWithCustomChallenge`. Implement a UI to allow the user to enter the custom challenge.
+
+## Confirm sign in with custom challenge
+
+To get a custom challenge from the user, create an appropriate UI for the user to submit the required value, and pass that value into the `confirmSignin()` API.
+
+#### [Async/Await]
+
+```swift
+func customChallenge(response: String) async {
+ do {
+ _ = try await Amplify.Auth.confirmSignIn(challengeResponse: response)
+ print("Confirm sign in succeeded")
+ } catch let error as AuthError {
+ print("Confirm sign in failed \(error)")
+ } catch {
+ print("Unexpected error: \(error)")
+ }
+}
+```
+
+#### [Combine]
+
+```swift
+func customChallenge(response: String) -> AnyCancellable {
+ Amplify.Publisher.create {
+ try await Amplify.Auth.confirmSignIn(challengeResponse: response)
+ }.sink {
+ if case let .failure(authError) = $0 {
+ print("Confirm sign in failed \(authError)")
+ }
+ }
+ receiveValue: { _ in
+ print("Confirm sign in succeeded")
+ }
+}
+```
+
+You will know the sign in flow is complete if you see the following in your console window:
+
+```console
+Confirm sign in succeeded
+```
+
+### Lambda Trigger Setup
+
+AWS Amplify now supports creating functions as part of its new backend experience. For more information on the Functions and how to start with them check out [Functions documentation](/[platform]/build-a-backend/functions/). In addition, more information on available triggers can be found in the [Cognito documentation](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-identity-pools-working-with-aws-lambda-triggers.html).
+
+### Custom Auth Flow with Secure Remote Password (SRP)
+
+Cognito User Pool allows to start the custom authentication flow with SRP as the first step. If you would like to use this flow, setup Define Auth Lambda trigger to handle SRP_A as the first challenge as shown below:
+
+```javascript
+exports.handler = (event, context) => {
+ if (event.request.session.length == 1 &&
+ event.request.session[0].challengeName == 'SRP_A') {
+ event.response.issueTokens = false;
+ event.response.failAuthentication = false;
+ event.response.challengeName = 'PASSWORD_VERIFIER';
+ } else if (event.request.session.length == 2 &&
+ event.request.session[1].challengeName == 'PASSWORD_VERIFIER' &&
+ event.request.session[1].challengeResult == true) {
+ event.response.issueTokens = false;
+ event.response.failAuthentication = false;
+ event.response.challengeName = 'CUSTOM_CHALLENGE';
+ } else if (event.request.session.length == 3 &&
+ event.request.session[2].challengeName == 'CUSTOM_CHALLENGE' &&
+ event.request.session[2].challengeResult == true) {
+ event.response.issueTokens = true;
+ event.response.failAuthentication = false;
+ } else {
+ event.response.issueTokens = false;
+ event.response.failAuthentication = true;
+ }
+ context.done(null, event);
+};
+```
+
+If your lambda is setup to start with `SRP` as the first step, make sure to initiate the signIn process with `customWithSRP` as the authentication flow:
+
+```swift
+let options = AWSAuthSignInOptions(
+ authFlowType: .customWithSRP)
+let signInResult = try await Amplify.Auth.signIn(
+ username: username,
+ password: password,
+ options: .init(pluginOptions: options))
+```
+
+
+The Auth category can be configured to perform a [custom authentication flow](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-challenge.html) defined by you. The following guide shows how to setup a simple passwordless authentication flow.
+
+## Prerequisites
+
+* An Android application targeting at least Android SDK API level 24 with Amplify libraries integrated
+ * For a full example of creating Android project, please follow the [project setup walkthrough](/[platform]/start/quickstart/)
+
+## Configure Auth
+
+The custom auth flow can be [configured manually](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-challenge.html).
+
+## Register a user
+
+The flow as mentioned above requires a username and a valid email id as parameters to register a user. Invoke the following api to initiate a sign up flow.
+
+#### [Java]
+
+```java
+AuthSignUpOptions options = AuthSignUpOptions.builder()
+ .userAttribute(AuthUserAttributeKey.email(), "my@email.com")
+ .build();
+Amplify.Auth.signUp("username", "Password123", options,
+ result -> Log.i("AuthQuickStart", "Result: " + result.toString()),
+ error -> Log.e("AuthQuickStart", "Sign up failed", error)
+);
+```
+
+#### [Kotlin - Callbacks]
+
+```kotlin
+val options = AuthSignUpOptions.builder()
+ .userAttribute(AuthUserAttributeKey.email(), "my@email.com")
+ .build()
+Amplify.Auth.signUp("username", "Password123", options,
+ { Log.i("AuthQuickStart", "Sign up succeeded: $it") },
+ { Log.e ("AuthQuickStart", "Sign up failed", it) }
+)
+```
+
+#### [Kotlin - Coroutines]
+
+```kotlin
+val options = AuthSignUpOptions.builder()
+ .userAttribute(AuthUserAttributeKey.email(), "my@email.com")
+ .build()
+try {
+ val result = Amplify.Auth.signUp("username", "Password123", options)
+ Log.i("AuthQuickStart", "Result: $result")
+} catch (error: AuthException) {
+ Log.e("AuthQuickStart", "Sign up failed", error)
+}
+```
+
+#### [RxJava]
+
+ ```java
+RxAmplify.Auth.signUp(
+ "username",
+ "Password123",
+ AuthSignUpOptions.builder().userAttribute(AuthUserAttributeKey.email(), "my@email.com").build())
+ .subscribe(
+ result -> Log.i("AuthQuickStart", "Result: " + result.toString()),
+ error -> Log.e("AuthQuickStart", "Sign up failed", error)
+ );
+```
+
+The next step in the sign up flow is to confirm the user. A confirmation code will be sent to the email id provided during sign up. Enter the confirmation code received via email in the `confirmSignUp` call.
+
+#### [Java]
+
+```java
+Amplify.Auth.confirmSignUp(
+ "username",
+ "the code you received via email",
+ result -> Log.i("AuthQuickstart", result.isSignUpComplete() ? "Confirm signUp succeeded" : "Confirm sign up not complete"),
+ error -> Log.e("AuthQuickstart", error.toString())
+);
+```
+
+#### [Kotlin - Callbacks]
+
+```kotlin
+Amplify.Auth.confirmSignUp(
+ "username", "the code you received via email",
+ { result ->
+ if (result.isSignUpComplete) {
+ Log.i("AuthQuickstart", "Confirm signUp succeeded")
+ } else {
+ Log.i("AuthQuickstart","Confirm sign up not complete")
+ }
+ },
+ { Log.e("AuthQuickstart", "Failed to confirm sign up", it) }
+)
+```
+
+#### [Kotlin - Coroutines]
+
+```kotlin
+try {
+ val code = "code you received via email"
+ val result = Amplify.Auth.confirmSignUp("username", code)
+ if (result.isSignUpComplete) {
+ Log.i("AuthQuickstart", "Signup confirmed")
+ } else {
+ Log.i("AuthQuickstart", "Signup confirmation not yet complete")
+ }
+} catch (error: AuthException) {
+ Log.e("AuthQuickstart", "Failed to confirm signup", error)
+}
+```
+
+#### [RxJava]
+
+```java
+RxAmplify.Auth.confirmSignUp("username", "the code you received via email")
+ .subscribe(
+ result -> Log.i("AuthQuickstart", result.isSignUpComplete() ? "Confirm signUp succeeded" : "Confirm sign up not complete"),
+ error -> Log.e("AuthQuickstart", error.toString())
+ );
+```
+
+You will know the sign up flow is complete if you see the following in your console window:
+
+```console
+Confirm signUp succeeded
+```
+
+## Sign in a user
+
+Implement a UI to get the username from the user. After the user enters the username you can start the sign in flow by calling the following method:
+
+#### [Java]
+
+```java
+AWSCognitoAuthSignInOptions options = AWSCognitoAuthSignInOptions.builder()
+ .authFlowType(AuthFlowType.CUSTOM_AUTH_WITHOUT_SRP)
+ .build();
+Amplify.Auth.signIn(
+ "username",
+ "password",
+ options,
+ result -> Log.i("AuthQuickstart", result.isSignedIn() ? "Sign in succeeded" : "Sign in not complete"),
+ error -> Log.e("AuthQuickstart", error.toString())
+);
+```
+
+#### [Kotlin - Callbacks]
+
+```kotlin
+val options = AWSCognitoAuthSignInOptions.builder()
+ .authFlowType(AuthFlowType.CUSTOM_AUTH_WITHOUT_SRP)
+ .build()
+Amplify.Auth.signIn(
+ "username",
+ "password",
+ options,
+ { result ->
+ if (result.isSignedIn) {
+ Log.i("AuthQuickstart", "Sign in succeeded")
+ } else {
+ Log.i("AuthQuickstart", "Sign in not complete")
+ }
+ },
+ { Log.e("AuthQuickstart", "Failed to sign in", it) }
+)
+```
+
+#### [Kotlin - Coroutines]
+
+```kotlin
+val options = AWSCognitoAuthSignInOptions.builder()
+ .authFlowType(AuthFlowType.CUSTOM_AUTH_WITHOUT_SRP)
+ .build()
+try {
+ val result = Amplify.Auth.signIn("username", "password", options)
+ if (result.isSignedIn) {
+ Log.i("AuthQuickstart", "Sign in succeeded")
+ } else {
+ Log.e("AuthQuickstart", "Sign in not complete")
+ }
+} catch (error: AuthException) {
+ Log.e("AuthQuickstart", "Sign in failed", error)
+}
+```
+
+#### [RxJava]
+
+```java
+AWSCognitoAuthSignInOptions options = AWSCognitoAuthSignInOptions.builder()
+ .authFlowType(AuthFlowType.CUSTOM_AUTH_WITHOUT_SRP)
+ .build();
+RxAmplify.Auth.signIn("username", "password", options)
+ .subscribe(
+ result -> Log.i("AuthQuickstart", result.isSignedIn() ? "Sign in succeeded" : "Sign in not complete"),
+ error -> Log.e("AuthQuickstart", error.toString())
+ );
+```
+
+Since this is a custom authentication flow with a challenge, the result of the signin process has a next step `.confirmSignInWithCustomChallenge`. Implement a UI to allow the user to enter the custom challenge.
+
+## Confirm sign in with custom challenge
+
+Get the custom challenge (`1234` in this case) from the user and pass it to the `confirmSignin()` api.
+
+#### [Java]
+
+```java
+Amplify.Auth.confirmSignIn(
+ "confirmation",
+ result -> Log.i("AuthQuickstart", "Confirm sign in succeeded: " + result.toString()),
+ error -> Log.e("AuthQuickstart", "Failed to confirm sign in", error)
+);
+```
+
+#### [Kotlin - Callbacks]
+
+```kotlin
+Amplify.Auth.confirmSignIn("confirmation",
+ { Log.i("AuthQuickstart", "Confirm sign in succeeded: $it") },
+ { Log.e("AuthQuickstart", "Failed to confirm sign in", it) }
+)
+```
+
+#### [Kotlin - Coroutines]
+
+```kotlin
+try {
+ val result = Amplify.Auth.confirmSignIn("confirmation")
+ Log.i("AuthQuickstart", "Confirm sign in succeeded: $result")
+} catch (error: AuthException) {
+ Log.e("AuthQuickstart", "Failed to confirm signin", error)
+}
+```
+
+#### [RxJava]
+
+```java
+RxAmplify.Auth.confirmSignIn("confirmation")
+ .subscribe(
+ result -> Log.i("AuthQuickstart", result.toString()),
+ error -> Log.e("AuthQuickstart", error.toString())
+ );
+```
+
+You will know the sign in flow is complete if you see the following in your console window:
+
+```console
+Confirm sign in succeeded
+```
+
+### Lambda Trigger Setup
+
+AWS Amplify now supports creating functions as part of the AWS Amplify. For more information on the Functions and how to start with them check out [Functions documentation](/[platform]/build-a-backend/functions/). In addition, more information on available triggers can be found in the [Cognito documentation](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-identity-pools-working-with-aws-lambda-triggers.html).
+
+### Custom Auth Flow with Secure Remote Password (SRP)
+
+Cognito User Pool allows to start the custom authentication flow with SRP as the first step. If you would like to use this flow, setup Define Auth Lambda trigger to handle SRP_A as the first challenge as shown below:
+
+```javascript
+exports.handler = (event, context) => {
+ if (event.request.session.length == 1 &&
+ event.request.session[0].challengeName == 'SRP_A') {
+ event.response.issueTokens = false;
+ event.response.failAuthentication = false;
+ event.response.challengeName = 'PASSWORD_VERIFIER';
+ } else if (event.request.session.length == 2 &&
+ event.request.session[1].challengeName == 'PASSWORD_VERIFIER' &&
+ event.request.session[1].challengeResult == true) {
+ event.response.issueTokens = false;
+ event.response.failAuthentication = false;
+ event.response.challengeName = 'CUSTOM_CHALLENGE';
+ } else if (event.request.session.length == 3 &&
+ event.request.session[2].challengeName == 'CUSTOM_CHALLENGE' &&
+ event.request.session[2].challengeResult == true) {
+ event.response.issueTokens = true;
+ event.response.failAuthentication = false;
+ } else {
+ event.response.issueTokens = false;
+ event.response.failAuthentication = true;
+ }
+ context.done(null, event);
+};
+```
+
+If your lambda is setup to start with `SRP` as the first step, make sure to initiate the signIn process with `customWithSRP` as the authentication flow:
+
+#### [Java]
+
+```java
+AWSCognitoAuthSignInOptions options = AWSCognitoAuthSignInOptions.builder()
+ .authFlowType(AuthFlowType.CUSTOM_AUTH_WITH_SRP)
+ .build();
+Amplify.Auth.signIn(
+ "username",
+ "password",
+ options,
+ result -> Log.i("AuthQuickstart", result.isSignedIn() ? "Sign in succeeded" : "Sign in not complete"),
+ error -> Log.e("AuthQuickstart", error.toString())
+);
+```
+
+#### [Kotlin - Callbacks]
+
+```kotlin
+val options = AWSCognitoAuthSignInOptions.builder()
+ .authFlowType(AuthFlowType.CUSTOM_AUTH_WITH_SRP)
+ .build()
+Amplify.Auth.signIn(
+ "username",
+ "password",
+ options,
+ { result ->
+ if (result.isSignedIn) {
+ Log.i("AuthQuickstart", "Sign in succeeded")
+ } else {
+ Log.i("AuthQuickstart", "Sign in not complete")
+ }
+ },
+ { Log.e("AuthQuickstart", "Failed to sign in", it) }
+)
+```
+
+#### [Kotlin - Coroutines]
+
+```kotlin
+val options = AWSCognitoAuthSignInOptions.builder()
+ .authFlowType(AuthFlowType.CUSTOM_AUTH_WITH_SRP)
+ .build()
+try {
+ val result = Amplify.Auth.signIn("username", "password", options)
+ if (result.isSignedIn) {
+ Log.i("AuthQuickstart", "Sign in succeeded")
+ } else {
+ Log.e("AuthQuickstart", "Sign in not complete")
+ }
+} catch (error: AuthException) {
+ Log.e("AuthQuickstart", "Sign in failed", error)
+}
+```
+
+#### [RxJava]
+
+```java
+AWSCognitoAuthSignInOptions options = AWSCognitoAuthSignInOptions.builder()
+ .authFlowType(AuthFlowType.CUSTOM_AUTH_WITH_SRP)
+ .build();
+RxAmplify.Auth.signIn("username", "password", options)
+ .subscribe(
+ result -> Log.i("AuthQuickstart", result.isSignedIn() ? "Sign in succeeded" : "Sign in not complete"),
+ error -> Log.e("AuthQuickstart", error.toString())
+ );
+```
+
+
+
+
+The Auth category can be configured to perform a [custom authentication flow](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-challenge.html) defined by you. The following guide shows how to setup a simple passwordless authentication flow.
+
+## Prerequisites
+
+Amplify requires a minimum target platform for iOS (13.0), Android (API level 24), and macOS (10.15). Refer to [Flutter's supported deployment platforms](https://docs.flutter.dev/reference/supported-platforms) when targeting Web, Windows, or Linux. Additional setup is required for some target platforms. Please see the [platform setup](/[platform]/build-a-backend/auth/connect-your-frontend/sign-in/#platform-setup) for more details on platform specific setup.
+
+## Configure Auth
+
+The custom auth flow can be [configured manually](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-challenge.html).
+
+## Register a user
+
+The flow as mentioned above requires a username and a valid email id as parameters to register a user. Invoke the following api to initiate a sign up flow.
+
+Because authentication flows in Cognito can be switched via your configuration, it is still required that users register with a password.
+
+```dart
+Future signUpCustomFlow() async {
+ try {
+ final userAttributes = {
+ AuthUserAttributeKey.email: 'email@domain.com',
+ AuthUserAttributeKey.phoneNumber: '+15559101234',
+ // additional attributes as needed
+ };
+ final result = await Amplify.Auth.signUp(
+ username: 'myusername',
+ password: 'mysupersecurepassword',
+ options: SignUpOptions(userAttributes: userAttributes),
+ );
+ safePrint('Sign up result: $result');
+ } on AuthException catch (e) {
+ safePrint('Error signing up: ${e.message}');
+ }
+}
+```
+
+The next step in the sign up flow is to confirm the user. A confirmation code will be sent to the email id provided during sign up. Enter the confirmation code received via email in the `confirmSignUp` call.
+
+```dart
+Future confirmUser({
+ required String username,
+ required String confirmationCode,
+}) async {
+ try {
+ final result = await Amplify.Auth.confirmSignUp(
+ username: username,
+ confirmationCode: confirmationCode,
+ );
+ // Check if further confirmations are needed or if
+ // the sign up is complete.
+ await _handleSignUpResult(result);
+ } on AuthException catch (e) {
+ safePrint('Error confirming user: ${e.message}');
+ }
+}
+```
+
+## Sign in a user
+
+Implement a UI to get the username from the user. After the user enters the username you can start the sign in flow by calling the following method:
+
+```dart
+// Create state variables for the sign in status
+var isSignedIn = false;
+String? challengeHint;
+
+Future signInCustomFlow(String username) async {
+ try {
+ final result = await Amplify.Auth.signIn(username: username);
+ setState(() {
+ isSignedIn = result.isSignedIn;
+ // Get the publicChallengeParameters from your Create Auth Challenge Lambda
+ challengeHint = result.nextStep.additionalInfo['hint'];
+ });
+ } on AuthException catch (e) {
+ safePrint('Error signing in: ${e.message}');
+ }
+}
+```
+
+
+
+Please note that you will be prevented from successfully calling `signIn` if a
+user has already signed in and a valid session is active. You must first call
+`signOut` to remove the original session.
+
+
+## Confirm sign in with custom challenge
+
+To get a custom challenge from the user, create an appropriate UI for the user to submit the required value, and pass that value into the `confirmSignin()` API.
+
+```dart
+Future confirmSignIn(String generatedNumber) async {
+ try {
+ final result = await Amplify.Auth.confirmSignIn(
+ /// Enter the random number generated by your Create Auth Challenge trigger
+ confirmationValue: generatedNumber,
+ );
+ safePrint('Sign in result: $result');
+ } on AuthException catch (e) {
+ safePrint('Error signing in: ${e.message}');
+ }
+}
+```
+
+Once the user provides the correct response, they should be authenticated in your application.
+
+> **Warning:** Special Handling on ConfirmSignIn
+>
+> During a `confirmSignIn` call, if `failAuthentication: true` is returned by the Lambda, the session of the request gets invalidated by Cognito, and a `NotAuthorizedException` is thrown. To recover, the user must initiate a new sign in by calling `Amplify.Auth.signIn`.
+>
+> Exception: `NotAuthorizedException` with a message `Invalid session for the user.`
+
+## Custom authentication flow with password verification
+
+The example in this documentation demonstrates the passwordless custom authentication flow. However, it is also possible to require that users supply a valid password as part of the custom authentication flow.
+
+To require a valid password, you can alter the [DefineAuthChallenge](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-define-auth-challenge.html) code to handle a `PASSWORD_VERIFIER` step:
+
+```js
+exports.handler = async (event) => {
+ if (
+ event.request.session.length === 1 &&
+ event.request.session[0].challengeName === 'SRP_A'
+ ) {
+ event.response.issueTokens = false;
+ event.response.failAuthentication = false;
+ event.response.challengeName = 'PASSWORD_VERIFIER';
+ } else if (
+ event.request.session.length === 2 &&
+ event.request.session[1].challengeName === 'PASSWORD_VERIFIER' &&
+ event.request.session[1].challengeResult === true
+ ) {
+ event.response.issueTokens = false;
+ event.response.failAuthentication = false;
+ event.response.challengeName = 'CUSTOM_CHALLENGE';
+ } else if (
+ event.request.session.length === 3 &&
+ event.request.session[2].challengeName === 'CUSTOM_CHALLENGE' &&
+ event.request.session[2].challengeResult === true
+ ) {
+ event.response.issueTokens = true;
+ event.response.failAuthentication = false;
+ } else {
+ event.response.issueTokens = false;
+ event.response.failAuthentication = true;
+ }
+
+ return event;
+};
+```
+
+
+---
+
+---
+title: "Email customization"
+section: "build-a-backend/auth/customize-auth-lifecycle"
+platforms: ["android", "angular", "flutter", "javascript", "nextjs", "react", "react-native", "swift", "vue"]
+gen: 2
+last-updated: "2024-08-15T17:57:11.000Z"
+url: "https://docs.amplify.aws/react/build-a-backend/auth/customize-auth-lifecycle/email-customization/"
+---
+
+## Customize the Verification Email
+
+By default, Amplify Auth resources are scaffolded with email as the default method for your users to sign in. When you users sign up they receive a verification email to confirm their ownership of the email they specified during sign-up. Emails such as the verification email can be customized with your app's brand identity.
+
+To get started, change the `email` attribute of `loginWith` from `true` to an object to begin customizing its default behavior:
+
+```diff title="amplify/auth/resource.ts"
+import { defineAuth } from "@aws-amplify/backend"
+
+export const auth = defineAuth({
+ loginWith: {
+- email: true,
++ email: {
++ verificationEmailStyle: "CODE",
++ verificationEmailSubject: "Welcome to my app!",
++ verificationEmailBody: (createCode) => `Use this code to confirm your account: ${createCode()}`,
++ },
+ },
+})
+```
+
+## Customize the Invitation Email
+
+In some cases, you may [set up a user account on behalf of a user in the Amplify console](/[platform]/build-a-backend/auth/manage-users/with-amplify-console/). In this case, Amplify Auth will send an invitation email to the user welcoming them to your application. This email includes a brief welcome message, along with the email address they can log in with and the temporary password you've set up for them.
+
+If you'd like to customize that email, you can override the `userInvitation` attribute of the `email` object:
+
+```diff title="amplify/auth/resource.ts"
+import { defineAuth } from "@aws-amplify/backend"
+
+export const auth = defineAuth({
+ loginWith: {
+- email: true,
++ email: {
++ // can be used in conjunction with a customized welcome email as well
++ verificationEmailStyle: "CODE",
++ verificationEmailSubject: "Welcome to my app!",
++ verificationEmailBody: (createCode) => `Use this code to confirm your account: ${createCode()}`,
++ userInvitation: {
++ emailSubject: "Welcome to my app!",
++ emailBody: (user, code) =>
++ `We're happy to have you! You can now login with username ${user()} and temporary password ${code()}`,
++ },
++ },
+ },
+})
+```
+
+Note that when using the `user` and `code` arguments of the `emailBody` function, `user` and `code` are **functions** which must be called. Failure to call them will result in an error when your sandbox deploys.
+
+---
+
+---
+title: "Triggers"
+section: "build-a-backend/auth/customize-auth-lifecycle"
+platforms: ["android", "angular", "flutter", "javascript", "nextjs", "react", "react-native", "swift", "vue"]
+gen: 2
+last-updated: "2024-05-03T17:21:51.000Z"
+url: "https://docs.amplify.aws/react/build-a-backend/auth/customize-auth-lifecycle/triggers/"
+---
+
+Amplify Auth's behavior can be customized through the use of triggers. A trigger is defined as a Function, and is a mechanism to slot some logic to execute during the authentication flow. For example, you can use triggers to [validate whether emails include an allowlisted domain](/[platform]/build-a-backend/functions/examples/email-domain-filtering), [add a user to a group upon confirmation](/[platform]/build-a-backend/functions/examples/add-user-to-group), or [create a "UserProfile" model upon account confirmation](/[platform]/build-a-backend/functions/examples/create-user-profile-record).
+
+Triggers translate to [Cognito user pool Lambda triggers](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-identity-pools-working-with-aws-lambda-triggers.html).
+
+> When you have a Lambda trigger assigned to your user pool, Amazon Cognito interrupts its default flow to request information from your function. Amazon Cognito generates a JSON event and passes it to your function. The event contains information about your user's request to create a user account, sign in, reset a password, or update an attribute. Your function then has an opportunity to take action, or to send the event back unmodified.
+
+To get started, define a function and specify the `triggers` property on your auth resource:
+
+```ts title="amplify/auth/resource.ts"
+import { defineAuth } from "@aws-amplify/backend"
+
+export const auth = defineAuth({
+ loginWith: {
+ email: true,
+ },
+ // highlight-next-line
+ triggers: {}
+})
+```
+
+To learn more about use cases for triggers, visit the [Functions examples](/[platform]/build-a-backend/functions/examples/).
+
+---
+
+---
+title: "Enable sign-in with web UI"
+section: "build-a-backend/auth"
+platforms: ["flutter", "swift", "android"]
+gen: 2
+last-updated: "2025-12-16T19:28:39.000Z"
+url: "https://docs.amplify.aws/react/build-a-backend/auth/sign-in-with-web-ui/"
+---
+
+
+## Prerequisites
+* An app set up according to the [getting started walkthrough](/[platform]/build-a-backend/auth/set-up-auth/)
+
+> **Warning:** 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.
+
+## Configure Auth Category
+
+
+
+This library's Cognito plugin currently supports the [Authorization Code Grant](https://docs.aws.amazon.com/cognito/latest/developerguide/authorization-endpoint.html) OAuth Flow.
+
+
+
+In your `auth/resource.ts` file, update the
+```ts
+export const auth = defineAuth({
+ loginWith: {
+ email: true,
+ externalProviders: {
+ callbackUrls: ["myapp://callback/"],
+ logoutUrls: ["myapp://signout/"],
+ },
+ },
+});
+```
+
+## Update AndroidManifest.xml
+
+Add the following activity and queries tag to your app's `AndroidManifest.xml` file, replacing `myapp` with
+your redirect URI prefix if necessary:
+
+```xml
+
+ ...
+
+
+
+
+
+
+
+
+ ...
+
+```
+
+## Launch Web UI Sign In
+
+Sweet! You're now ready to launch sign in with web UI. For now, just add this method to the `onCreate` method of MainActivity:
+
+#### [Java]
+
+```java
+Amplify.Auth.signInWithWebUI(
+ this,
+ result -> Log.i("AuthQuickStart", result.toString()),
+ error -> Log.e("AuthQuickStart", error.toString())
+);
+```
+
+#### [Kotlin - Callbacks]
+
+```kotlin
+Amplify.Auth.signInWithWebUI(
+ this,
+ { Log.i("AuthQuickStart", "Signin OK = $it") },
+ { Log.e("AuthQuickStart", "Signin failed", it) }
+)
+```
+
+#### [Kotlin - Coroutines]
+
+```kotlin
+try {
+ val result = Amplify.Auth.signInWithWebUI(this)
+ Log.i("AuthQuickStart", "Signin OK: $result")
+} catch (error: AuthException) {
+ Log.e("AuthQuickStart", "Signin failed", error)
+}
+```
+
+#### [RxJava]
+
+```java
+RxAmplify.Auth.signInWithWebUI(this)
+ .subscribe(
+ result -> Log.i("AuthQuickStart", result.toString()),
+ error -> Log.e("AuthQuickStart", error.toString())
+ );
+```
+
+### Additional options during signIn
+
+You may pass additional parameters to the `Amplify.Auth.signInWithWebUI` which are added as query parameters in the requests to [Cognito authorization endpoint](https://docs.aws.amazon.com/cognito/latest/developerguide/authorization-endpoint.html).
+
+```kotlin
+val options = AWSCognitoAuthWebUISignInOptions.builder()
+ .nonce("randomUUID")
+ .language("en")
+ .loginHint("username")
+ .prompt(AuthWebUIPrompt.LOGIN, AuthWebUIPrompt.CONSENT)
+ .resource("https://localhost")
+ .build()
+
+Amplify.Auth.signInWithWebUI(
+ this,
+ options,
+ result -> Log.i("AuthQuickStart", result.toString()),
+ error -> Log.e("AuthQuickStart", error.toString())
+);
+```
+
+
+## Prerequisites
+
+> **Warning:** **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.
+
+For a full example, please follow the [project setup walkthrough](/[platform]/start/quickstart/).
+
+
+
+To use Auth in a macOS project, you'll need to enable the Keychain Sharing capability. In Xcode, navigate to **your application target** > **Signing & Capabilities** > **+ Capability**, then select **Keychain Sharing.**
+
+This capability is required because Auth uses the Data Protection Keychain on macOS as a platform best practice.
+See [TN3137: macOS keychain APIs and implementations](https://developer.apple.com/documentation/technotes/tn3137-on-mac-keychains) for more information on how Keychain works on macOS and the Keychain Sharing entitlement.
+
+For more information on adding capabilities to your application, see [Xcode Capabilities](https://developer.apple.com/documentation/xcode/capabilities).
+
+
+
+## Configure Auth Category
+
+
+
+This library's Cognito plugin currently supports the [Authorization Code Grant](https://docs.aws.amazon.com/cognito/latest/developerguide/authorization-endpoint.html) OAuth Flow.
+
+
+
+Update the `auth/resource.ts` file like the following to enable the sign-in and sign-out capabilities with a web ui.
+
+```ts
+export const auth = defineAuth({
+ loginWith: {
+ email: true,
+ externalProviders: {
+ callbackUrls: ["myapp://callback/"],
+ logoutUrls: ["myapp://signout/"],
+ },
+ },
+});
+```
+## Update Info.plist
+
+Signin with web UI require the Amplify plugin to show up the signin UI inside a webview. After the signin process is complete it will redirect back to your app.
+You have to enable this in your app's `Info.plist`. Right click Info.plist and then choose Open As > Source Code. Add the following entry in the URL scheme:
+
+```xml
+
+
+
+
+
+
+
+
+ CFBundleURLTypes
+
+
+ CFBundleURLSchemes
+
+ myapp
+
+
+
+
+
+
+```
+
+When creating a new SwiftUI app using Xcode 13 no longer require configuration files such as the Info.plist. If you are missing this file, click on the project target, under Info, Url Types, and click '+' to add a new URL Type. Add `myapp` to the URL Schemes. You should see the Info.plist file now with the entry for CFBundleURLSchemes.
+
+## Launch Web UI Sign In
+
+You're now ready to launch sign in with web UI. The `signInWithWebUI` api require a presentationAnchor and for an iOS app it will be the main UIWindow of the app. The example code below assume that you are in a UIViewController where you can fetch the UIWindow instance by `self.view.window`.
+
+#### [Async/Await]
+
+```swift
+func signInWithWebUI() async {
+ do {
+ let signInResult = try await Amplify.Auth.signInWithWebUI(presentationAnchor: self.view.window!)
+ if signInResult.isSignedIn {
+ print("Sign in succeeded")
+ }
+ } catch let error as AuthError {
+ print("Sign in failed \(error)")
+ } catch {
+ print("Unexpected error: \(error)")
+ }
+}
+```
+
+#### [Combine]
+
+```swift
+func signInWithWebUI() -> AnyCancellable {
+ Amplify.Publisher.create {
+ try await Amplify.Auth.signInWithWebUI(presentationAnchor: self.view.window!)
+ }.sink {
+ if case let .failure(authError) = $0 {
+ print("Sign in failed \(authError)")
+ }
+ }
+ receiveValue: { signInResult in
+ if signInResult.isSignedIn {
+ print("Sign in succeeded")
+ }
+ }
+}
+```
+
+### Prefer private session during signIn
+
+Starting Amplify 1.6.0, `Amplify.Auth.signInWithWebUI` automatically uses [ASWebAuthenticationSession](https://developer.apple.com/documentation/authenticationservices/aswebauthenticationsession) internally for iOS 13.0+. For older iOS versions, it will fall back to [SFAuthenticationSession](https://developer.apple.com/documentation/safariservices/sfauthenticationsession).
+This release also introduces a new `preferPrivateSession` flag to `AWSAuthWebUISignInOptions` during the sign in flow. If `preferPrivateSession` is set to `true` during sign in, the user will not see a web view displayed when they sign out. `preferPrivateSession` will set [ASWebAuthenticationSession.prefersEphemeralWebBrowserSession](https://developer.apple.com/documentation/authenticationservices/aswebauthenticationsession/3237231-prefersephemeralwebbrowsersessio) internally and the authentication session will be private if the user's preferred browser supports it.
+
+```swift
+try await Amplify.Auth.signInWithWebUI(
+ presentationAnchor: self.view.window!,
+ options: .preferPrivateSession()
+) {
+ ...
+}
+```
+
+### Additional options during signIn
+
+You may pass additional parameters to the `Amplify.Auth.signInWithWebUI` which are added as query parameters in the requests to [Cognito authorization endpoint](https://docs.aws.amazon.com/cognito/latest/developerguide/authorization-endpoint.html).
+
+```swift
+let options = AuthWebUISignInRequest.Options(
+ pluginOptions: AWSAuthWebUISignInOptions.init(
+ nonce: "randomUUID",
+ language: "en",
+ loginHint: "username",
+ prompt: [.login, .consent],
+ resource: "http://localhost"))
+
+let signInResult = try await Amplify.Auth.signInWithWebUI(
+ presentationAnchor: self.view.window!,
+ options: options)
+```
+
+
+## Prerequisites
+
+* An app set up according to the [getting started walkthrough](/[platform]/build-a-backend/auth/set-up-auth/)
+
+> **Warning:** 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.
+
+## Configure Auth Category
+
+
+
+This library's Cognito plugin currently supports the [Authorization Code Grant](https://docs.aws.amazon.com/cognito/latest/developerguide/authorization-endpoint.html) OAuth Flow.
+
+
+
+Update the `auth/resource.ts` file like the following to enable the sign-in and sign-out capabilities with a web ui.
+
+```ts
+export const auth = defineAuth({
+ loginWith: {
+ email: true,
+ externalProviders: {
+ callbackUrls: ["myapp://callback/"],
+ logoutUrls: ["myapp://signout/"],
+ },
+ },
+});
+```
+
+## How It Works
+
+Sign-in with web UI will display the sign-in UI inside a webview. After the sign-in process is complete, the sign-in UI will redirect back to your app.
+
+## Platform Setup
+
+### Web
+
+To use Hosted UI in your Flutter web application locally, you must run the app with the `--web-port=3000` argument (with the value being whichever port you assigned to localhost host when configuring your redirect URIs).
+
+### Android
+
+Add the following `queries` element to the `AndroidManifest.xml` file in your app's `android/app/src/main` directory, as well as the following `intent-filter` to the `MainActivity` in the same file.
+
+Replace `myapp` with your redirect URI scheme as necessary:
+
+```xml
+
+
+
+
+
+
+ ...
+
+
+
+
+
+
+
+
+ ...
+
+```
+
+### macOS
+
+Open XCode and enable the App Sandbox capability and then select "Incoming Connections (Server)" under "Network".
+
+
+
+### iOS, Windows and Linux
+
+No specific platform configuration is required.
+
+## Launch Web UI Sign In
+
+You're now ready to launch sign in with web UI.
+
+```dart
+Future signInWithWebUI() async {
+ try {
+ final result = await Amplify.Auth.signInWithWebUI();
+ safePrint('Sign in result: $result');
+ } on AuthException catch (e) {
+ safePrint('Error signing in: ${e.message}');
+ }
+}
+```
+
+You can also specify a provider with the `provider` attribute:
+
+```dart
+Future signInWithWebUIProvider() async {
+ try {
+ final result = await Amplify.Auth.signInWithWebUI(
+ provider: AuthProvider.google,
+ );
+ safePrint('Result: $result');
+ } on AuthException catch (e) {
+ safePrint('Error signing in: ${e.message}');
+ }
+}
+```
+
+Amplify Flutter currently supports the following social sign-in providers:
+ * Google
+ * Facebook
+ * Login With Amazon
+ * Apple
+
+### Prefer private session during signIn on iOS.
+
+Amplify.Auth.signInWithWebUI uses [ASWebAuthenticationSession](https://developer.apple.com/documentation/authenticationservices/aswebauthenticationsession) internally for iOS. ASWebAuthenticationSession has a property, [prefersEphemeralWebBrowserSession](https://developer.apple.com/documentation/authenticationservices/aswebauthenticationsession/3237231-prefersephemeralwebbrowsersessio) which can be used to indicate whether the session should ask the browser for a private authentication session. To set this flag to true, set `preferPrivateSession` to true using `CognitoSignInWithWebUIPluginOptions`.
+
+This will bypass the permissions dialog that is displayed to the end user during sign in and sign out. However, it will also prevent reuse of existing sessions from the user's browser. For example, if the user is logged into Google in their browser and try to sign in using Google in your app, they would now need to re-enter their credentials.
+
+```dart
+Future signInWithWebUIAndPrivateSession() async {
+ await Amplify.Auth.signInWithWebUI(
+ options: const SignInWithWebUIOptions(
+ pluginOptions: CognitoSignInWithWebUIPluginOptions(
+ isPreferPrivateSession: true,
+ ),
+ ),
+ );
+}
+```
+
+### Additional options during signIn
+
+You may pass additional parameters to the `Amplify.Auth.signInWithWebUI` which are added as query parameters in the requests to [Cognito authorization endpoint](https://docs.aws.amazon.com/cognito/latest/developerguide/authorization-endpoint.html).
+
+```dart
+Future signInWithWebUIAndOptions() async {
+ try {
+ final result = await Amplify.Auth.Amplify.Auth.signInWithWebUI(
+ options: SignInWithWebUIOptions(pluginOptions: CognitoSignInWithWebUIPluginOptions(
+ nonce: 'randomUUID',
+ language: 'en',
+ loginHint: 'username',
+ prompt: List.from([CognitoSignInWithWebUIPrompt.login, CognitoSignInWithWebUIPrompt.consent]),
+ resource: 'http://localhost'
+ )
+ )
+ );
+ safePrint('Sign in result: $result');
+ } on AuthException catch (e) {
+ safePrint('Error signing in: ${e.message}');
+ }
+}
+```
+
+
+---
+
+---
+title: "Uninstalling the app"
+section: "build-a-backend/auth"
+platforms: ["swift", "android"]
+gen: 2
+last-updated: "2024-05-02T22:35:36.000Z"
+url: "https://docs.amplify.aws/react/build-a-backend/auth/app-uninstall/"
+---
+
+
+Some Amplify categories such as Analytics and Auth persist data to the local device. This application data is removed when a user uninstalls the application from the device.
+
+If the [Android Auto Backup for Apps](https://developer.android.com/guide/topics/data/autobackup) service was enabled, this service will attempt to restore application data.
+
+Amplify Auth uses [EncryptedSharedPreferences](https://developer.android.com/reference/androidx/security/crypto/EncryptedSharedPreferences) when persisting auth data. When an application is uninstalled, the [Android Keystore](https://developer.android.com/training/articles/keystore) keys used to create our EncryptedSharedPreferences files are deleted. Upon an application re-install, these restored files are no longer readable due to the key removal from the Android Keystore.
+
+Due to this limitation with EncryptedSharedPreferences, Auth information canβt be restored on an application re-install. The user will have to re-authenticate.
+
+
+
+Some Amplify categories such as Analytics and Auth persist data to the local device. Some of that data is automatically removed when a user uninstalls the app from the device.
+
+Amplify stores Auth information in the local [system keychain](https://developer.apple.com/documentation/security/keychain_services), which does not guarantee any particular behavior around whether data is removed when an app is uninstalled.
+
+Deciding on when to clear this auth information is not something that the SDK can do in a generic way, so App developers should decide when to clear the data by signing out. One strategy for accomplishing this would be to use [UserDefaults](https://developer.apple.com/documentation/foundation/userdefaults) to detect whether or not the app is launching for the first time, and invoking [`Auth.signOut()`](/[platform]/build-a-backend/auth/connect-your-frontend/sign-out/) if the app has not been launched before.
+
+
+---
+
+---
+title: "Data usage policy information"
+section: "build-a-backend/auth"
+platforms: ["swift"]
+gen: 2
+last-updated: "2024-05-02T22:35:36.000Z"
+url: "https://docs.amplify.aws/react/build-a-backend/auth/data-usage-policy/"
+---
+
+
+Apple requires app developers to provide the data usage policy of the app when they submit their app to the App Store. See Apple's [User privacy and data use](https://developer.apple.com/app-store/user-privacy-and-data-use/) for more details. The Amplify Library is used to interact with AWS resources under the developerβs ownership and management. The library cannot predict the usage of its APIs and it is up to the developer to provide the privacy manifest that accurately reflects the data collected by the app. Below are the different categories identified by Apple and the corresponding data type used by the Amplify Library.
+
+By utilizing the library, Amplify gathers API usage metrics from the AWS services accessed. This process involves adding a user agent to the request made to your AWS service. The user-agent header is included with information about the Amplify Library version, operating system name, and version. AWS collects this data to generate metrics related to our library usage. This information is not linked to the userβs identity and not used for tracking purposes as described in Apple's privacy and data use guidelines.
+
+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
+
+| Data Type | Amplify Category | Purpose | Linked To Identity | Tracking | Provided by developer |
+| ------------------------------ | ------------------ | ------------------- | :------------------: | :--------: | :---------------------: |
+| **Name** | | | | | |
+| | Auth | App Functionality | β | β | β |
+| **Email Address** | | | | | |
+| | Auth | App Functionality | β | β | β |
+| **Phone Number** | | | | | |
+| | Auth | App Functionality | β | β | β |
+
+## User Content
+
+| Data Type | Amplify Category | Purpose | Linked To Identity | Tracking | Provided by developer |
+| ------------------------------ | ------------------ | ------------------- | :------------------: | :--------: | :---------------------: |
+| **Photos or Videos** | | | | | |
+| | Storage | App Functionality | β | β | β |
+| | Predictions | App Functionality | β | β | β |
+| **Audio Data** | | | | | |
+| | Predictions | App Functionality | β | β | β |
+
+## Identifiers
+
+| Data Type | Amplify Category | Purpose | Linked To Identity | Tracking | Provided by developer |
+| ------------------------------ | ------------------ | ------------------- | :------------------: | :--------: | :---------------------: |
+| **User ID** | | | | | |
+| | Auth | App Functionality | β | β | β |
+| | Analytics | Analytics | β | β | β |
+| **Device ID** | | | | | |
+| | Auth | App Functionality | β | β | β |
+| | Analytics | Analytics | β | β | β |
+
+## Other Data
+
+| Data Type | Amplify Category | Purpose | Linked To Identity | Tracking | Provided by developer |
+| ------------------------------ | ------------------ | ------------------- | :------------------: | :--------: | :---------------------: |
+| **OS Version** | | | | | |
+| | All categories | Analytics | β | β | β |
+| **OS Name** | | | | | |
+| | All categories | Analytics | β | β | β |
+| **Locale Info** | | | | | |
+| | All categories | Analytics | β | β | β |
+| **App Version** | | | | | |
+| | Auth | App Functionality | β | β | β |
+| **Min OS target of the app** | | | | | |
+| | Auth | App Functionality | β | β | β |
+| **Timezone information** | | | | | |
+| | Auth | App Functionality | β | β | β |
+| **Network information** | | | | | |
+| | Auth | App Functionality | β | β | β |
+| **Has SIM card** | | | | | |
+| | Auth | App Functionality | β | β | β |
+| **Cellular Carrier Name** | | | | | |
+| | Auth | App Functionality | β | β | β |
+| **Device Model** | | | | | |
+| | Auth | App Functionality | β | β | β |
+| **Device Name** | | | | | |
+| | Auth | App Functionality | β | β | β |
+| **Device OS Version** | | | | | |
+| | Auth | App Functionality | β | β | β |
+| **Device Height and Width** | | | | | |
+| | Auth | App Functionality | β | β | β |
+| **Device Language** | | | | | |
+| | Auth | App Functionality | β | β | β |
+| **identifierForVendor** | | | | | |
+| | Auth | App Functionality | β | β | β |
+
+## Health and Fitness
+No data is collected
+
+## Financial Info
+No data is collected
+
+## Location
+No data is collected
+
+## Sensitive Info
+No data is collected
+
+## Contacts
+No data is collected
+
+## Browsing History
+No data is collected
+
+## Search History
+No data is collected
+
+## Diagnostics
+No data is collected
+
+
+Some Amplify categories such as Analytics and Auth persist data to the local device. Some of that data is automatically removed when a user uninstalls the app from the device.
+
+Amplify stores Auth information in the local [system keychain](https://developer.apple.com/documentation/security/keychain_services), which does not guarantee any particular behavior around whether data is removed when an app is uninstalled.
+
+Deciding on when to clear this auth information is not something that the SDK can do in a generic way, so App developers should decide when to clear the data by signing out. One strategy for accomplishing this would be to use [UserDefaults](https://developer.apple.com/documentation/foundation/userdefaults) to detect whether or not the app is launching for the first time, and invoking [`Auth.signOut()`](/[platform]/build-a-backend/auth/connect-your-frontend/sign-out/) if the app has not been launched before.
+
+---
+
+---
+title: "Examples"
+section: "build-a-backend/auth"
+platforms: ["android", "angular", "flutter", "javascript", "nextjs", "react", "react-native", "swift", "vue"]
+gen: 2
+last-updated: "2024-10-18T22:15:30.000Z"
+url: "https://docs.amplify.aws/react/build-a-backend/auth/examples/"
+---
+
+
+
+---
+
+---
+title: "Microsoft Entra ID (SAML)"
+section: "build-a-backend/auth/examples"
+platforms: ["android", "angular", "flutter", "javascript", "nextjs", "react", "react-native", "swift", "vue"]
+gen: 2
+last-updated: "2025-02-28T16:21:52.000Z"
+url: "https://docs.amplify.aws/react/build-a-backend/auth/examples/microsoft-entra-id-saml/"
+---
+
+Microsoft Entra ID can be configured as a SAML provider for use with Amazon Cognito. Integrating Entra ID enables you to sign in with your existing enterprise users, and maintain profiles unique to the Amplify Auth resource for use within your Amplify app. To learn more, visit the [Azure documentation for SAML authentication with Microsoft Entra ID](https://learn.microsoft.com/en-us/entra/architecture/auth-saml).
+
+> **Info:** **Note:** the following guidance showcases configuration with your [personal cloud sandbox](/[platform]/deploy-and-host/sandbox-environments/setup/). You will need to repeat the configuration steps for branch deployments after confirming functionality against your sandbox.
+
+## Start your personal cloud sandbox
+
+To get started, define your auth resource with the appropriate redirect URIs:
+
+```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,
+ externalProviders: {
+ logoutUrls: ["http://localhost:3000/come-back-soon"],
+ callbackUrls: ["http://localhost:3000/profile"],
+ },
+ },
+})
+```
+
+Deploy to your personal cloud sandbox with `npx ampx sandbox`. This will generate a domain you can use to configure your new Entra ID App. After deploying your changes successfully, copy the generated `domain` value from `amplify_outputs.json`
+
+```json title="amplify_outputs.json"
+{
+ "auth": {
+ "aws_region": "us-east-1",
+ "user_pool_id": "",
+ "user_pool_client_id": "",
+ "identity_pool_id": "",
+ "mfa_methods": [],
+ "standard_required_attributes": [
+ "email"
+ ],
+ "username_attributes": [
+ "email"
+ ],
+ "user_verification_types": [
+ "email"
+ ],
+ "mfa_configuration": "OFF",
+ "password_policy": {
+ "min_length": 8,
+ "require_numbers": true,
+ "require_lowercase": true,
+ "require_uppercase": true,
+ "require_symbols": true
+ },
+ "oauth": {
+ "identity_providers": [],
+ "redirect_sign_in_uri": [
+ "http://localhost:3000/profile"
+ ],
+ "redirect_sign_out_uri": [
+ "http://localhost:3000/come-back-soon"
+ ],
+ "response_type": "code",
+ "scopes": [
+ "phone",
+ "email",
+ "openid",
+ "profile",
+ "aws.cognito.signin.user.admin"
+ ],
+ // highlight-next-line
+ "domain": ".auth.us-east-1.amazoncognito.com"
+ },
+ },
+ "version": "1"
+}
+```
+
+## Set up Microsoft Entra ID
+
+Next, navigate to [portal.azure.com](https://portal.azure.com/), select **Entra ID**. In your default directory, or company's existing directory, under **Manage**, select **Enterprise Applications**
+
+
+
+Afterwards, select **New application**, then select **Create your own application**. Specify a name for the application and choose **Integrate any other application you don't find in the gallery (Non-gallery)**
+
+
+
+Now that you have created the new enterprise application you can begin to configure Single Sign-on with SAML. Select **Single sign-on**
+
+
+
+Then select **SAML**
+
+
+
+You will be directed to a page to set up single sign-on with SAML, which needs a few pieces of information from your Amplify Auth resource.
+
+
+
+In the **Basic SAML Configuration** step, select **Edit** and populate with the appropriate values.
+
+| Label | Value |
+|-------|-------|
+| Identifier (Entity ID) | `urn:amazon:cognito:sp:` |
+| Reply URL (Assertion Consumer Service URL) | `https:///saml2/idpresponse` |
+| Logout Url (Optional) | `https:///saml2/logout` |
+
+> **Info:** **Note:** Amazon Cognito redirect URIs for SAML providers follow the convention:
+>
+> ```text showLineNumbers={false}
+https://.auth..amazoncognito.com/saml2/
+```
+>
+> If you are using a custom domain the route remains the same: `/saml2/`. [Learn more about configuring Amazon Cognito with SAML identity providers](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-saml-idp.html)
+
+> **Warning:** **Warning:** there is a known limitation where upstream sign-out functionality successfully signs out of Entra ID, but fails to redirect back to the user app. This behavior is disabled by default with SAML integrations in Amplify Auth.
+
+Save the configuration and proceed to Step 3's **SAML Certificates** section. Copy the **App Federation Metadata Url**
+
+
+
+## Configure your backend with Entra ID
+
+Now that you've configured your SAML provider with Microsoft Entra ID and copied the **App Federation Metadata Url**, configure your auth resource with the new SAML provider and paste the URL value into the `metadataContent` property:
+
+```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,
+ externalProviders: {
+ saml: {
+ name: "MicrosoftEntraIDSAML",
+ metadata: {
+ metadataType: "URL",
+ metadataContent: "",
+ },
+ attributeMapping: {
+ email: "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress",
+ },
+ },
+ logoutUrls: ["http://localhost:3000/come-back-soon"],
+ callbackUrls: ["http://localhost:3000/profile"],
+ },
+ },
+})
+```
+
+User attributes can be found in Step 2's **Attributes & Claims** section, and are prefixed with a namespace by default. The example above shows mapping the default claim for the SAML user's email address, however additional attributes can be mapped.
+
+## Optionally upload the Cognito Signing Certificate
+
+In the AWS Console, navigate to your Cognito User Pool. Select the identity provider, **MicrosoftEntraIDSAML**, created after configuring Amplify Auth with the Entra ID SAML provider. Select **View signing certificate** and **download as .crt**
+
+
+
+Rename the file extension to `.cer` in order to upload to Azure. On the **Single sign-on** page, scroll down to **Step 3** (**SAML Certificates**), and under **Verification Certificates (optional)**, select **Edit**.
+
+
+
+Select **Require verification certificates** and upload the certificate.
+
+
+
+Save your changes, and now requests to Entra ID from your Cognito User Pool will be verified.
+
+## Connect your frontend
+
+Now your users are ready to sign in with Microsoft Entra ID. To sign in with this custom provider, specify the provider name as the name specified in your auth resource definition: `MicrosoftEntraIDSAML`
+
+
+```ts title="main.ts"
+import { signInWithRedirect } from "aws-amplify/auth"
+
+signInWithRedirect({
+ provider: { custom: "MicrosoftEntraIDSAML" }
+})
+```
+
+
+
+#### [Java]
+
+```java
+Amplify.Auth.signInWithSocialWebUI(
+ AuthProvider.custom("MicrosoftEntraIDSAML")
+ this,
+ result -> Log.i("AuthQuickStart", result.toString()),
+ error -> Log.e("AuthQuickStart", error.toString())
+);
+```
+
+#### [Kotlin - Callbacks]
+
+```kotlin
+Amplify.Auth.signInWithSocialWebUI(
+ AuthProvider.custom("MicrosoftEntraIDSAML"),
+ this,
+ { Log.i("AuthQuickstart", "Sign in OK: $it") },
+ { Log.e("AuthQuickstart", "Sign in failed", it) }
+)
+```
+
+#### [Kotlin - Coroutines]
+
+```kotlin
+try {
+ val result = Amplify.Auth.signInWithSocialWebUI(AuthProvider.custom("MicrosoftEntraIDSAML"), this)
+ Log.i("AuthQuickstart", "Sign in OK: $result")
+} catch (error: AuthException) {
+ Log.e("AuthQuickstart", "Sign in failed", error)
+}
+```
+
+#### [RxJava]
+
+```java
+RxAmplify.Auth.signInWithSocialWebUI(AuthProvider.custom("MicrosoftEntraIDSAML"), this)
+ .subscribe(
+ result -> Log.i("AuthQuickstart", result.toString()),
+ error -> Log.e("AuthQuickstart", error.toString())
+ );
+```
+
+
+
+```dart
+Future signInWithMicrosoftEntraID() async {
+ try {
+ final result = await Amplify.Auth.signInWithWebUI(
+ provider: AuthProvider.custom("MicrosoftEntraIDSAML"),
+ );
+ safePrint('Sign in result: $result');
+ } on AuthException catch (e) {
+ safePrint('Error signing in: ${e.message}');
+ }
+}
+```
+
+
+
+#### [Async/Await]
+
+```swift
+func signInWithMicrosoftEntraID() async {
+ do {
+ let signInResult = try await Amplify.Auth.signInWithWebUI(
+ for: AuthProvider.custom("MicrosoftEntraIDSAML"),
+ presentationAnchor: self.view.window!
+ )
+ if signInResult.isSignedIn {
+ print("Sign in succeeded")
+ }
+ } catch let error as AuthError {
+ print("Sign in failed \(error)")
+ } catch {
+ print("Unexpected error: \(error)")
+ }
+}
+```
+
+#### [Combine]
+
+```swift
+func signInWithMicrosoftEntraID() -> AnyCancellable {
+ Amplify.Publisher.create {
+ try await Amplify.Auth.signInWithWebUI(
+ for: AuthProvider.custom("MicrosoftEntraIDSAML"),
+ presentationAnchor: self.view.window!
+ )
+ }
+ .sink { completion in
+ if case let .failure(authError) = completion {
+ print("Sign in failed \(authError)")
+ }
+ } receiveValue: { signInResult in
+ if signInResult.isSignedIn {
+ print("Sign in succeeded")
+ }
+ }
+}
+```
+
+
+
+---
+
+---
+title: "Grant access to auth resources"
+section: "build-a-backend/auth"
+platforms: ["android", "angular", "flutter", "javascript", "nextjs", "react", "react-native", "swift", "vue"]
+gen: 2
+last-updated: "2024-07-12T17:36:34.000Z"
+url: "https://docs.amplify.aws/react/build-a-backend/auth/grant-access-to-auth-resources/"
+---
+
+Amplify Auth can be defined with an `access` property, which allows other resources to interact with auth by specifying actions.
+
+```ts title="amplify/auth/resource.ts"
+import { defineAuth } from "@aws-amplify/backend"
+import { addUserToGroup } from "../functions/add-user-to-group/resource"
+
+/**
+ * Define and configure your auth resource
+ * @see https://docs.amplify.aws/gen2/build-a-backend/auth
+ */
+export const auth = defineAuth({
+ loginWith: {
+ email: true,
+ },
+ access: (allow) => [
+ allow.resource(addUserToGroup).to(["addUserToGroup"])
+ ],
+})
+```
+
+
+
+When you grant a function access to another resource in your Amplify backend it will configure environment variables for that function to make SDK calls to the AWS services it has access to. Those environment variables are typed and available as part of the `env` object.
+
+
+
+## List of actions
+
+|Action Name|Description|Cognito IAM Actions|
+|-|-|-|
+|manageUsers | Grants CRUD access to users in the UserPool |
cognito-idp:AdminConfirmSignUp
cognito-idp:AdminCreateUser
cognito-idp:AdminDeleteUser
cognito-idp:AdminDeleteUserAttributes
cognito-idp:AdminDisableUser
cognito-idp:AdminEnableUser
cognito-idp:AdminGetUser
cognito-idp:AdminListGroupsForUser
cognito-idp:AdminRespondToAuthChallenge
cognito-idp:AdminSetUserMFAPreference
cognito-idp:AdminSetUserSettings
cognito-idp:AdminUpdateUserAttributes
cognito-idp:AdminUserGlobalSignOut
|
+|manageGroupMembership | Grants permission to add and remove users from groups |
cognito-idp:AdminAddUserToGroup
cognito-idp:AdminRemoveUserFromGroup
|
+|manageGroups | Grants CRUD access to groups in the UserPool |
cognito-idp:GetGroup
cognito-idp:ListGroups
cognito-idp:CreateGroup
cognito-idp:DeleteGroup
cognito-idp:UpdateGroup
|
+|manageUserDevices | Manages devices registered to users|
cognito-idp:AdminForgetDevice
cognito-idp:AdminGetDevice
cognito-idp:AdminListDevices
cognito-idp:AdminUpdateDeviceStatus
|
+|managePasswordRecovery | Grants permission to reset user passwords |
cognito-idp:AdminResetUserPassword
cognito-idp:AdminSetUserPassword
|
+|addUserToGroup | Grants permission to add any user to any group. |
cognito-idp:AdminAddUserToGroup
+|createUser | Grants permission to create new users and send welcome messages via email or SMS. |
cognito-idp:AdminCreateUser
+|deleteUser | Grants permission to delete any user |
cognito-idp:AdminDeleteUser
+|deleteUserAttributes | Grants permission to delete attributes from any user |
cognito-idp:AdminDeleteUserAttributes
+|disableUser | Grants permission to deactivate any user |
cognito-idp:AdminDisableUser
+|enableUser | Grants permission to activate any user |
cognito-idp:AdminEnableUser
+|forgetDevice | Grants permission to deregister any user's devices |
cognito-idp:AdminForgetDevice
+|getDevice | Grants permission to get information about any user's devices |
cognito-idp:AdminGetDevice
+|getUser | Grants permission to look up any user by user name |
cognito-idp:AdminGetUser
+|listUsers | Grants permission to list users and their basic details in the UserPool |
cognito-idp:ListUsers
+|listDevices | Grants permission to list any user's remembered devices |
cognito-idp:AdminListDevices
+|listGroupsForUser | Grants permission to list the groups that any user belongs to |
cognito-idp:AdminListGroupsForUser
+|listUsersInGroup | Grants permission to list users in the specified group |
cognito-idp:ListUsersInGroup
+|removeUserFromGroup | Grants permission to remove any user from any group |
cognito-idp:AdminRemoveUserFromGroup
+|resetUserPassword | Grants permission to reset any user's password |
cognito-idp:AdminResetUserPassword
+|setUserMfaPreference | Grants permission to set any user's preferred MFA method |
cognito-idp:AdminSetUserMFAPreference
+|setUserPassword | Grants permission to set any user's password |
cognito-idp:AdminSetUserPassword
+|setUserSettings | Grants permission to set user settings for any user |
cognito-idp:AdminSetUserSettings
+|updateDeviceStatus | Grants permission to update the status of any user's remembered devices |
cognito-idp:AdminUpdateDeviceStatus
+|updateUserAttributes | Grants permission to updates any user's standard or custom attributes |
cognito-idp:AdminUpdateUserAttributes
+
+---
+
+---
+title: "Modify Amplify-generated Cognito resources with CDK"
+section: "build-a-backend/auth"
+platforms: ["android", "angular", "flutter", "javascript", "nextjs", "react", "react-native", "swift", "vue"]
+gen: 2
+last-updated: "2025-12-03T11:13:25.000Z"
+url: "https://docs.amplify.aws/react/build-a-backend/auth/modify-resources-with-cdk/"
+---
+
+Amplify Auth provides sensible defaults for the underlying Amazon Cognito resource definitions. You can customize your authentication resource to enable it to behave exactly as needed for your use cases by modifying it directly using [AWS Cloud Development Kit (CDK)](https://aws.amazon.com/cdk/)
+
+## Override Cognito UserPool password policies
+
+You can override the password policy by using the L1 `cfnUserPool` construct and adding a `addPropertyOverride`.
+
+```ts title="amplify/backend.ts"
+import { defineBackend } from '@aws-amplify/backend';
+import { auth } from './auth/resource';
+
+const backend = defineBackend({
+ auth,
+});
+// extract L1 CfnUserPool resources
+const { cfnUserPool } = backend.auth.resources.cfnResources;
+// modify cfnUserPool policies directly
+cfnUserPool.policies = {
+ passwordPolicy: {
+ minimumLength: 10,
+ requireLowercase: true,
+ requireNumbers: true,
+ requireSymbols: true,
+ requireUppercase: true,
+ temporaryPasswordValidityDays: 20,
+ },
+};
+```
+
+
+## Override Cognito UserPool to enable passwordless sign-in methods
+
+> **Info:** **Recommended approach:** Passwordless authentication can now be configured directly in `defineAuth` without requiring CDK overrides. [Learn how to configure passwordless authentication](/[platform]/build-a-backend/auth/concepts/passwordless/).
+
+For advanced use cases, you can still modify the underlying Cognito user pool resource to enable sign in with passwordless methods using CDK overrides. [Learn more about passwordless sign-in methods](/[platform]/build-a-backend/auth/concepts/passwordless/).
+
+You can also read more about how passwordless authentication flows are implemented in the [Cognito documentation](https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-authentication-flow-methods.html).
+
+```ts title="amplify/backend.ts"
+import { defineBackend } from "@aws-amplify/backend"
+import { auth } from "./auth/resource"
+
+const backend = defineBackend({
+ auth,
+})
+
+const { cfnResources } = backend.auth.resources;
+const { cfnUserPool, cfnUserPoolClient } = cfnResources;
+
+// Specify which authentication factors you want to allow with USER_AUTH
+cfnUserPool.addPropertyOverride(
+ 'Policies.SignInPolicy.AllowedFirstAuthFactors',
+ ['PASSWORD', 'WEB_AUTHN', 'EMAIL_OTP', 'SMS_OTP']
+);
+
+// The USER_AUTH flow is used for passwordless sign in
+cfnUserPoolClient.explicitAuthFlows = [
+ 'ALLOW_REFRESH_TOKEN_AUTH',
+ 'ALLOW_USER_AUTH'
+];
+
+/* Needed for WebAuthn */
+// The WebAuthnRelyingPartyID is the domain of your relying party, e.g. "example.domain.com"
+cfnUserPool.addPropertyOverride('WebAuthnRelyingPartyID', '');
+cfnUserPool.addPropertyOverride('WebAuthnUserVerification', 'preferred');
+```
+
+
+---
+
+---
+title: "Moving to production"
+section: "build-a-backend/auth"
+platforms: ["android", "angular", "flutter", "javascript", "nextjs", "react", "react-native", "swift", "vue"]
+gen: 2
+last-updated: "2024-10-10T22:55:38.000Z"
+url: "https://docs.amplify.aws/react/build-a-backend/auth/moving-to-production/"
+---
+
+Amplify Auth provisions [Amazon Cognito](https://aws.amazon.com/cognito/) resources that are provisioned with limited capabilities for sending email and SMS messages. In its default state, it is not intended to handle production workloads, but is sufficient for developing your application and associated business logic.
+
+## Email
+
+Cognito provides a [default email functionality](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-email.html#user-pool-email-default) that limits how many emails can be sent in one day. When considering production workloads, Cognito can be configured to send emails using [Amazon Simple Email Service (Amazon SES)](https://aws.amazon.com/ses/).
+
+> **Warning:** All new AWS accounts default to a "sandbox" status with Amazon SES. This comes with the primary caveat that you can only send mail **to** verified email addresses and domains
+
+To get started with Amazon SES in production, you must first [request production access](https://docs.aws.amazon.com/ses/latest/dg/request-production-access.html). Once you submit your request the submission cannot be modified, however you will receive a response from AWS within 24 hours.
+
+After you have configured your account for production access and have verified your _sender_ email, you can configure your Cognito user pool to send emails using the verified sender:
+
+```ts title="amplify/auth/resource.ts"
+import { defineAuth } from "@aws-amplify/backend"
+
+/**
+ * Define and configure your auth resource
+ * @see https://docs.amplify.aws/react/build-a-backend/auth
+ */
+export const auth = defineAuth({
+ loginWith: {
+ email: true,
+ },
+ senders: {
+ email: {
+ // configure using the email registered and verified in Amazon SES
+ fromEmail: "registrations@example.com",
+ },
+ },
+})
+```
+
+Now when emails are sent on new user sign-ups, password resets, etc., the sending account will be your verified email! To customize further, you can change the display name of the sender, or optionally apply a custom address for your users to reply.
+
+```ts title="amplify/auth/resource.ts"
+import { defineAuth } from "@aws-amplify/backend"
+
+/**
+ * Define and configure your auth resource
+ * @see https://docs.amplify.aws/react/build-a-backend/auth
+ */
+export const auth = defineAuth({
+ loginWith: {
+ email: true,
+ },
+ senders: {
+ email: {
+ fromEmail: "registrations@example.com",
+ // highlight-start
+ fromName: "MyApp",
+ replyTo: "inquiries@example.com"
+ // highlight-end
+ },
+ },
+})
+```
+
+## SMS
+
+In order to send SMS authentication codes, you must [request an origination number](https://docs.aws.amazon.com/pinpoint/latest/userguide/settings-request-number.html). Authentication codes will be sent from the origination number. If your AWS account is in the SMS sandbox, you must also add a destination phone number, which can be done by going to the [Amazon Pinpoint Console](https://console.aws.amazon.com/pinpoint/), selecting SMS and voice in the navigation pane, and selecting Add phone number in the Destination phone numbers tab. To check if your AWS account is in the SMS sandbox, go to the [SNS console](https://console.aws.amazon.com/sns/), select the Text messaging (SMS) tab from the navigation pane, and check the status under the Account information section.
+
+---
+
+---
+title: "Advanced workflows"
+section: "build-a-backend/auth"
+platforms: ["javascript", "react-native", "flutter", "swift", "android", "angular", "nextjs", "react", "vue"]
+gen: 2
+last-updated: "2025-11-19T19:55:05.000Z"
+url: "https://docs.amplify.aws/react/build-a-backend/auth/advanced-workflows/"
+---
+
+
+## Identity Pool Federation
+
+With identity federation, you don't need to create custom sign-in code or manage your own user identities. Instead, users of your app can sign in using a well-known external identity
+provider (IdP), such as Login with Amazon, Facebook, Google, or any other OpenID Connect (OIDC)-compatible IdP. They can receive an authentication token, and then exchange that token for
+temporary security credentials in AWS that map to an IAM role with permissions to use the resources in your AWS account. Using an IdP helps you keep your AWS account secure because you
+don't have to embed and distribute long-term security credentials with your application.
+
+Imagine that you are creating a mobile app that accesses AWS resources, such as a game that runs on a mobile device and stores player and score information using Amazon S3 and DynamoDB.
+
+When you write such an app, you make requests to AWS services that must be signed with an AWS access key. However, we strongly recommend that you do not embed or distribute long-term
+AWS credentials with apps that a user downloads to a device, even in an encrypted store. Instead, build your app so that it requests temporary AWS security credentials dynamically when
+needed using identity federation. The supplied temporary credentials map to an AWS role that has only the permissions needed to perform the tasks required by the mobile app.
+
+You can use `federateToIdentityPool` to get AWS credentials directly from Cognito Federated Identities and not use User Pool federation. If you logged in with `Auth.signIn` you **cannot**
+call `federateToIdentityPool` as Amplify will perform this federation automatically for you in the background. In general, you should only call `Auth.federatedSignIn()` when using OAuth flows.
+
+You can use the escape hatch API `federateToIdentityPool` with a valid token from other social providers.
+
+```dart
+final cognitoPlugin =
+ Amplify.Auth.getPlugin(AmplifyAuthCognito.pluginKey);
+const googleIdToken = 'idToken';
+final session = await cognitoPlugin.federateToIdentityPool(
+ token: googleIdToken,
+ provider: AuthProvider.google,
+);
+```
+
+
+
+Note that when federated, APIs such as `Auth.getCurrentUser` will throw an error as the user is not authenticated with User Pools.
+
+
+
+### Retrieve Session
+
+After federated login, you can retrieve the session using the `Auth.fetchAuthSession` API.
+
+### Token Refresh
+
+
+
+Automatic authentication token refresh is NOT supported when federated.
+
+
+
+By default, Amplify will **NOT** automatically refresh the tokens from the federated providers. You will need to handle the token refresh logic and provide the new token to the `federateToIdentityPool` API.
+
+### Clear Session
+
+You can clear the federated session using the `clearFederationToIdentityPool` API.
+
+```dart
+final cognitoPlugin =
+ Amplify.Auth.getPlugin(AmplifyAuthCognito.pluginKey);
+await cognitoPlugin.clearFederationToIdentityPool();
+```
+
+
+
+`clearFederationToIdentityPool` will only clear the session from the local cache; the developer needs to handle signing out from the federated identity provider.
+
+
+
+### Provide Custom Identity ID
+
+You can provide a custom identity ID to the `federateToIdentityPool` API. This is useful when you want to use the same identity ID across multiple sessions.
+
+```dart
+final cognitoPlugin =
+ Amplify.Auth.getPlugin(AmplifyAuthCognito.pluginKey);
+const googleIdToken = 'idToken';
+const identityId = 'us-west-2:b4cd4809-7ab1-42e1-b044-07dab9eaa768';
+final session = await cognitoPlugin.federateToIdentityPool(
+ token: googleIdToken,
+ provider: AuthProvider.google,
+ options: FederateToIdentityPoolOptions(
+ developerProvidedIdentityId: identityId,
+ ),
+);
+```
+
+
+## Subscribing Events
+
+You can take specific actions when users sign-in or sign-out by subscribing to authentication events in your app. Please see our [Hub Module Developer Guide](/[platform]/build-a-backend/auth/connect-your-frontend/listen-to-auth-events/) for more information.
+
+## Identity Pool Federation
+
+Imagine that you are creating a mobile app that accesses AWS resources, such as a game that runs on a mobile device and stores player and score information using Amazon S3 and DynamoDB.
+
+When you write such an app, you make requests to AWS services that must be signed with an AWS access key. However, we strongly recommend that you do not embed or distribute long-term AWS credentials with apps that a user downloads to a device, even in an encrypted store. Instead, build your app so that it requests temporary AWS security credentials dynamically when needed using web identity federation. The supplied temporary credentials map to an AWS role that has only the permissions needed to perform the tasks required by the mobile app.
+
+With web identity federation, you don't need to create custom sign-in code or manage your own user identities. Instead, users of your app can sign in using a well-known external identity provider (IdP), such as Login with Amazon, Facebook, Google, or any other OpenID Connect (OIDC)-compatible IdP. They can receive an authentication token, and then exchange that token for temporary security credentials in AWS that map to an IAM role with permissions to use the resources in your AWS account. Using an IdP helps you keep your AWS account secure because you don't have to embed and distribute long-term security credentials with your application.
+
+You can use `federateToIdentityPool` to get AWS credentials directly from Cognito Federated Identities and not use User Pool federation. If you logged in with `Auth.signIn` you **cannot** call `federateToIdentityPool` as Amplify will perform this federation automatically for you in the background. In general, you should only call `Auth.federatedSignIn()` when using OAuth flows.
+
+You can use the escape hatch API `federateToIdentityPool` with a valid token from other social providers.
+
+#### [Java]
+
+```java
+if (Amplify.Auth.getPlugin("awsCognitoAuthPlugin") instanceof AWSCognitoAuthPlugin) {
+ AWSCognitoAuthPlugin plugin = (AWSCognitoAuthPlugin) Amplify.Auth.getPlugin("awsCognitoAuthPlugin");
+ plugin.federateToIdentityPool(
+ "YOUR_TOKEN",
+ AuthProvider.facebook(),
+ result -> {
+ Log.i("AuthQuickstart", "Successful federation to Identity Pool.");
+ // use result.getCredentials()
+ },
+ e -> {
+ Log.e("AuthQuickstart", "Failed to federate to Identity Pool.", e)
+ }
+ );
+}
+```
+
+#### [Kotlin - Callbacks]
+
+```kotlin
+(Amplify.Auth.getPlugin("awsCognitoAuthPlugin") as? AWSCognitoAuthPlugin)?.let { plugin ->
+ plugin.federateToIdentityPool(
+ "YOUR_TOKEN",
+ AuthProvider.facebook(),
+ {
+ Log.i("AuthQuickstart", "Successful federation to Identity Pool.")
+ // use "it.credentials"
+ },
+ {
+ Log.e("AuthQuickstart", "Failed to federate to Identity Pool.", it)
+ }
+ )
+}
+```
+
+
+Note that when federated, APIs such as Auth.getCurrentUser will throw an error as the user is not authenticated with User Pools.
+
+
+### Retrieve Session
+
+After federated login, you can retrieve the session using the `Auth.fetchAuthSession` API.
+
+### Token Refresh
+
+
+Automatic authentication token refresh is NOT supported when federated.
+
+
+By default, Amplify will **NOT** automatically refresh the tokens from the federated providers. You will need to handle the token refresh logic and provide the new token to the `federateToIdentityPool` API.
+
+### Clear Session
+
+You can clear the federated session using the `clearFederationToIdentityPool` API.
+
+#### [Java]
+
+```java
+if (Amplify.Auth.getPlugin("awsCognitoAuthPlugin") instanceof AWSCognitoAuthPlugin) {
+ AWSCognitoAuthPlugin plugin = (AWSCognitoAuthPlugin) Amplify.Auth.getPlugin("awsCognitoAuthPlugin");
+ plugin.clearFederationToIdentityPool(
+ () -> Log.i("AuthQuickstart", "Federation cleared successfully."),
+ e -> Log.e("AuthQuickstart", "Failed to clear federation.", e)
+ );
+}
+```
+
+#### [Kotlin - Callbacks]
+
+```kotlin
+(Amplify.Auth.getPlugin("awsCognitoAuthPlugin") as? AWSCognitoAuthPlugin)?.let { plugin ->
+ plugin.clearFederationToIdentityPool(
+ { Log.i("AuthQuickstart", "Federation cleared successfully.") },
+ { Log.e("AuthQuickstart", "Failed to clear federation.", it) }
+ )
+}
+```
+
+
+`clearFederationToIdentityPool` will only clear the session from the local cache, the developer needs to handle signing out from the federated provider.
+
+
+### Provide Custom Identity Id
+
+You can provide a custom identity id to the `federateToIdentityPool` API. This is useful when you want to use the same identity id across multiple devices.
+
+#### [Java]
+
+```java
+FederateToIdentityPoolOptions options = FederateToIdentityPoolOptions.builder()
+ .developerProvidedIdentityId("YOUR_CUSTOM_IDENTITY_ID")
+ .build();
+
+if (Amplify.Auth.getPlugin("awsCognitoAuthPlugin") instanceof AWSCognitoAuthPlugin) {
+ AWSCognitoAuthPlugin plugin = (AWSCognitoAuthPlugin) Amplify.Auth.getPlugin("awsCognitoAuthPlugin");
+ plugin.federateToIdentityPool(
+ "YOUR_TOKEN",
+ AuthProvider.facebook(),
+ options,
+ result -> {
+ Log.i("AuthQuickstart", "Successful federation to Identity Pool.");
+ // use result.getCredentials()
+ },
+ e -> {
+ Log.e("AuthQuickstart", "Failed to federate to Identity Pool.", e)
+ }
+ );
+}
+```
+
+#### [Kotlin - Callbacks]
+
+```kotlin
+val options = FederateToIdentityPoolOptions.builder()
+ .developerProvidedIdentityId("YOUR_CUSTOM_IDENTITY_ID")
+ .build()
+
+(Amplify.Auth.getPlugin("awsCognitoAuthPlugin") as? AWSCognitoAuthPlugin)?.let { plugin ->
+ plugin.federateToIdentityPool(
+ "YOUR_TOKEN",
+ AuthProvider.facebook(),
+ options,
+ {
+ Log.i("AuthQuickstart", "Successful federation to Identity Pool.")
+ // use "it.credentials"
+ },
+ {
+ Log.e("AuthQuickstart", "Failed to federate to Identity Pool.", it)
+ }
+ )
+}
+```
+
+
+
+## Subscribing Events
+
+You can take specific actions when users sign-in or sign-out by subscribing authentication events in your app. Please see our [Hub Module Developer Guide](/[platform]/build-a-backend/auth/connect-your-frontend/listen-to-auth-events/) for more information.
+
+## Identity Pool Federation
+
+Imagine that you are creating a mobile app that accesses AWS resources, such as a game that runs on a mobile device and stores player and score information using Amazon S3 and DynamoDB.
+
+When you write such an app, you make requests to AWS services that must be signed with an AWS access key. However, we strongly recommend that you do not embed or distribute long-term AWS credentials with apps that a user downloads to a device, even in an encrypted store. Instead, build your app so that it requests temporary AWS security credentials dynamically when needed using web identity federation. The supplied temporary credentials map to an AWS role that has only the permissions needed to perform the tasks required by the mobile app.
+
+With web identity federation, you don't need to create custom sign-in code or manage your own user identities. Instead, users of your app can sign in using a well-known external identity provider (IdP), such as Login with Amazon, Facebook, Google, or any other OpenID Connect (OIDC)-compatible IdP. They can receive an authentication token, and then exchange that token for temporary security credentials in AWS that map to an IAM role with permissions to use the resources in your AWS account. Using an IdP helps you keep your AWS account secure, because you don't have to embed and distribute long-term security credentials with your application.
+
+You can use `federateToIdentityPool` to get AWS credentials directly from Cognito Federated Identities and not use User Pool federation. If you have logged in with `Auth.signIn` you **can not** call `federateToIdentityPool` as Amplify will perform this federation automatically for you in the background. In general, you should only call `Auth.federateToIdentityPool` when using OAuth flows.
+
+You can use the escape hatch API `federateToIdentityPool` with a valid token from other social providers.
+
+```swift
+func federateToIdentityPools() async throws {
+ guard let authCognitoPlugin = try Amplify.Auth.getPlugin(
+ for: "awsCognitoAuthPlugin") as? AWSCognitoAuthPlugin else {
+ fatalError("Unable to get the Auth plugin")
+ }
+ do {
+ let result = try await authCognitoPlugin.federateToIdentityPool(
+ withProviderToken: "YOUR_TOKEN", for: .facebook)
+ print("Federation successful with result: \(result)")
+ } catch {
+ print("Failed to federate to identity pools with error: \(error)")
+ }
+}
+```
+
+
+Note that when federated, API's such as Auth.getCurrentUser() will throw an error as the user is not authenticated with User Pools.
+
+
+### Retrieve Session
+
+After federated login, you can retrieve session using the `Auth.fetchAuthSession` API.
+
+### Token Refresh
+
+
+NOTE: Automatic authentication token refresh is NOT supported when federated.
+
+
+By default, Amplify will **NOT** automatically refresh the tokens from the federated providers. You will need to handle the token refresh logic and provide the new token to the `federateToIdentityPool` API.
+
+### Clear Session
+
+You can clear the federated session using the `clearFederationToIdentityPool` API.
+
+```swift
+func clearFederationToIdentityPools() async throws {
+ guard let authCognitoPlugin = try Amplify.Auth.getPlugin(
+ for: "awsCognitoAuthPlugin") as? AWSCognitoAuthPlugin else {
+ fatalError("Unable to get the Auth plugin")
+ }
+ do {
+ try await authCognitoPlugin.clearFederationToIdentityPool()
+ print("Federation cleared successfully")
+ } catch {
+ print("Clear federation failed with error: \(error)")
+ }
+}
+```
+
+
+clearFederationToIdentityPool will only clear the session from local cache, developer need to handle signing out from the federated provider.
+
+
+### Provide Custom Identity Id
+
+You can provide a custom identity id to the `federateToIdentityPool` API. This is useful when you want to use the same identity id across multiple devices.
+
+```swift
+func federateToIdentityPoolsUsingCustomIdentityId() async throws {
+ guard let authCognitoPlugin = try Amplify.Auth.getPlugin(
+ for: "awsCognitoAuthPlugin") as? AWSCognitoAuthPlugin else {
+ fatalError("Unable to get the Auth plugin")
+ }
+ do {
+ let identityId = "YOUR_CUSTOM_IDENTITY_ID"
+ let result = try await authCognitoPlugin.federateToIdentityPool(
+ withProviderToken: "YOUR_TOKEN",
+ for: .facebook,
+ options: .init(developerProvidedIdentityID: identityId))
+ print("Federation successful with result: \(result)")
+ } catch {
+ print("Failed to federate to identity pools with error: \(error)")
+ }
+}
+```
+
+## Keychain Sharing
+
+### Migrating to a Shared Keychain
+
+To use a shared keychain:
+
+1. In Xcode, go to Project Settings β Your Target β Signing & Capabilities
+2. Select +Capability
+3. Add Keychain Sharing capability
+4. Add a keychain group
+5. Repeat for all apps for which you want to share auth state, adding the same keychain group for all of them
+
+To move to the shared keychain using this new keychain access group, specify the `accessGroup` parameter when instantiating the `AWSCognitoAuthPlugin`. If a user is currently signed in, they will be signed out when first using the access group:
+
+```swift
+let accessGroup = AccessGroup(name: "\(teamID)com.example.sharedItems")
+let secureStoragePreferences = AWSCognitoSecureStoragePreferences(
+ accessGroup: accessGroup)
+try Amplify.add(
+ plugin: AWSCognitoAuthPlugin(
+ secureStoragePreferences: secureStoragePreferences))
+try Amplify.configure()
+```
+
+If you would prefer the user session to be migrated (which will allow the user to continue to be signed in), then specify the `migrateKeychainItemsOfUserSession` boolean in the AccessGroup to be true like so:
+
+```swift
+let accessGroup = AccessGroup(
+ name: "\(teamID)com.example.sharedItems",
+ migrateKeychainItemsOfUserSession: true)
+let secureStoragePreferences = AWSCognitoSecureStoragePreferences(
+ accessGroup: accessGroup)
+try Amplify.add(
+ plugin: AWSCognitoAuthPlugin(
+ secureStoragePreferences: secureStoragePreferences))
+try Amplify.configure()
+```
+
+Sign in a user with any sign-in method within one app that uses this access group. After reloading another app that uses this access group, the user will be signed in. Likewise, signing out of one app will sign out the other app after reloading it.
+
+### Migrating to another Shared Keychain
+
+To move to a different access group, update the name parameter of the AccessGroup to be the new access group. Set `migrateKeychainItemsOfUserSession` to `true` to migrate an existing user session under the previously used access group.
+
+### Migrating from a Shared Keychain
+
+If you'd like to stop sharing state between this app and other apps, you can set the access group to be `AccessGroup.none` or `AccessGroup.none(migrateKeychainItemsOfUserSession: true)` if you'd like the session to be migrated.
+
+### Retrieving Team ID
+
+First, ensure your Info.plist has the `AppIdentifierPrefix` key:
+
+```xml title="Info.plist"
+
+
+
+
+ AppIdentifierPrefix
+ $(AppIdentifierPrefix)
+
+
+```
+
+Then, you can retrieve the team ID from your Info.plist:
+
+```swift
+guard let teamID = Bundle.main.infoDictionary?["AppIdentifierPrefix"] as? String else {
+ fatalError("AppIdentifierPrefix key not found in Info.plist")
+}
+```
+
+
+## Subscribing to Events
+
+You can take specific actions when users sign-in or sign-out by subscribing to authentication events in your app. Please see our [Hub Module Developer Guide](/[platform]/build-a-backend/auth/connect-your-frontend/listen-to-auth-events/) for more information.
+
+## Identity Pool Federation
+
+You can alternatively create your own custom credentials provider to get AWS credentials directly from Cognito Federated Identities and not use User Pool federation. You must supply the custom credentials provider to Amplify via the `Amplify.configure` method call. Below, you can see sample code of how such a custom provider can be built to achieve the use case.
+
+```js
+import { Amplify } from 'aws-amplify';
+import {
+ fetchAuthSession,
+ CredentialsAndIdentityIdProvider,
+ CredentialsAndIdentityId,
+ GetCredentialsOptions,
+ AuthTokens,
+} from 'aws-amplify/auth';
+
+// Note: This example requires installing `@aws-sdk/client-cognito-identity` to obtain Cognito credentials
+// npm add @aws-sdk/client-cognito-identity
+import { CognitoIdentity } from '@aws-sdk/client-cognito-identity';
+
+// You can make use of the sdk to get identityId and credentials
+const cognitoidentity = new CognitoIdentity({
+ region: '',
+});
+
+// Note: The custom provider class must implement CredentialsAndIdentityIdProvider
+class CustomCredentialsProvider implements CredentialsAndIdentityIdProvider {
+
+ // Example class member that holds the login information
+ federatedLogin?: {
+ domain: string,
+ token: string
+ };
+
+ // Custom method to load the federated login information
+ loadFederatedLogin(login?: typeof this.federatedLogin) {
+ // You may also persist this by caching if needed
+ this.federatedLogin = login;
+ }
+
+ async getCredentialsAndIdentityId(
+ getCredentialsOptions: GetCredentialsOptions
+ ): Promise {
+ try {
+
+ // You can add in some validation to check if the token is available before proceeding
+ // You can also refresh the token if it's expired before proceeding
+
+ const getIdResult = await cognitoidentity.getId({
+ // Get the identityPoolId from config
+ IdentityPoolId: '',
+ Logins: { [this.federatedLogin.domain]: this.federatedLogin.token },
+ });
+
+ const cognitoCredentialsResult = await cognitoidentity.getCredentialsForIdentity({
+ IdentityId: getIdResult.IdentityId,
+ Logins: { [this.federatedLogin.domain]: this.federatedLogin.token },
+ });
+
+ const credentials: CredentialsAndIdentityId = {
+ credentials: {
+ accessKeyId: cognitoCredentialsResult.Credentials?.AccessKeyId,
+ secretAccessKey: cognitoCredentialsResult.Credentials?.SecretKey,
+ sessionToken: cognitoCredentialsResult.Credentials?.SessionToken,
+ expiration: cognitoCredentialsResult.Credentials?.Expiration,
+ },
+ identityId: getIdResult.IdentityId,
+ };
+ return credentials;
+ } catch (e) {
+ console.log('Error getting credentials: ', e);
+ }
+ }
+ // Implement this to clear any cached credentials and identityId. This can be called when signing out of the federation service.
+ clearCredentialsAndIdentityId(): void {}
+}
+
+// Create an instance of your custom provider
+const customCredentialsProvider = new CustomCredentialsProvider();
+Amplify.configure(awsconfig, {
+ Auth: {
+ // Supply the custom credentials provider to Amplify
+ credentialsProvider: customCredentialsProvider
+ },
+});
+
+```
+
+Now that the custom credentials provider is built and supplied to `Amplify.configure`, let's look at how you can use the custom credentials provider to finish federation into Cognito identity pool.
+
+
+### Facebook Sign-in (React Native - Expo)
+
+```javascript
+import Expo from 'expo';
+import React from 'react';
+import { fetchAuthSession } from 'aws-amplify/auth';
+
+const App = () => {
+ const signIn = async () => {
+ const { type, token, expires } =
+ await Expo.Facebook.logInWithReadPermissionsAsync(
+ 'YOUR_FACEBOOK_APP_ID',
+ {
+ permissions: ['public_profile']
+ }
+ );
+ if (type === 'success') {
+ // sign in with federated identity
+ try {
+ customCredentialsProvider.loadFederatedLogin({
+ domain: 'graph.facebook.com',
+ token: token
+ });
+ const fetchSessionResult = await fetchAuthSession(); // will return the credentials
+ console.log('fetchSessionResult: ', fetchSessionResult);
+ } catch (err) {
+ console.log(err);
+ }
+ }
+ };
+
+ // ...
+
+ return (
+
+
+
+ );
+};
+```
+
+
+
+### Facebook sign-in (React)
+
+```js
+import React, { useEffect } from 'react';
+import {
+ fetchAuthSession,
+} from 'aws-amplify/auth';
+
+// To federated sign in from Facebook
+const SignInWithFacebook = () => {
+
+ useEffect(() => {
+ if (!window.FB) createScript();
+ }, [])
+
+ const signIn = () => {
+ const fb = window.FB;
+ fb.getLoginStatus(response => {
+ if (response.status === 'connected') {
+ getAWSCredentials(response.authResponse);
+ } else {
+ fb.login(
+ response => {
+ if (!response || !response.authResponse) {
+ return;
+ }
+ customCredentialsProvider.loadFederatedLogin({
+ domain: 'graph.facebook.com',
+ token: response.authResponse.accessToken,
+ });
+ const fetchSessionResult = await fetchAuthSession(); // will return the credentials
+ console.log('fetchSessionResult: ', fetchSessionResult);
+ },
+ {
+ // the authorized scopes
+ scope: 'public_profile,email'
+ }
+ );
+ }
+ });
+ }
+
+ const createScript = () => {
+ // load the sdk
+ window.fbAsyncInit = fbAsyncInit;
+ const script = document.createElement('script');
+ script.src = 'https://connect.facebook.net/en_US/sdk.js';
+ script.async = true;
+ script.onload = initFB;
+ document.body.appendChild(script);
+ }
+
+ const initFB = () => {
+ const fb = window.FB;
+ console.log('FB SDK initialized');
+ }
+
+ const fbAsyncInit = () => {
+ // init the fb sdk client
+ const fb = window.FB;
+ fb.init({
+ appId : 'your_facebook_app_id',
+ cookie : true,
+ xfbml : true,
+ version : 'v2.11'
+ });
+ }
+
+ return (
+
+ );
+}
+```
+
+### Federate with Auth0
+
+You can use `Auth0` as one of the providers of your Cognito Identity Pool. This will allow users authenticated via Auth0 have access to your AWS resources.
+
+Step 1. [Follow Auth0 integration instructions for Cognito Federated Identity Pools](https://auth0.com/docs/customize/integrations/aws/amazon-cognito)
+
+Step 2. Login with `Auth0`, then use the id token returned to get AWS credentials from `Cognito Federated Identity Pools` using custom credentials provider you created at the start:
+
+```js
+import { fetchAuthSession } from 'aws-amplify/auth';
+
+const { idToken, domain, name, email, phoneNumber } = getFromAuth0(); // get the user credentials and info from auth0
+
+async function getCognitoCredentials() {
+ try {
+ customCredentialsProvider.loadFederatedLogin({
+ domain,
+ token: idToken
+ });
+ const fetchSessionResult = await fetchAuthSession(); // will return the credentials
+ console.log('fetchSessionResult: ', fetchSessionResult);
+ } catch (err) {
+ console.log(err);
+ }
+}
+```
+
+
+## Lambda Triggers
+
+With the triggers property of defineAuth and defineFunction from the new Functions implementation, you can define [Lambda Triggers](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-identity-pools-working-with-aws-lambda-triggers.html) for your Cognito User Pool. These enable you to add custom functionality to your registration and authentication flows. [Check out a preSignUp hook example here.](/[platform]/build-a-backend/functions/examples/email-domain-filtering/)
+
+### Pre Authentication and Pre Sign-up Lambda triggers
+
+If you have a Pre Authentication Lambda trigger enabled, you can pass `clientMetadata` as an option for `signIn`. This metadata can be used to implement additional validations around authentication.
+
+```ts
+import { signIn } from 'aws-amplify/auth';
+
+async function handleSignIn(username: string, password: string) {
+ try {
+ await signIn({
+ username,
+ password,
+ options: {
+ clientMetadata: {} // Optional, an object of key-value pairs which can contain any key and will be passed to your Lambda trigger as-is.
+ }
+ });
+ } catch (err) {
+ console.log(err);
+ }
+}
+```
+
+### Passing metadata to other Lambda triggers
+
+Many Cognito Lambda Triggers also accept unsanitized key/value pairs in the form of a `clientMetadata` attribute. This attribute can be specified for various Auth APIs which result in Cognito Lambda Trigger execution.
+
+These APIs include:
+
+- `signIn`
+- `signUp`
+- `confirmSignIn`
+- `confirmSignUp`
+- `resetPassword`
+- `confirmResetPassword`
+- `resendSignUpCode`
+- `updateUserAttributes`
+- `fetchAuthSession`
+
+Additionally, you can configure a `ClientMetadataProvider` which passes the `clientMetadata` to internal `fetchAuthSession` calls:
+
+```javascript
+// Set global clientMetadata (affects all token refreshes)
+import { cognitoUserPoolsTokenProvider } from 'aws-amplify/auth/cognito';
+
+const clientMetadataProvider = () => Promise.resolve({
+ 'app-version': '1.0.0',
+ 'device-type': 'mobile'
+});
+
+cognitoUserPoolsTokenProvider.setClientMetadataProvider(clientMetadataProvider);
+```
+
+Please note that some of triggers which accept a `validationData` attribute will use `clientMetadata` as the value for `validationData`. Exercise caution with using `clientMetadata` when you are relying on `validationData`.
+
+## Working with AWS service objects
+
+You can use AWS _Service Interface Objects_ to work with AWS Services in authenticated State. You can call methods on any AWS Service interface object by passing your credentials from Amplify `fetchAuthSession` to the service call constructor:
+
+```javascript
+import { fetchAuthSession } from 'aws-amplify/auth';
+import Route53 from 'aws-sdk/clients/route53';
+
+async function changeResourceRecordSets() {
+ try {
+ const { credentials } = await fetchAuthSession();
+
+ const route53 = new Route53({
+ apiVersion: '2013-04-01',
+ credentials
+ });
+
+ // more code working with route53 object
+ //route53.changeResourceRecordSets();
+ } catch (err) {
+ console.log(err);
+ }
+}
+```
+
+> **Warning:** Note: To work with Service Interface Objects, your Amazon Cognito users' [IAM role](https://docs.aws.amazon.com/cognito/latest/developerguide/iam-roles.html) must have the appropriate permissions to call the requested services.
+
+## Custom Token providers
+
+Create a custom Auth token provider for situations where you would like provide your own tokens for a service. For example, using OIDC Auth with AppSync. You must supply the token provider to Amplify via the `Amplify.configure` method call. Below, you can see sample code of how such a custom provider can be built to achieve the use case.
+
+```javascript
+import { Amplify } from 'aws-amplify';
+import { TokenProvider, decodeJWT } from 'aws-amplify/auth';
+
+// ...
+
+const myTokenProvider: TokenProvider = {
+ async getTokens({ forceRefresh } = {}) {
+ if (forceRefresh) {
+ // try to obtain new tokens if possible
+ }
+
+ const accessTokenString = '';
+ const idTokenString = '';
+
+ return {
+ accessToken: decodeJWT(accessTokenString),
+ idToken: decodeJWT(idTokenString),
+ };
+ },
+};
+
+Amplify.configure(awsconfig, {
+ Auth: {
+ tokenProvider: myTokenProvider
+ }
+});
+
+```
+## API reference
+
+For the complete API documentation for Authentication module, visit our [API Reference](https://aws-amplify.github.io/amplify-js/api/modules/aws_amplify.auth.html)
+
+
+---
+
+---
+title: "Use existing Cognito resources"
+section: "build-a-backend/auth"
+platforms: ["android", "angular", "flutter", "javascript", "nextjs", "react", "react-native", "swift", "vue"]
+gen: 2
+last-updated: "2025-02-19T23:36:30.000Z"
+url: "https://docs.amplify.aws/react/build-a-backend/auth/use-existing-cognito-resources/"
+---
+
+Amplify Auth can be configured to use an existing Amazon Cognito user pool and identity pool. If you are in a team setting or part of a company that has previously created auth resources, you can [configure the client library directly](#use-auth-resources-without-an-amplify-backend), or maintain references with [AWS Cloud Development Kit (AWS CDK)](https://aws.amazon.com/cdk/) in your Amplify backend.
+
+> **Info:** **Note:** when using existing auth resources, it may be necessary to add additional policies or permissions for your authenticated and unauthenticated IAM roles. These changes must be performed manually.
+
+## Use auth resources without an Amplify backend
+
+
+You can use existing resources without an Amplify backend by configuring the client library directly.
+
+```ts title="src/main.ts"
+import { Amplify } from "aws-amplify"
+
+Amplify.configure({
+ Auth: {
+ Cognito: {
+ userPoolId: "",
+ userPoolClientId: "",
+ identityPoolId: "",
+ loginWith: {
+ email: true,
+ },
+ signUpVerificationMethod: "code",
+ userAttributes: {
+ email: {
+ required: true,
+ },
+ },
+ allowGuestAccess: true,
+ passwordFormat: {
+ minLength: 8,
+ requireLowercase: true,
+ requireUppercase: true,
+ requireNumbers: true,
+ requireSpecialCharacters: true,
+ },
+ },
+ },
+})
+```
+
+
+Configuring the mobile client libraries directly is not supported, however you can manually create `amplify_outputs.json` with the following schema:
+
+> **Info:** **Note:** it is strongly recommended to use backend outputs to generate this file for each sandbox or branch deployment
+
+```json title="amplify_outputs.json"
+{
+ "version": "1",
+ "auth": {
+ "aws_region": "",
+ "user_pool_id": "",
+ "user_pool_client_id": "",
+ "identity_pool_id": "",
+ "username_attributes": ["email"],
+ "standard_required_attributes": ["email"],
+ "user_verification_types": ["email"],
+ "unauthenticated_identities_enabled": true,
+ "password_policy": {
+ "min_length": 8,
+ "require_lowercase": true,
+ "require_uppercase": true,
+ "require_numbers": true,
+ "require_symbols": true
+ }
+ }
+}
+```
+
+
+## Use auth resources with an Amplify backend
+
+> **Warning:** Amplify cannot modify the configuration of your referenced resources and only captures the resource configuration at the time of reference, any subsequent changes made to the referenced resources will not be automatically reflected in your Amplify backend.
+
+If you have created Amazon Cognito resources outside of the context of your Amplify app such as creating resources through the AWS Console or consuming resources created by a separate team, you can use `referenceAuth` to reference the existing resources. It requires a user pool, a user pool client, identity pool, and an authenticated & unauthenticated IAM role configured on your identity pool.
+
+```ts title="amplify/auth/resource.ts"
+import { referenceAuth } from '@aws-amplify/backend';
+
+export const auth = referenceAuth({
+ userPoolId: 'us-east-1_xxxx',
+ identityPoolId: 'us-east-1:b57b7c3b-9c95-43e4-9266-xxxx',
+ authRoleArn: 'arn:aws:iam::xxxx:role/amplify-xxxx-mai-amplifyAuthauthenticatedU-xxxx',
+ unauthRoleArn: 'arn:aws:iam::xxxx:role/amplify-xxxx-mai-amplifyAuthunauthenticate-xxxx',
+ userPoolClientId: 'xxxx',
+});
+```
+
+> **Info:** IAM policies specific to your Amplify application will be appended to your authenticated and unauthenticated roles, and applications using the referenced resource will be able to create users in the Cognito user pool and identities in the Cognito identity pool.
+
+You can also use the [`access` property](/[platform]/build-a-backend/auth/grant-access-to-auth-resources/) to grant permissions to your auth resource from other Amplify backend resources. For example, if you have a function that needs to retrieve details about a user:
+
+```ts title="amplify/auth/resource.ts"
+import { referenceAuth } from '@aws-amplify/backend';
+import { getUser } from "../functions/get-user/resource";
+
+export const auth = referenceAuth({
+ userPoolId: 'us-east-1_xxxx',
+ identityPoolId: 'us-east-1:b57b7c3b-9c95-43e4-9266-xxxx',
+ authRoleArn: 'arn:aws:iam::xxxx:role/amplify-xxxx-mai-amplifyAuthauthenticatedU-xxxx',
+ unauthRoleArn: 'arn:aws:iam::xxxx:role/amplify-xxxx-mai-amplifyAuthunauthenticate-xxxx',
+ userPoolClientId: 'xxxx',
+ access: (allow) => [
+ allow.resource(getUser).to(["getUser"]),
+ ],
+});
+```
+
+Additionally, you can also use the `groups` property to reference groups in your user pool. This is useful if you want to work with groups in your application and provide access to resources such as storage based on group membership.
+
+```ts title="amplify/auth/resource.ts"
+import { referenceAuth } from '@aws-amplify/backend';
+import { getUser } from "../functions/get-user/resource";
+
+export const auth = referenceAuth({
+ userPoolId: 'us-east-1_xxxx',
+ identityPoolId: 'us-east-1:b57b7c3b-9c95-43e4-9266-xxxx',
+ authRoleArn: 'arn:aws:iam::xxxx:role/amplify-xxxx-mai-amplifyAuthauthenticatedU-xxxx',
+ unauthRoleArn: 'arn:aws:iam::xxxx:role/amplify-xxxx-mai-amplifyAuthunauthenticate-xxxx',
+ userPoolClientId: 'xxxx',
+ groups: {
+ admin: "arn:aws:iam::xxxx:role/amplify-xxxx-mai-amplifyAuthadminGroupRole-xxxx",
+ },
+});
+```
+
+In a team setting you may want to reference a different set of auth resources depending on the deployment context. For instance if you have a `staging` branch that should reuse resources from a separate "staging" environment compared to a `production` branch that should reuse resources from the separate "production" environment. In this case we recommend using environment variables.
+
+```ts title="amplify/auth/resource.ts"
+import { referenceAuth } from '@aws-amplify/backend';
+
+export const auth = referenceAuth({
+ userPoolId: process.env.MY_USER_POOL_ID,
+ identityPoolId: process.env.MY_IDENTITY_POOL_ID,
+ authRoleArn: process.env.MY_AUTH_ROLE_ARN,
+ unauthRoleArn: process.env.MY_UNAUTH_ROLE_ARN,
+ userPoolClientId: process.env.MY_USER_POOL_CLIENT_ID,
+});
+```
+
+Environment variables must be configured separately on your machine for sandbox deployments and Amplify console for branch deployments.
+
+## Next steps
+
+- [Learn how to connect your frontend](/[platform]/build-a-backend/auth/connect-your-frontend/)
+
+---
+
+---
+title: "Use AWS SDK"
+section: "build-a-backend/auth"
+platforms: ["swift", "android"]
+gen: 2
+last-updated: "2024-09-24T23:57:23.000Z"
+url: "https://docs.amplify.aws/react/build-a-backend/auth/use-aws-sdk/"
+---
+
+For advanced use cases where Amplify does not provide the functionality, you can retrieve an escape hatch to access the underlying Amazon Cognito client.
+
+
+The escape hatch provides access to the underlying `AWSCognitoIdentityProvider` instance. Import the necessary types:
+
+```swift
+import AWSCognitoAuthPlugin
+import AWSCognitoIdentityProvider
+```
+
+Then retrieve the escape hatch with this code:
+
+```swift
+func getEscapeHatch() {
+ let client: CognitoIdentityProviderClient
+
+ // Get the instance of AWSCognitoAuthPlugin
+ let plugin = try? Amplify.Auth.getPlugin(for: "awsCognitoAuthPlugin") as? AWSCognitoAuthPlugin
+
+ // Get the instance of CognitoIdentityProviderClient
+ if case .userPoolAndIdentityPool(let userPoolClient, _) = plugin?.getEscapeHatch() {
+ client = userPoolClient
+ } else if case .userPool(let userPoolClient) = plugin?.getEscapeHatch() {
+ client = userPoolClient
+ } else {
+ fatalError("No user pool configuration found")
+ }
+ print("Fetched escape hatch - \(String(describing: client))")
+}
+```
+
+
+
+You can access the underlying `CognitoIdentityProviderClient` and `CognitoIdentityClient` as shown below
+
+```kotlin
+implementation "aws.sdk.kotlin:cognitoidentityprovider:1.0.44"
+implementation "aws.sdk.kotlin:cognitoidentity:1.0.44"
+```
+
+#### [Kotlin]
+
+```kotlin
+suspend fun resendCodeUsingEscapeHatch() {
+ // Get the instance of AWSCognitoAuthPlugin
+ val cognitoAuthPlugin = Amplify.Auth.getPlugin("awsCognitoAuthPlugin")
+ val cognitoAuthService = cognitoAuthPlugin.escapeHatch as AWSCognitoAuthService
+
+ // Get the instance of CognitoIdentityProviderClient
+ val cognitoIdentityProviderClient = cognitoAuthService.cognitoIdentityProviderClient
+ val request = ResendConfirmationCodeRequest {
+ clientId = "xxxxxxxxxxxxxxxx"
+ username = "user1"
+ }
+ val response = cognitoIdentityProviderClient?.resendConfirmationCode(request)
+}
+```
+
+#### [Java]
+
+
+
+[Learn more about consuming Kotlin clients from Java using either a blocking interface or an equivalent async interface based on futures](https://github.com/awslabs/smithy-kotlin/blob/main/docs/design/kotlin-smithy-sdk.md#java-interop).
+
+
+
+```java
+// Get the instance of AWSCognitoAuthPlugin
+AWSCognitoAuthPlugin cognitoAuthPlugin = (AWSCognitoAuthPlugin) Amplify.Auth.getPlugin("awsCognitoAuthPlugin");
+
+// Get the instance of CognitoIdentityProviderClient
+CognitoIdentityProviderClient client = cognitoAuthPlugin.getEscapeHatch().getCognitoIdentityProviderClient();
+ResendConfirmationCodeRequest request = ResendConfirmationCodeRequest.Companion.invoke(dslBuilder -> {
+ dslBuilder.setClientId("xxxxxxxxxxxxxxxx");
+ dslBuilder.setUsername("user1");
+ return null;
+});
+
+assert client != null;
+client.resendConfirmationCode(request, new Continuation() {
+ @NonNull
+ @Override
+ public CoroutineContext getContext() {
+ return GlobalScope.INSTANCE.getCoroutineContext();
+ }
+
+ @Override
+ public void resumeWith(@NonNull Object resultOrException) {
+ Log.i(TAG, "Result: " + resultOrException);
+ }
+});
+```
+
+
+
+---
+
+---
+title: "API References"
+section: "build-a-backend/auth"
+platforms: ["angular", "javascript", "nextjs", "react", "react-native", "vue"]
+gen: 2
+last-updated: ""
+url: "https://docs.amplify.aws/react/build-a-backend/auth/reference/"
+---
+
+
+
+---
+
+---
+title: "Data"
+section: "build-a-backend"
+platforms: ["android", "angular", "flutter", "javascript", "nextjs", "react", "react-native", "swift", "vue"]
+gen: 2
+last-updated: "2024-02-21T20:06:17.000Z"
+url: "https://docs.amplify.aws/react/build-a-backend/data/"
+---
+
+
+
+---
+
+---
+title: "Set up Amplify Data"
+section: "build-a-backend/data"
+platforms: ["android", "angular", "flutter", "javascript", "nextjs", "react", "react-native", "swift", "vue"]
+gen: 2
+last-updated: "2025-11-13T16:29:27.000Z"
+url: "https://docs.amplify.aws/react/build-a-backend/data/set-up-data/"
+---
+
+In this guide, you will learn how to set up Amplify Data. This includes building a real-time API and database using TypeScript to define your data model, and securing your API with authorization rules. We will also explore using AWS Lambda to scale to custom use cases.
+
+Before you begin, you will need:
+
+- [Node.js](https://nodejs.org/) v18.16.0 or later
+- [npm](https://www.npmjs.com/) v6.14.4 or later
+- [git](https://git-scm.com/) v2.14.1 or later
+
+With Amplify Data, you can build a secure, real-time API backed by a database in minutes. After you define your data model using TypeScript, Amplify will deploy a real-time API for you. This API is powered by AWS AppSync and connected to an Amazon DynamoDB database. You can secure your API with authorization rules and scale to custom use cases with AWS Lambda.
+
+## Building your data backend
+
+If you've run `npm create amplify@latest` already, you should see an `amplify/data/resource.ts` file, which is the central location to configure your data backend. The most important element is the `schema` object, which defines your backend data models (`a.model()`) and custom queries (`a.query()`), mutations (`a.mutation()`), and subscriptions (`a.subscription()`).
+
+```ts title="amplify/data/resource.ts"
+import { a, defineData, type ClientSchema } from '@aws-amplify/backend';
+
+const schema = a.schema({
+ Todo: a.model({
+ content: a.string(),
+ isDone: a.boolean()
+ })
+ .authorization(allow => [allow.publicApiKey()])
+});
+
+// Used for code completion / highlighting when making requests from frontend
+export type Schema = ClientSchema;
+
+// defines the data resource to be deployed
+export const data = defineData({
+ schema,
+ authorizationModes: {
+ defaultAuthorizationMode: 'apiKey',
+ apiKeyAuthorizationMode: { expiresInDays: 30 }
+ }
+});
+```
+
+Every `a.model()` automatically creates the following resources in the cloud:
+
+- a DynamoDB database table to store records
+- query and mutation APIs to create, read (list/get), update, and delete records
+- `createdAt` and `updatedAt` fields that help you keep track of when each record was initially created or when it was last updated
+- real-time APIs to subscribe for create, update, and delete events of records
+
+The `allow.publicApiKey()` rule designates that anyone authenticated using an API key can create, read, update, and delete todos.
+
+To deploy these resources to your cloud sandbox, run the following CLI command in your terminal:
+
+
+```bash title="Terminal" showLineNumbers={false}
+npx ampx sandbox
+```
+
+
+
+```bash title="Terminal" showLineNumbers={false}
+npx ampx sandbox --outputs-out-dir
+```
+
+
+
+```bash title="Terminal" showLineNumbers={false}
+npx ampx sandbox --outputs-out-dir
+```
+
+
+```bash title="Terminal" showLineNumbers={false}
+npx ampx sandbox --outputs-format dart --outputs-out-dir lib
+```
+
+
+## Connect your application code to the data backend
+
+Once the cloud sandbox is up and running, it will also create an `amplify_outputs.json` file, which includes the relevant connection information to your data backend, like your API endpoint URL and API key.
+
+To connect your frontend code to your backend, you need to:
+
+1. Configure the Amplify library with the Amplify client configuration file (`amplify_outputs.json`)
+2. Generate a new API client from the Amplify library
+3. Make an API request with end-to-end type-safety
+
+
+First, install the Amplify client library to your project:
+
+```bash title="Terminal" showLineNumbers={false}
+npm add aws-amplify
+```
+
+
+
+In your app's entry point, typically **main.tsx** for React apps created using Vite, make the following edits:
+
+```tsx title="src/main.tsx"
+import { Amplify } from 'aws-amplify';
+import outputs from '../amplify_outputs.json';
+
+Amplify.configure(outputs);
+```
+
+
+
+In your app's entry point, typically **main.ts** for Vue apps created using Vite, make the following edits:
+
+```tsx title="src/main.ts"
+import { Amplify } from 'aws-amplify';
+import outputs from '../amplify_outputs.json';
+
+Amplify.configure(outputs);
+```
+
+
+
+Under Gradle Scripts, open build.gradle (Module :app), add the following lines:
+
+```kotlin title="app/build.gradle.kts"
+android {
+ compileOptions {
+ // Support for modern Java features
+ isCoreLibraryDesugaringEnabled = true
+ }
+}
+
+dependencies {
+ // Amplify API dependencies
+ // highlight-start
+ implementation("com.amplifyframework:aws-api:ANDROID_VERSION")
+ // highlight-end
+ // ... other dependencies
+ coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:ANDROID_DESUGAR_VERSION")
+}
+```
+
+Click **Sync Now** in the notification bar above the file editor to sync these dependencies.
+
+Next, configure the Amplify client library with the generated `amplify_outputs.json` file to make it aware of the backend API endpoint. *Note: verify that the **amplify_outputs.json** file is present in your **res/raw/** folder.
+
+Create a new `MyAmplifyApp` class that inherits from `Application` with the following code:
+
+> **Warning:** Before calling the `Amplify.configure` function, make sure to either download the `amplify_outputs.json` file from the console, or generate it with the following command:
+>
+> ```bash title="Terminal" showLineNumbers={false}
+npx ampx generate outputs --app-id