Announcing the AWS Amplify CLI toolchain. Click here to read more.

View Section

Authentication

AWS Amplify Authentication module provides Authentication APIs and building blocks for developers who want to create user authentication experiences.

Amazon Cognito

Amazon Cognito User Pools is a full-featured user directory service to handle user registration, storage, authentication, and account recovery. Cognito User Pools returns JWT tokens to your app and does not provide temporary AWS credentials for calling authorized AWS Services. Amazon Cognito Federated Identities on the other hand, is a way to authorize your users to use the various AWS services. With an identity pool, you can obtain temporary AWS credentials with permissions you define to access other AWS services directly or to access resources through Amazon API Gateway.

When working together, Cognito User Pools acts as a source of user identities (identity provider) for the Cognito Federated Identities. Other sources can be OpenID, Facebook, Google, etc. AWS Amplify uses User Pools to store your user information and handle authorization, and it leverages Federated Identities to manage user access to AWS Resources, for example allowing a user to upload a file to an S3 bucket.

Ensure you have installed and configured the Amplify CLI and library.

Automated Setup

Run the following command in your project’s root folder:

$ amplify add auth

If you have previously enabled an Amplify category that uses Auth behind the scenes, e.g. API category, you may already have an Auth configuration. In such a case, run amplify auth update command to edit your configuration.

The CLI prompts will help you to customize your auth flow for your app. With the provided options, you can:

  • Customize sign-in/registration flow
  • Customize email and SMS messages for Multi-Factor Authentication
  • Customize attributes for your users, e.g. name, email
  • Enable 3rd party authentication providers, e.g. Facebook, Twitter, Google and Amazon

After configuring your Authentication options, update your backend:

$ amplify push

A configuration file called aws-exports.js will be copied to your configured source directory, for example ./src.

Configure Your App

In your app’s entry point i.e. App.js, import and load the configuration file:

import Amplify, { Auth } from 'aws-amplify';
import aws_exports from './aws-exports';
Amplify.configure(aws_exports);

Manual Setup

For manual configuration you need to provide your AWS Resource configuration:

import Amplify from 'aws-amplify';

Amplify.configure({
    Auth: {

        // REQUIRED only for Federated Authentication - Amazon Cognito Identity Pool ID
        identityPoolId: 'XX-XXXX-X:XXXXXXXX-XXXX-1234-abcd-1234567890ab',
        
        // REQUIRED - Amazon Cognito Region
        region: 'XX-XXXX-X',

        // OPTIONAL - Amazon Cognito Federated Identity Pool Region 
        // Required only if it's different from Amazon Cognito Region
        identityPoolRegion: 'XX-XXXX-X',

        // OPTIONAL - Amazon Cognito User Pool ID
        userPoolId: 'XX-XXXX-X_abcd1234',

        // OPTIONAL - Amazon Cognito Web Client ID (26-char alphanumeric string)
        userPoolWebClientId: 'a1b2c3d4e5f6g7h8i9j0k1l2m3',

        // OPTIONAL - Enforce user authentication prior to accessing AWS resources or not
        mandatorySignIn: false,

        // OPTIONAL - Configuration for cookie storage
        cookieStorage: {
        // REQUIRED - Cookie domain (only required if cookieStorage is provided)
            domain: '.yourdomain.com',
        // OPTIONAL - Cookie path
            path: '/',
        // OPTIONAL - Cookie expiration in days
            expires: 365,
        // OPTIONAL - Cookie secure flag
            secure: true
        },

        // OPTIONAL - customized storage object
        storage: new MyStorage(),
        
        // OPTIONAL - Manually set the authentication flow type. Default is 'USER_SRP_AUTH'
        authenticationFlowType: 'USER_PASSWORD_AUTH'
    }
});

Working with the API

Common Authentication Use Cases

The Authentication category exposes a set of APIs to be used in any JavaScript framework. Please check AWS Amplify API Reference for full API list.

Sign In

Sign in with user credentials:

import { Auth } from 'aws-amplify';

Auth.signIn(username, password)
    .then(user => console.log(user))
    .catch(err => console.log(err));

// If MFA is enabled, sign-in should be confirmed with the congirmation code
// `user` : Return object from Auth.signIn()
// `code` : Confirmation code  
// `mfaType` : MFA Type e.g. SMS, TOTP.
Auth.confirmSignIn(user, code, mfaType)
    .then(data => console.log(data))
    .catch(err => console.log(err));

Sign Up

Creates a new user in your User Pool:

import { Auth } from 'aws-amplify';

Auth.signUp({
    username,
    password,
    attributes: {
        email,          // optional
        phone_number,   // optional - E.164 number convention
        // other custom attributes 
    },
    validationData: []  //optional
    })
    .then(data => console.log(data))
    .catch(err => console.log(err));

// After retrieveing the confirmation code from the user
Auth.confirmSignUp(username, code, {
    // Optional. Force user confirmation irrespective of existing alias. By default set to True.
    forceAliasCreation: true    
}).then(data => console.log(data))
  .catch(err => console.log(err));

Forcing Email Uniqueness in Cognito User Pools

When your Cognito User Pool sign-in options are set to “Username”, and “Also allow sign in with verified email address”, signUp() method creates a new user account everytime, without validating email uniqueness. In this case you will end up having multiple user pool identities and previously created account’s attribute is changed to email_verified : false.

To enforce Cognito User Pool signups with a unique email, you need to change your User Pool’s Attributes setting in Amazon Cognito console as the following:

User Pool Settings

Sign Out

import { Auth } from 'aws-amplify';

Auth.signOut()
    .then(data => console.log(data))
    .catch(err => console.log(err));

// By doing this, you are revoking all the auth tokens(id token, access token and refresh token)
// which means the user is signed out from all the devices
// Note: although the tokens are revoked, the AWS credentials will remain valid until they expire (which by default is 1 hour)
Auth.signOut({ global: true })
    .then(data => console.log(data))
    .catch(err => console.log(err));
    

Change password

import { Auth } from 'aws-amplify';

Auth.currentAuthenticatedUser()
    .then(user => {
        return Auth.changePassword(user, 'oldPassword', 'newPassword');
    })
    .then(data => console.log(data))
    .catch(err => console.log(err));

Forgot Password

import { Auth } from 'aws-amplify';

Auth.forgotPassword(username)
    .then(data => console.log(data))
    .catch(err => console.log(err));

// Collect confirmation code and new password, then
Auth.forgotPasswordSubmit(username, code, new_password)
    .then(data => console.log(data))
    .catch(err => console.log(err));

Verify phone_number or email address

Either the phone number or the email address is required for account recovery. You can let the user verify those attributes by:

// To initiate the process of verifying the attribute like 'phone_number' or 'email'
Auth.verifyCurrentUserAttribute(attr)
.then(() => {
     console.log('a verification code is sent');
}).catch(e) => {
     console.log('failed with error', e);
});

// To verify attribute with the code
Auth.verifyCurrentUserAttributeSubmit(attr, 'the_verification_code')
.then(() => {
     console.log('phone_number verified');
}).catch(e) => {
     console.log('failed with error', e);
});

Retrieve Current Authenticated User

You can call Auth.currentAuthenticatedUser() to get the current authenticated user object.

import { Auth } from 'aws-amplify';

Auth.currentAuthenticatedUser()
    .then(user => console.log(user))
    .catch(err => console.log(err));

This method can be used to check if a user is logged in when the page is loaded. It will throw an error if there is no user logged in. This method should be called after the Auth module is configured or the user is logged in. To ensure that you can listen on the auth events configured or signIn. Learn how to listen on auth events.

Retrieve Current Session

Auth.currentSession() returns a CognitoUserSession object which contains JWT accessToken, idToken, and refreshToken.

let session = Auth.currentSession();
// CognitoUserSession => { idToken, refreshToken, accessToken }

Managing Security Tokens

When using Authentication with AWS Amplify, you don’t need to refresh Amazon Cognito tokens manually. The tokens are automatically refreshed by the library when necessary.

Security Tokens like IdToken or AccessToken are stored in localStorage for the browser and in AsyncStorage for React Native. If you want to store those tokens in a more secure place or you are using Amplify in server side, then you can provide your own storage object to store those tokens.

For example:

class MyStorage {
    // set item with the key
    static setItem(key: string, value: string): string;
    // get item with the key
    static getItem(key: string): string;
    // remove item with the key
    static removeItem(key: string): void;
    // clear out the storage
    static clear(): void;
    // If the storage operations are async(i.e AsyncStorage)
    // Then you need to sync those items into the memory in this method
    static sync(): Promise<void>;
}

// tell Auth to use your storage object
Auth.configure({
    storage: MyStorage
});

To learn more about tokens, please visit Amazon Cognito Developer Documentation.

Using Components in React

For React and React Native apps, the simplest way to add authentication flows into your app is to use withAuthenticator High Order Component.

withAuthenticator automatically detects the authentication state and updates the UI. If the user is signed in, the underlying component (typically your app’s main component) is displayed otherwise signing/signup controls is displayed.

Just add these two lines to your App.js:

import { withAuthenticator } from 'aws-amplify-react'; // or 'aws-amplify-react-native';
...
export default withAuthenticator(App);

Now, your app has complete flows for user sign-in and registration. Since you have wrapped your App with withAuthenticator, only signed in users can access your app. The routing for login pages and giving access to your App Component will be managed automatically.

Enabling Federated Identities

You can enable federated Identity login by specifying federated option (for react-js only). Here is a configuration for enabling social login with multiple providers:

import { withAuthenticator } from 'aws-amplify-react';
const AppWithAuth = withAuthenticator(App);

const federated = {
    google_client_id: '',
    facebook_app_id: '',
    amazon_client_id: ''
};

ReactDOM.render(<AppWithAuth federated={federated}/>, document.getElementById('root'));

You can also initiate a federated signin process by calling Auth.federatedSignIn() method with a specific identity provider in your code:

import { Auth } from 'aws-amplify';

// Retrieve active Google user session
const ga = window.gapi.auth2.getAuthInstance();
ga.signIn().then(googleUser => {
    const { id_token, expires_at } = googleUser.getAuthResponse();
    const profile = googleUser.getBasicProfile();
    const user = {
        email: profile.getEmail(),
        name: profile.getName()
    };

    return Auth.federatedSignIn(
        // Initiate federated sign-in with Google identity provider 
        'google',
        { 
            // the JWT token
            token: id_token, 
            // the expiration time
            expires_at 
        },
        // a user object
        user
    ).then(() => {
        // ...
    });
});

Availible identity providers are google, facebook, amazon, developer and OpenID. To use an OpenID provider, use the URI of your provider as the key, e.g. accounts.your-openid-provider.com.

Retrieving JWT Token

After the federated login, you can retrieve related JWT token from the local cache using the Cache module:

import { Cache } from 'aws-amplify';

// Run this after the sign-in
Cache.getItem('federatedInfo').then(federatedInfo => {
     const { token } = federatedInfo;
});

Refreshing JWT Tokens

By default, AWS Amplify will automatically refresh the tokens for Google and Facebook, so that your AWS credentials will be valid at all times. But if you are using another federated provider, you will need to provide your own token refresh method:

import { Auth } from 'aws-amplify';

function refreshToken() {
    // refresh the token here and get the new token info
    // ......

    return new Promise(res, rej => {
        const data = {
            token, // the token from the provider
            expires_at, // the timestamp for the expiration
            identity_id, // optional, the identityId for the credentials
        }
        res(data);
    });
}

Auth.configure({
    refreshHandlers: {
        'developer': refreshToken
    }
})

Rendering a Sign Out Button

withAuthenticator component renders your App component after a successful user signed in, and it prevents non-sign-in uses to interact with your app. In this case, we need to display a sign-out button to trigger the related process.

To display a sign-out button, set includeGreetings = true in the parameter object. It displays a greetings section on top of your app, and a sign-out button is displayed in the authenticated state.

export default withAuthenticator(App, { includeGreetings: true });

Using Authenticator Component

The withAuthenticator HOC essentially just wraps Authenticator component. Using Authenticator directly gives you more customization options for your UI.

Wrapping your Component

This will render your App component with Authenticator:

import { Authenticator } from 'aws-amplify-react'; // or 'aws-amplify-react-native'
...

class AppWithAuth extends Component {
  render(){
    return (
      <div>
      <Authenticator>
        <App />
      </Authenticator>
      </div>
    );
  }
}

export default AppWithAuth;

Show your App After Sign-in

In the previous example, you’ll see the App is rendered even before the user is signed-in. To change this behavior, you can use Authenticator properties. When inside Authenticator, the App component automatically receives those properties.

authState is the current authentication state (a string):

 - signIn
 - signUp
 - confirmSignIn
 - confirmSignUp
 - forgotPassword
 - verifyContact
 - signedIn

authData - additional data within authState; when the state is signedIn, it will return a user object.

Using the options above, to control the condition for Authenticator to render App component, simply set _validAuthStates property:

this._validAuthStates = ['signedIn'];

Then, in the component’s constructor, implement showComponent(theme) {} in lieu of the typical render() {} method.

Federated Identities (Social Sign-in)

Availability Note Currently, our federated identity components only support Google, Facebook and Amazon identities. Please see our Setup Guide for Federated Identities.

To enable social sign-in in your app with Federated Identities, add Google client_id, Facebook app_id and/or Amazon client_id properties to Authenticator component:

import { Authenticator } from 'aws-amplify-react';
const federated = {
    google_client_id: '',
    facebook_app_id: '',
    amazon_client_id: ''
};

return (
    <Authenticator federated={federated}> //federated option is currently not supported on react-native
)

For React Native, you can use Auth.federatedSignIn() to get your federated identity from Cognito. You need to provide a valid JWT token from the third provider. You can also use it with Authenticator, so that component automatically persists your login status.

Federated Sign in with Facebook Example:

import Expo from 'expo';
import Amplify, { Auth } from 'aws-amplify';
import { Authenticator } from 'aws-amplify-react-native';

export default class App extends React.Component {
  async signIn() {
    const { type, token, expires } = await Expo.Facebook.logInWithReadPermissionsAsync('YOUR_FACEBOOK_APP_ID', {
        permissions: ['public_profile'],
      });
    if (type === 'success') {
      // sign in with federated identity
      Auth.federatedSignIn('facebook', { token, expires_at: expires}, { name: 'USER_NAME' })
        .then(credentials => {
          console.log('get aws credentials', credentials);
        }).catch(e => {
          console.log(e);
        });
    }
  }

  // ...

  render() {
    return (
      <View style={styles.container}>
        <Authenticator>
        </Authenticator>
        <Button title="FBSignIn" onPress={this.signIn.bind(this)} />
      </View>
    );
  }
}

Customize UI

To customize the UI for Federated Identities sign-in, you can use withFederated component (react-js only). The following code shows how you customize the login buttons and the layout for social sign-in.

import { withFederated } from 'aws-amplify-react';

const Buttons = (props) => (
    <div>
        <img
            onClick={props.googleSignIn}
            src={google_icon}
        />
        <img
            onClick={props.facebookSignIn}
            src={facebook_icon}
        />
        <img
            onClick={props.amazonSignIn}
            src={amazon_icon}
        />
    </div>
)

const Federated = withFederated(Buttons);

...

const federated = {
    google_client_id: '',
    facebook_app_id: '',
    amazon_client_id: ''
};

<Federated federated={federated} onStateChange={this.handleAuthStateChange} /> //federated option is currently not supported on react-native

There is also withGoogle, withFacebook, withAmazon components, in case you need to customize a single provider.

Using Amazon Cognito Hosted UI

Amazon Cognito provides a customizable user experience via the hosted UI. The hosted UI supports OAuth 2.0 and Federated Identities with Facebook, Amazon, Google, and SAML providers. To learn more about Amazon Cognito Hosted UI, please visit Amazon Cognito Developer Guide.

Setup your Cognito App Client

To start using hosted UI, you need to setup your App Client in the Amazon Cognito console.

To setup App Client;

  • Go to Amazon Cognito Console.
  • Click User Pools on the top menu to select a User Pool or create a new one.
  • Click App integration and App client settings on the left menu.
  • Select Enabled Identity Providers and enter Callback URL(s) and Sign out URL(s) fields.
  • Under the OAuth 2.0 section, select an OAuth Flow. Authorization code grant is the recommended choice for security reasons.
  • Choose item(s) from OAuth Scopes.
  • Click ‘Save Changes’

To enable the domain for your hosted UI;

  • On the left menu, go to App integration > Domain name.
  • In the Domain prefix section, enter the prefix for the pages that will be hosted by Amazon Cognito.

You can also enable Federated Identities for your hosted UI;

  • Go to Federation > Identity providers
  • Select an Identity provider and enter required credentials for the identity provider. (e.g., App Id, App secret, Authorized scope)
  • In the settings page for your selected identity provider (Facebook, Google, etc.), set Oauth Redirected URI to https://your-domain-prefix.auth.us-east-1.amazoncognito.com/oauth2/idpresponse (your-domain-prefix is the domain prefix you have entered in previously).
  • To retrieve user attributes from your identity provider, go to Federation > Attribute mapping. Here, you can map Federation Provider attributes to corresponding User pool attributes.

If email attribute is a required field in your Cognito User Pool settings, please make sure that you have selected email in your Authorized Scopes, and you have mapped it correctly to your User Pool attributes.

Configuring the Hosted UI

To configure your application for hosted UI, you need to use oauth options:

import Amplify from 'aws-amplify';

const oauth = {
    // Domain name
    domain : 'your-domain-prefix.auth.us-east-1.amazoncognito.com', 
    
    // Authorized scopes
    scope : ['phone', 'email', 'profile', 'openid','aws.cognito.signin.user.admin'], 

    // Callback URL
    redirectSignIn : 'http://www.example.com/signin', 
    
    // Sign out URL
    redirectSignOut : 'http://www.example.com/signout',

    // 'code' for Authorization code grant, 
    // 'token' for Implicit grant
    responseType: 'code'

    // optional, for Cognito hosted ui specified options
    options: {
        // Indicates if the data collection is enabled to support Cognito advanced security features. By default, this flag is set to true.
        AdvancedSecurityDataCollectionFlag : true
    }
}

Amplify.configure({
    Auth: {
        // other configurations...
        // ....
        oauth: oauth
    },
    // ...
});

Launching the Hosted UI

To invoke the browser to display the hosted UI, you need to construct the URL in your app;

const config = Auth.configure();
const { 
    domain,  
    redirectSignIn, 
    redirectSignOut,
    responseType } = config.oauth;

const clientId = config.userPoolWebClientId;
// The url of the Cognito Hosted UI
const url = 'https://' + domain + '/login?redirect_uri=' + redirectSignIn + '&response_type=' + responseType + '&client_id=' + clientId;
// If you only want to log your users in with Google or Facebook, you can construct the url like:
const url_to_google = 'https://' + domain + '/oauth2/authorize?redirect_uri=' + redirectSignIn + '&response_type=' + responseType + '&client_id=' + clientId + '&identity_provider=Google';
const url_to_facebook = 'https://' + domain + '/oauth2/authorize?redirect_uri=' + redirectSignIn + '&response_type=' + responseType + '&client_id=' + clientId + '&identity_provider=Facebook';

// Launch hosted UI
window.location.assign(url);

// Launch Google/Facebook login page
window.location.assign(url_to_google);
window.location.assign(url_to_facebook);

Launching the Hosted UI in React

With React, you can use withOAuth HOC to launch the hosted UI experience. Just wrap your app’s main component with our HOC:

import { withOAuth } from 'aws-amplify-react';

class MyApp extends React.Component {
    // ...
    render() {
        return(
            <button onClick={this.props.OAuthSignIn}>
                Sign in with AWS
            </button>
        )
    }
}

export default withOAuth(MyApp);

Handling Authentication Events

When using the hosted UI, you can handle authentication events by creating event listeners with the Hub module.

Enabling MFA

MFA (Multi-factor authentication increases security for your app by adding an authentication method and not relying solely on the username (or alias) and password. AWS Amplify uses Amazon Cognito to provide MFA. Please see Amazon Cognito Developer Guide for more information about setting up MFA in Amazon Cognito.

Once you enable MFA on Amazon Cognito, you can configure your app to work with MFA.

Enabling TOTP

With TOTP (Time-based One-time Password), your app user is challenged to complete authentication using a time-based one-time (TOTP) password after their username and password have been verified.

You can setup TOTP for a user in your app:

import { Auth } from 'aws-amplify';

// To setup TOTP, first you need to get a `authorization code` from Amazon Cognito
// `user` is the current Authenticated user
Auth.setupTOTP(user).then((code) => {
    // You can directly display the `code` to the user or convert it to a QR code to be scanned.
    // E.g., use following code sample to render a QR code with `qrcode.react` component:  
    //      import QRCode from 'qrcode.react';
    //      const str = "otpauth://totp/AWSCognito:"+ username + "?secret=" + code + "&issuer=" + issuer;
    //      <QRCode value={str}/>
});

// ...

// Then you will have your TOTP account in your TOTP-generating app (like Google Authenticator)
// Use the generated one-time password to verify the setup
Auth.verifyTotpToken(user, challengeAnswer).then(() => {

    // don't forget to set TOTP as the preferred MFA method
    Auth.setPreferredMFA(user, 'TOTP');
    // ...
}).catch( e => {
    // Token is not verified
});

Setup MFA Type

There are multiple MFA types supported by Amazon Cognito. You can set the preferred method in your code:

import { Auth } from 'aws-amplify';

// You can select preferred mfa type, for example:
// Select TOTP as preferred
Auth.setPreferredMFA(user, 'TOTP').then((data) => {
    console.log(data);
    // ...
}).catch(e => {});

// Select SMS as preferred
Auth.setPreferredMFA(user, 'SMS');

// Select no-mfa
Auth.setPreferredMFA(user, 'NOMFA');

Retrieving Current Preferred MFA Type

You can get current preferred MFA type in your code:

import { Auth } from 'aws-amplify';

Auth.getPreferredMFA(user).then((data) => {
    console.log('Current prefered MFA type is: ' + data);
})

Letting User Select MFA Type

When working with multiple MFA Types, you can let the app user select the desired authentication method. SelectMFAType UI Component, which is provided with aws-amplify-react package, renders a list of available MFA types.

import Amplify from 'aws-amplify';
import amplify from './aws-exports';
import { SelectMFAType } from 'aws-amplify-react';

Amplify.configure(amplify);

// Please have at least TWO types
// Please make sure you set it properly according to your Cognito User pool
const MFATypes = {
    SMS: true, // if SMS enabled in your user pool
    TOTP: true, // if TOTP enabled in your user pool
    Optional: true, // if MFA is set to optional in your user pool
}

class App extends Component {
    // ...
    render() {
        return (
            // ...
            <SelectMFAType authData={this.props.authData} MFATypes={MFATypes}>
        )
    }
}

export default withAuthenticator(App, true);

Customizing Authentication Flow

Amazon Cognito User Pools support customizing the authentication flow to enable new challenge types, in addition to a password, to verify the identity of users. These challenge types may include CAPTCHAs or dynamic challenge questions.

To define your challenges for custom authentication flow, you need to implement Lambda triggers for Amazon Cognito.

Switching Authentication Flow Type

There are two different types of authentication flow supported: USER_SRP_AUTH and USER_PASSWORD_AUTH. USER_SRP_AUTH is used by default and utilizes the SRP protocol (Secure Remote Password) to encrypt the password on the client before it’s sent to the back-end. It is a more secure way of sending user credentials over the network and is, therefore, the recommended approach.

The USER_PASSWORD_AUTH flow will send user credentials unencrypted to the back-end. If you want to migrate users to Cognito using the “Migration” trigger and avoid forcing users to reset their passwords, you need to use this authentication flow type as the Lambda function invoked by the trigger has to be able to verify the supplied user credentials.

To configure Auth to use the USER_PASSWORD_AUTH flow, add it as a string value to the property authenticationFlowType:

Auth.configure({
    // other configurations...
    // ...
    authenticationFlowType: 'USER_PASSWORD_AUTH',
})

For your Cognito User Pool to accept authentication requests using USER_PASSWORD_AUTH, your Cognito app client has to be configured to allow that flow. In the AWS Console, this is done by ticking the checkbox at General settings > App clients > Show Details (for the affected client) > Enable username-password (non-SRP) flow. If you’re using the AWS CLI or Cloudformation, update your app client by adding USER_PASSWORD_AUTH to the list of “Explicit Auth Flows”.

Creating a CAPTCHA

The following Lambda creates a CAPTCHA as a challenge to the user. The URL for the CAPTCHA image and the expected answer is added to the private challenge parameters:

export const handler = async (event) => {
    if (!event.request.session || event.request.session.length === 0) {
        event.response.publicChallengeParameters = {
            captchaUrl: "url/123.jpg",
        };
        event.response.privateChallengeParameters = {
            answer: "5",
        };
        event.response.challengeMetadata = "CAPTCHA_CHALLENGE";
    }
    return event;
};

Defining a Custom Challenge

This example defines a custom challenge:

export const handler = async (event) => {
    if (!event.request.session || event.request.session.length === 0) {
        // If we don't have a session or it is empty then send a CUSTOM_CHALLENGE
        event.response.challengeName = "CUSTOM_CHALLENGE";
        event.response.failAuthentication = false;
        event.response.issueTokens = false;
    } else if (event.request.session.length === 1 && event.request.session[0].challengeResult === true) {
        // If we passed the CUSTOM_CHALLENGE then issue token
        event.response.failAuthentication = false;
        event.response.issueTokens = true;
    } else {
        // Something is wrong. Fail authentication
        event.response.failAuthentication = true;
        event.response.issueTokens = false;
    }

    return event;
};

Verify Challenge Response

This Lambda is used to verify a challenge answer:

export const handler = async (event, context) => {
    if (event.request.privateChallengeParameters.answer === event.request.challengeAnswer) {
        event.response.answerCorrect = true;
    } else {
        event.response.answerCorrect = false;
    }

    return event;
};

For more information about working with Lambda Triggers for custom authentication challenge, please visit Amazon Cognito Developer Documentation.

Using a Custom Challenge

To initiate a custom authorization flow in your app, call signIn without a password. A custom challenge needs to be answered using the sendCustomChallengeAnswer method:

import { Auth } from 'aws-amplify';
let challengeResponse = "the answer for the challenge";

Auth.signIn(username)
    .then(user => {
        if (user.challengeName === 'CUSTOM_CHALLENGE') {
            Auth.sendCustomChallengeAnswer(user, challengeResponse)
                .then(user => console.log(user))
                .catch(err => console.log(err));
        } else {
            console.log(user);
        }
    })
    .catch(err => console.log(err));

Migrating Users to Amazon Cognito

Cognito provides a trigger to migrate users from your existing user directory to Cognito seamlessly. You configure your Cognito User Pool’s “Migration” trigger to invoke a Lambda function whenever a user that does not already exist in the user pool signs in or resets their password.

In short, the Lambda function should validate the user credentials against your existing user directory and return a response object containing user attributes and status on success, or an error message on error. There’s a good documentation here on how to set up this migration flow and a more detailed instruction here on how the lambda should handle request and response objects.

The default authentication flow encrypts the user password before it’s sent to Cognito, meaning your triggered Lambda won’t receive a user password that can be validated. If you want to be able to migrate users on signin, you need to configure your user pool and application to use the USER_PASSWORD_AUTH authentication flow. See section Switching Authentication Flow Type for instructions.

Working with User Attributes

You can pass user attributes during sign up:

Auth.signUp({
    'username': 'jdoe',
    'password': 'mysecurerandompassword#123',
    'attributes': {
        'email': 'me@domain.com',
        'phone_number': '+12128601234', // E.164 number convention
        'given_name': 'Jane',
        'family_name': 'Doe',
        'nickname': 'Jane'
    }
});

You can retrieve user attributes:

let user = await Auth.currentAuthenticatedUser();

You can update user attributes:

let result = await Auth.updateUserAttributes(user, {
    'email': 'me@anotherdomain.com',
    'family_name': 'Lastname'
});
console.log(result); // SUCCESS

If you change the email address, the user you will receive a confirmation code. In your app, you can confirm the verification code:

let result = await Auth.verifyCurrentUserAttributeSubmit('email', 'abc123');

Subscribing Events

You can take specific actions when users sign-in or sign-out by subscribing authentication events in your app. Please see our Hub Module Developer Guide for more information.

Working with AWS Service Objects

You can use AWS Service Interface Objects to work AWS Services in authenticated State. You can call methods on any AWS Service interface object by passing your credentials from Auth object to the service call constructor:

import Route53 from 'aws-sdk/clients/route53';

Auth.currentCredentials()
  .then(credentials => {
    const route53 = new Route53({
      apiVersion: '2013-04-01',
      credentials: Auth.essentialCredentials(credentials)
    });

    // more code working with route53 object
    // route53.changeResourceRecordSets();
  })

Full API Documentation for Service Interface Objects is available here.

Note: To work with Service Interface Objects, your Amazon Cognito users’ IAM role must have the appropriate permissions to call the requested services.

API Reference

For the complete API documentation for Authentication module, visit our API Reference

Customization

Customize UI Theme

AWS Amplify’s default UI components are theme based. To see the default styling, check AmplifyTheme.js for the related package in our repo.

You can create your own theme, and use it to render Amplify components:

import MyTheme from './MyTheme';

<Authenticator theme={MyTheme} />

Alternatively, you can import and override AmplifyTheme component in your code to apply style changes:

import { AmplifyTheme } from 'aws-amplify-react';

const MySectionHeader = Object.assign({}, AmplifyTheme.sectionHeader, { background: 'orange' });
const MyTheme = Object.assign({}, AmplifyTheme, { sectionHeader: MySectionHeader });

<Authenticator theme={MyTheme} />

A sample theme can be found here.

Create Your Own UI

To customize the default auth experience even more, you can create your own auth UI. To do this, your component will leverage the following Authenticator properties:

- authState
- authData
- onStateChange

The following example creates an ‘Always On’ Auth UI, which continuously shows the current auth state in your app.

import { Authenticator, SignIn, SignUp, ConfirmSignUp, Greetings } from 'aws-amplify-react';

const AlwaysOn = (props) => {
    return (
        <div>
            <div>I am always here to show current auth state: {props.authState}</div>
            <button onClick={() => props.onStateChange('signUp')}>Show Sign Up</button>
        </div>
    )
}

handleAuthStateChange(state) {
    if (state === 'signedIn') {
        /* Do something when the user has signed-in */
    }
}

render() {
    return (
        <Authenticator hideDefault={true} onStateChange={this.handleAuthStateChange}>
            <SignIn/>
            <SignUp/>
            <ConfirmSignUp/>
            <Greetings/>
            <AlwaysOn/>
        </Authenticator>
    )
}

Composing Your Own Authenticator

Authenticator is designed as a container for a number of Auth components. Each component does a single job, e.g., SignIn, SignUp, etc. By default, all of this elements are visible depending on the authentication state.

If you want to replace some or all of the Authenticator elements, you need to set hideDefault={true}, so the component doesn’t render its default view. Then you can pass in your own set of child components that listen to authState and decide what to do.

You can also pass the child components you want to use. For example, the following Authenticator configuration only renders Greetings component which has a Sign Out button:

<Authenticator hideDefault={true}>
    <Greetings />
</Authenticator>

Customize Greeting message

The Greetings component has two states: signedIn, and signedOut. To customize the greeting message, set properties inGreeting and outGreeting using a string or function.

<Authenticator hideDefault={true}>
    <Greetings
        inGreeting={(username) => 'Hello ' + username}
        outGreeting="Please sign in..."
    />
</Authenticator>

Customize withAuthenticator

The withAuthenticator HOC gives you some nice default authentication screens out-of-box. If you want to use your own components rather than the provided default components, you can pass the list of customized components to withAuthenticator:

import React, { Component } from 'react';
import { ConfirmSignIn, ConfirmSignUp, ForgotPassword, SignIn, SignUp, VerifyContact, withAuthenticator } from 'aws-amplify-react';

class App extends Component {
  render() {
    ...
  }
}

// This is my custom Sign in component
class MySignIn extends SignIn {
  render() {
    ...
  }
}

export default withAuthenticator(App, false, [
  <MySignIn/>,
  <ConfirmSignIn/>,
  <VerifyContact/>,
  <SignUp/>,
  <ConfirmSignUp/>,
  <ForgotPassword/>
]);

Customize Error Messages

During authentication flows, Amplify handles error messages returned from the server. Amplify provides a simple way of customizing those error messages with a messageMap callback.

The function takes the original message as arguments and then outputs the desired message. Check AmplifyMessageMap.js file to see how Amplify makes the map function.

const map = (message) => {
    if (/incorrect.*username.*password/i.test(message)) {
        return 'Incorrect username or password';
    }

    return message;
}

<Authenticator errorMessage={map} />

You may notice in AmplifyMessageMap.js it also handles internationalization. This topic is covered in our I18n Guide.

Customize Text Labels

You can change the text for the labels (like ‘Sign In’ and ‘Sign Up’) on the built-in user interface by providing your own dictionary to the localization engine:

import { I18n } from 'aws-amplify';

const authScreenLabels = {
    en: {
        'Sign Up': 'Create new account',
        'Sign Up Account': 'Create a new account'
    }
};

I18n.setLanguage('en');
I18n.putVocabularies(authScreenLabels);

Customize Initial authState

You can change the initial auth state for your Authenticator. By default the initial state is signIn which will shows the signIn component. If you want the signUp component shows first, you can do:

<Authenticator authState='signUp'>

Using Modular Imports

If you only need to use Auth, you can do: npm install @aws-amplify/auth which will only install the Auth module for you.

Then in your code, you can import the Auth module by:

import Auth from '@aws-amplify/auth';

Auth.configure();