0% found this document useful (0 votes)
48 views103 pages

Cognito Flutter Docs Gen2

The document provides a comprehensive guide on setting up Amplify Auth using Amazon Cognito for user authentication in applications. It covers defining authentication resources, configuring user attributes, implementing multi-factor authentication (MFA), and integrating pre-built UI components for various frameworks. Additionally, it outlines the importance of security strategies and the implications of different authentication methods and configurations.

Uploaded by

Fahim Ashab
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
48 views103 pages

Cognito Flutter Docs Gen2

The document provides a comprehensive guide on setting up Amplify Auth using Amazon Cognito for user authentication in applications. It covers defining authentication resources, configuring user attributes, implementing multi-factor authentication (MFA), and integrating pre-built UI components for various frameworks. Additionally, it outlines the importance of security strategies and the implications of different authentication methods and configurations.

Uploaded by

Fahim Ashab
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 103

Set up Amplify Auth

Amplify Auth is powered by Amazon Cognito. Cognito is a robust user directory service that
handles user registration, authentication, account recovery, and other operations.

To get started with defining your authentication resource, open or create the auth resource file:

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 or an external
provider such as Google, Facebook, Amazon, or Sign in with Apple.

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.

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.
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 amplify_authenticator library:
Terminal
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
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.
Terminal
flutter pub get
Next, update your main.dart file with the following:
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<void> main() async {


try {
WidgetsFlutterBinding.ensureInitialized();
await _configureAmplify();
runApp(const MyApp());
} on AmplifyException catch (e) {
runApp(Text("Error configuring Amplify: ${e.message}"));
}
}

Future<void> _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(),
],
),
),
),
),
);
}
}
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 to adjust
colors and styling as needed.

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. 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 is a full-featured user directory service to handle user
registration, authentication, and account recovery

2. Amazon Cognito Federated Identities or Identity Pools 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, 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.

Email
By default Amplify Auth is scaffolded with email as the default method for user sign-in.
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.
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: After you create your auth resource, you cannot switch an attribute between required
and not required.

amplify/auth/resource.ts

import { defineAuth } from "@aws-amplify/backend"


export const auth = defineAuth({

loginWith: {

// this configures a required "email" attribute

email: true,

},

userAttributes: {

// specify a "birthdate" attribute

birthdate: {

mutable: true,

required: false,

},

})

Standard attributes

User attributes are defined as Cognito 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.

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. 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:

amplify/auth/resource.ts

import { defineAuth } from "@aws-amplify/backend"

export const auth = defineAuth({

loginWith: {

// this configures a required "email" attribute

email: true,

},

userAttributes: {

"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,

},

},

})

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.

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.

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.

amplify/auth/resource.ts

import { defineAuth } from '@aws-amplify/backend';

export const auth = defineAuth({

loginWith: {

email: true

},

multifactor: {

mode: 'OPTIONAL',
totp: true,

},

userAttributes: {

phoneNumber: {

required: true

});

Note: Email-based MFA is currently not supported with defineAuth. We are working towards
supporting this feature. For more information, visit the feature request in GitHub.

To take advantage of this feature with an Amplify generated backend, the underlying CDK
construct can be extended manually. See overriding Cognito User Pool multi-factor
authentication options for more information.

When MFA is REQUIRED with SMS in your backend auth resource, you will need to pass the
phone number during sign-up API call. If you are using the email or username as the primary
sign-in mechanism, you will need to pass the phone_number attribute as a user attribute.

Similarly, when MFA is REQUIRED with email as your delivery mechanism, you will need to pass
an email address during the sign-up API call. If you are using phoneNumber or username as the
primary sign-in mechanism, you will need to pass the email attribute as a user attribute.

This configuration may change depending on the combination of MFA methods enabled in your
user pool.

Understand your MFA options

When enabling MFA you will have two key decisions to make:

 MFA enforcement: As part of this setup you will determine how MFA is enforced. If you
require MFA by setting MFA 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.
Learn more

Compare TOTP, SMS, and EMAIL MFA methods

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.

Future<void> _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<MfaType> _promptUserPreference(Set<MfaType> allowedTypes) async {

// ···

Future<void> _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}');

Multi-factor authentication with SMS

If you are using the Authenticator component 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: In order to send SMS authentication codes, you must request an origination
number. Learn more about configuring your auth resource for production workloads.

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.

Future<void> signUpWithPhoneVerification(

String username,

String password,

) async {

await Amplify.Auth.signUp(

username: username,

password: password,

options: SignUpOptions(

userAttributes: <AuthUserAttributeKey, String>{

// ... if required

AuthUserAttributeKey.email: '[email protected]',

AuthUserAttributeKey.phoneNumber: '+18885551234',
},

),

);

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.

Future<void> confirmSignUpPhoneVerification(

String username,

String otpCode,

) async {

await Amplify.Auth.confirmSignUp(

username: username,

confirmationCode: otpCode,

);

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.

Future<void> confirmSignInPhoneVerification(String otpCode) async {

await Amplify.Auth.confirmSignIn(

confirmationValue: otpCode,

);

}
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.

Future<void> updateMfaPreferences() async {

final cognitoPlugin = Amplify.Auth.getPlugin(AmplifyAuthCognito.pluginKey);

await cognitoPlugin.updateMfaPreference(

sms: MfaPreference.enabled, // or .preferred

);

Multi-factor authentication with TOTP

If you are using the Authenticator component 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 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.

Future<void> 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<void> _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');

// ···

}
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.

Future<void> 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}');

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.

Future<void> updateMfaPreferences() async {

final cognitoPlugin = Amplify.Auth.getPlugin(AmplifyAuthCognito.pluginKey);

await cognitoPlugin.updateMfaPreference(

totp: MfaPreference.preferred,

);

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.

Future<void> 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');

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.

Future<void> verifyTotpSetup(String totpCode) async {

try {

await Amplify.Auth.verifyTotpSetup(totpCode);

} on AuthException catch (e) {

safePrint('An error occurred verifying TOTP: $e');

}
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.

Future<void> updateMfaPreferences() async {

final cognitoPlugin = Amplify.Auth.getPlugin(AmplifyAuthCognito.pluginKey);

await cognitoPlugin.updateMfaPreference(

sms: MfaPreference.enabled,

totp: MfaPreference.preferred,

);

Recover from a lost TOTP device

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 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 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

If you are using the Authenticator component with Amplify, this feature works without any
additional code. The guide below is for writing your own implementation.

Once you have setup email as your second layer of authentication with MFA as shown above,
your users will get an authentication code via email to complete sign-in after they sign in with
their username and password.

In order to send email authentication codes, the following prerequisites must be met:

 Cognito must be configured to send emails using Amazon Simple Email Service (Amazon
SES).
 Advanced Security Features (ASF) must be enabled in your user pool.

 If account recovery is enabled in Cognito, the delivery method for recovery messages
cannot be set to Email only

Additional pricing applies for ASF. Learn more about Amazon Cognito pricing

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.

Future<void> signUpWithEmailVerification(

String username,

String password,

) async {

await Amplify.Auth.signUp(

username: username,

password: password,

options: SignUpOptions(

userAttributes: <AuthUserAttributeKey, String>{

AuthUserAttributeKey.email: '[email protected]',

// ... if required

AuthUserAttributeKey.phoneNumber: '+18885551234',

},

),

);

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.

Future<void> confirmSignUpEmailVerification(
String username,

String otpCode,

) async {

await Amplify.Auth.confirmSignUp(

username: username,

confirmationCode: otpCode,

);

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.

Future<void> confirmSignInEmailVerification(String otpCode) async {

await Amplify.Auth.confirmSignIn(

confirmationValue: otpCode,

);

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.

Future<void> updateMfaPreferences() async {

final cognitoPlugin = Amplify.Auth.getPlugin(AmplifyAuthCognito.pluginKey);

await cognitoPlugin.updateMfaPreference(

email: MfaPreference.enabled, // or .preferred

);
}

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.

Future<void> 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}');

Update the current user's MFA preferences

Invoke the following API to update the MFA preference for the current user.

Only one MFA method can be marked as preferred at a time. If the user has multiple MFA
methods enabled and tries to mark more than one MFA method as preferred, the API will throw
an error.

Future<void> updateMfaPreferences() async {

final cognitoPlugin = Amplify.Auth.getPlugin(AmplifyAuthCognito.pluginKey);

await cognitoPlugin.updateMfaPreference(

sms: MfaPreference.enabled,

totp: MfaPreference.preferred,

);
}

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.

Note: The device tracking and remembering 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.

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

});
Understand key terms used for tracking devices

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.

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: 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 LoginGoogle Sign-InLogin with AmazonSign in with Apple

1. Create a developer account with Facebook.

2. Sign in 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.

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 for use with cloud sandbox, or via
the Amplify Console for branch environments.

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 LoginGoogle Sign-InLogin with AmazonSign in with Apple

1. Sign In 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://<your-user-pool-domain>/oauth2/idpresponse

6. Save your changes.

Learn more about using social identity providers with user pool

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.
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'),

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.

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.
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'),

attributeMapping: {

email: 'email'

},

callbackUrls: ["myapp://callback/"],

logoutUrls: ["myapp://signout/"],

});

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:

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: '<your-issuer-url>',

},

],

callbackUrls: ["myapp://callback/"],

logoutUrls: ["myapp://signout/"],

},

},

});

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:

amplify/auth/resource.ts

import { defineAuth } from '@aws-amplify/backend';

export const auth = defineAuth({

loginWith: {

email: true,

externalProviders: {
saml: {

name: 'MicrosoftEntraIDSAML',

metadata: {

metadataContent: '<your-url-hosting-saml-metadata>', // or content of the metadata file

metadataType: 'URL', // or 'FILE'

},

},

callbackUrls: ["myapp://callback/"],

logoutUrls: ["myapp://signout/"],

},

},

});

Tokens and credentials

Amplify Auth interacts with its underlying Amazon Cognito user pool 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 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:

"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 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.

"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": "[email protected]"

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:
{

"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": "[email protected]"

Conversely, user pool group claims are found in both the access token and ID token on
the cognito:groups claim:

"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": "[email protected]"

Visit the AWS documentation for using tokens with Cognito user pools to learn more about
tokens, how they're used with Cognito, and their intended usage.

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 on iOS and macOS
and EncryptedSharedPreferences on Android.

Amplify will refresh the access token and ID token as long as the refresh token 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.

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.

await Amplify.addPlugin(

AmplifyAuthCognito(secureStorageFactory: InMemoryStorage.new),

);

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<String, String> _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
invoke await Amplify.Auth.signOut(options: const signOutOptions(globalSignOut: true)) to
globally sign out your user from all of their devices.

Using the Authenticator

The quickest way to get started with Amplify Auth in your frontend application is with
the Authenticator component, which provides a customizable UI and complete authentication
flows.

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.

Sign-up

Amplify provides a client library that enables you to interact with backend resources such as
Amplify Auth.

The quickest way to get started with Amplify Auth in your frontend application is with
the Authenticator component, 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:

/// Signs a user up with a username, password, and email. The required

/// attributes may be different depending on your app's configuration.


Future<void> 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}');

Future<void> _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.',

);

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

confirmSignU The sign up needs to be confirmed by collecting a code from the user and
p 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:

Future<void> 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

Amplify provides a client library that enables you to interact with backend resources such as
Amplify Auth.
The quickest way to get started with Amplify Auth in your frontend application is with
the Authenticator component, which provides a customizable UI and complete authentication
flows.

Using the signIn API

Future<void> 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.

Future<void> _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.',

);

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

The user was created with a temporary password


confirmSignInWithNewPassword and must set a new one. Complete the process
with confirmSignIn.

The sign-in must be confirmed with a custom


confirmSignInWithCustomChallenge challenge response. Complete the process
with confirmSignIn.

The sign-in must be confirmed with a TOTP code


confirmSignInWithTotpMfaCode from the user. Complete the process
with confirmSignIn.

The sign-in must be confirmed with a SMS code


confirmSignInWithSmsMfaCode from the user. Complete the process
with confirmSignIn.

The sign-in must be confirmed with a code from


confirmSignInWithOtpCode the user (sent via SMS or Email). Complete the
process with confirmSignIn.

The user must select their mode of MFA


continueSignInWithMfaSelection verification before signing in. Complete the
process with confirmSignIn.

continueSignInWithMfaSetupSelection The user must select their mode of MFA


Next Step Description

verification to setup. Complete the process by


passing
either "EMAIL" or "TOTP" to confirmSignIn.

The TOTP setup process must be continued.


continueSignInWithTotpSetup
Complete the process with confirmSignIn.

The EMAIL setup process must be continued.


continueSignInWithEmailMfaSetup Complete the process by passing a valid email
address to confirmSignIn.

The user must reset their password


resetPassword
via resetPassword.

The user hasn't completed the sign-up flow fully


confirmSignUp
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.

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 to learn more about enabling MFA on your
backend auth resource.

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

confirmSignInWithTotpM The sign-in must be confirmed with a TOTP code from the
faCode user. Complete the process with confirmSignIn.

confirmSignInWithSmsMf The sign-in must be confirmed with a SMS code from the user.
aCode Complete the process with confirmSignIn.

confirmSignInWithOtpCo The sign-in must be confirmed with a code from the user (sent
de via SMS or Email). Complete the process with confirmSignIn.

continueSignInWithMfaS The user must select their mode of MFA verification before
election signing in. Complete the process with confirmSignIn.

The user must select their mode of MFA verification to setup.


continueSignInWithMfaS Complete the process by passing
etupSelection either MfaType.email.confirmationValue or MfaType.totp.confi
rmationValue to confirmSignIn.

continueSignInWithTotpS The TOTP setup process must be continued. Complete the


etup process with confirmSignIn.

continueSignInWithEmail The EMAIL setup process must be continued. Complete the


MfaSetup process by passing a valid email address to confirmSignIn.

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.

Sign in with an external identity provider


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:

<queries>

<intent>

<action android:name=

"android.support.customtabs.action.CustomTabsService" />

</intent>

</queries>

<application>

...

<activity

android:name=".MainActivity" android:exported="true">

<intent-filter>

<action android:name="android.intent.action.VIEW" />

<category android:name="android.intent.category.DEFAULT" />

<category android:name="android.intent.category.BROWSABLE" />


<data android:scheme="myapp" />

</intent-filter>

</activity>

...

</application>

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.

Future<void> 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}');

Password

ign-out

Amplify provides a client library that enables you to interact with backend resources such as
Amplify Auth.

The quickest way to get started with Amplify Auth in your frontend application is with
the Authenticator component, which provides a customizable UI and complete authentication
flows.

To sign a user out of your application use the signOut API.

Future<void> 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}');

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).

Future<void> 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}');

anage 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.

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:

Future<void> 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.

Future<void> 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}');

}
}

PREVIOUS

anage 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.

Configure custom user attributes during sign-up

Custom attributes can be passed in with the userAttributes option of the signUp API:

Future<void> _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,

),

);

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.

Future<void> 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.

Future<void> 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.

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:

Future<void> updateUserAttributes() async {

const attributes = [

AuthUserAttribute(

userAttributeKey: AuthUserAttributeKey.email,

value: '[email protected]',

),

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}');

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:

Future<void> 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:

Future<void> 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}');

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.

AWS Cognito Auth Plugin sends important events through Amplify Hub. You can listen to these
events like the following:

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;

});

Delete user account

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.

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.

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 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:

Future<void> deleteUser() async {

try {

await Amplify.Auth.deleteUser();

safePrint('Delete user succeeded');

} on AuthException catch (e) {

safePrint('Delete user failed with error: $e');

}
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.

PREVIOUS

Listen to auth events

NEXT

Multi-step sign-in

On this page

 Allow users to delete their account

Site color mode

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 you provided
when you define your auth resources like described on Manage MFA Settings 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.

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.

Future<SignInResult> signInWithCognito(

String username,

String password,

) async {

final SignInResult result = await Amplify.Auth.signIn(

username: username,

password: password,

);

return _handleSignInResult(result);

Future<void> _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.

Future<void> _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.',

);

Future<void> 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.

Future<void> _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<void> 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.

Future<void> _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.',

);

Future<void> 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

Future<void> _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<MfaType> _promptUserPreference(Set<MfaType> allowedTypes) async {

// ···

}
Future<void> _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.

Future<void> _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<void> 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.

Future<void> _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<void> 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

Future<void> _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<MfaType> _promptUserPreference(Set<MfaType> allowedTypes) async {

// ···

Future<void> _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.

For example, your custom challenge Lambda may pass a prompt to the frontend which requires
the user to enter a secret code.

Future<void> _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.

Future<void> 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}');

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.

Future<void> _handleSignInResult(SignInResult result) async {

switch (result.nextStep.signInStep) {

// ...

case AuthSignInStep.confirmSignInWithNewPassword:

safePrint('Please enter a new password');

// ...

Future<void> 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 docs for more information.

Future<void> _handleSignInResult(SignInResult result) async {

switch (result.nextStep.signInStep) {

// ...
case AuthSignInStep.resetPassword:

final resetResult = await Amplify.Auth.resetPassword(

username: username,

);

await _handleResetPasswordResult(resetResult);

// ...

Future<void> _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 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.

Future<void> _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.',

);

Future<void> 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.

Future<void> _handleSignInResult(SignInResult result) async {

switch (result.nextStep.signInStep) {

// ...

case AuthSignInStep.done:

// Could also check that `result.isSignedIn` is `true`

safePrint('Sign in is complete');

PREVIOUS
Delete user account

With admin actions

Amplify Auth can be managed with the AWS SDK's @aws-sdk/client-cognito-identity-


provider package. 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.

To get started, create an "ADMINS" group that will be used to authorize the mutation:

amplify/auth/resource.ts

import { defineAuth } from "@aws-amplify/backend"

export const auth = defineAuth({

loginWith: {

email: true,

},

groups: ["ADMINS"]

})

Next, create the Function resource:

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.

amplify/auth/resource.ts
import { defineAuth } from "@aws-amplify/backend"

import { addUserToGroup } from "../data/add-user-to-group/resource"

export const auth = defineAuth({

loginWith: {

email: true,

},

groups: ["ADMINS"],

access: (allow) => [

allow.resource(addUserToGroup).to(["addUserToGroup"])

],

})

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.

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<typeof schema>

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:

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

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.

Future<void> 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}');

Future<void> _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;

To complete the password reset process, invoke the confirmResetPassword API with the code
your user received and the new password they want to set.

Future<void> 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}');

Update password

You can update a signed in user's password using the updatePassword API.

Future<void> 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}');

Override default user account verification channel

You can always change the channel used by your authentication resources by overriding the
following setting.

amplify/auth/resource.ts

import { defineAuth } from '@aws-amplify/backend';

export const auth = defineAuth({

loginWith: {

email: true

},

accountRecovery: 'EMAIL_ONLY'

});

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:

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,

},

};

PREVIOUS

With admin action

Custom auth flows

The Auth category can be configured to perform a custom authentication flow 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 when targeting Web, Windows, or
Linux. Additional setup is required for some target platforms. Please see the platform setup for
more details on platform specific setup.

Configure Auth

The custom auth flow can be configured manually.

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.

Future<void> signUpCustomFlow() async {

try {

final userAttributes = <AuthUserAttributeKey, String>{

AuthUserAttributeKey.email: '[email protected]',

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.

Future<void> 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:

// Create state variables for the sign in status

var isSignedIn = false;

String? challengeHint;

Future<void> 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.

Future<void> 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.

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 code to handle
a PASSWORD_VERIFIER step:

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;

};

NEXT

Email customization

On this page

 Prerequisites

 Configure Auth

 Register a user

 Sign in a user

 Confirm sign in with custom challenge

 Custom authentication flow with password verification

Site color mode


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:

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. 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:
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.

riggers

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, add a
user to a group upon confirmation, or create a "UserProfile" model upon account confirmation.

Triggers translate to Cognito user pool Lambda triggers.

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:

amplify/auth/resource.ts

import { defineAuth } from "@aws-amplify/backend"

export const auth = defineAuth({

loginWith: {

email: true,

},

triggers: {}

})

Enable sign-in with web UI

Prerequisites

 An app set up according to the getting started walkthrough

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 OAuth Flow.

Update the auth/resource.ts file like the following to enable the sign-in and sign-out capabilities
with a web ui.
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:

<queries>

<intent>

<action android:name=

"android.support.customtabs.action.CustomTabsService" />

</intent>

</queries>
<application>

...

<activity

android:name=".MainActivity" android:exported="true">

<intent-filter>

<action android:name="android.intent.action.VIEW" />

<category android:name="android.intent.category.DEFAULT" />

<category android:name="android.intent.category.BROWSABLE" />

<data android:scheme="myapp" />

</intent-filter>

</activity>

...

</application>

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.

Future<void> 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:

Future<void> 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 internally for iOS.


ASWebAuthenticationSession has a property, prefersEphemeralWebBrowserSession 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.

Future<void> signInWithWebUIAndPrivateSession() async {

await Amplify.Auth.signInWithWebUI(

options: const SignInWithWebUIOptions(

pluginOptions: CognitoSignInWithWebUIPluginOptions(

isPreferPrivateSession: true,

),

),

);

PREVIOUS

Moving to production

Amplify Auth provisions Amazon 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 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).

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. 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:

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: "[email protected]",

},

},
})

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.

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: "[email protected]",

fromName: "MyApp",

replyTo: "[email protected]"

},

},

})

SMS

In order to send SMS authentication codes, you must request an origination number.
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, 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, select the Text messaging (SMS) tab from the
navigation pane, and check the status under the Account information section.

dvanced 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.

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.

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.

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,

),

You might also like