## Using withAuthenticator HOC

For React Native, the simplest way to add authentication flows into your app is to use the `withAuthenticator` Higher 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 signin/signup controls are displayed.

> The default implementation uses the Amplify UI styling, for an example of what that looks like out of the box on web and mobile, see [here](https://ui.docs.amplify.aws/react/connected-components/authenticator).

Just add these two lines to your `App.js`:

```javascript
import { withAuthenticator } from 'aws-amplify-react-native';
import { Amplify } from 'aws-amplify';
// Get the aws resources configuration parameters
import awsconfig from './aws-exports'; // if you are using Amplify CLI

Amplify.configure(awsconfig);

// ...

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.

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

To display a sign-out button or customize other, 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. Other customization options are also available as properties to the HOC:

```jsx
export default withAuthenticator(App, {
  // Render a sign out button once logged in
  includeGreetings: true,
  // Show only certain components
  authenticatorComponents: [MyComponents],
  // display federation/social provider buttons
  federated: { myFederatedConfig },
  // customize the UI/styling
  theme: { myCustomTheme }
});
```

## Using the Authenticator Component

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

```jsx
<Authenticator
  // Optionally hard-code an initial state
  authState="signIn"
  // Pass in an already authenticated CognitoUser or FederatedUser object
  authData={CognitoUser | 'username'}
  // Fired when Authentication State changes
  onStateChange={(authState) => console.log(authState)}
  // An object referencing federation and/or social providers
  // The federation here means federation with the Cognito Identity Pool Service
  // *** Only supported on React/Web (Not React Native) ***
  // For React Native use the API Auth.federatedSignIn()
  federated={myFederatedConfig}
  // A theme object to override the UI / styling
  theme={myCustomTheme}
  // Hide specific components within the Authenticator
  // *** Only supported on React/Web (Not React Native)  ***
  hide={[
    Greetings,
    SignIn,
    ConfirmSignIn,
    RequireNewPassword,
    SignUp,
    ConfirmSignUp,
    VerifyContact,
    ForgotPassword,
    TOTPSetup,
    Loading
  ]}
  // or hide all the default components
  hideDefault={true}
  // Pass in an aws-exports configuration
  amplifyConfig={myAWSExports}
  // Pass in a message map for error strings
  errorMessage={myMessageMap}
>
  // Default components can be customized/passed in as child components. //
  Define them here if you used hideDefault={true}
  <Greetings />
  <SignIn federated={myFederatedConfig} />
  <ConfirmSignIn />
  <RequireNewPassword />
  <SignUp />
  <ConfirmSignUp />
  <VerifyContact />
  <ForgotPassword />
  <TOTPSetup />
  <Loading />
</Authenticator>
```

## Customize your own components

You can provide custom components to the `Authenticator` as child components in React and React Native.

```jsx
import { Authenticator, SignIn } from 'aws-amplify-react-native';

// The override prop tells the Authenticator that the SignUp component is not hidden but overridden
<Authenticator hideDefault={true}>
  <SignIn />
  <MyCustomSignUp override={'SignUp'} />
</Authenticator>;

class MyCustomSignUp extends Component {
  constructor() {
    super();
    this.gotoSignIn = this.gotoSignIn.bind(this);
  }

  gotoSignIn() {
    // to switch the authState to 'signIn'
    this.props.onStateChange('signIn', {});
  }

  render() {
    return (
      <div>
        {/* only render this component when the authState is 'signUp' */}
        {this.props.authState === 'signUp' && (
          <div>
            My Custom SignUp Component
            <button onClick={this.gotoSignIn}>Goto SignIn</button>
          </div>
        )}
      </div>
    );
  }
}
```

You can render the custom component (or not) based on the injected `authState` within your component as well as jump to other states within your component.

```jsx
if (props.onStateChange) props.onStateChange(state, data);
```

> **_The withFederated and Federated components are not supported on React Native_**. Use the API Auth.federatedSignIn() on React Native.

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

#### Wrapping your Component

This will render your App component with _Authenticator_:

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

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

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
 - requireNewPassword
 - verifyContact
 - signedIn
```

**authData** - additional data within authState; when the state is `signedIn`, it will return a [`CognitoUser`](https://github.com/aws-amplify/amplify-js/blob/main/packages/amazon-cognito-identity-js/index.d.ts#L48) object.

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

```javascript
this._validAuthStates = ['signedIn'];
```

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

## SignUp

The SignUp component provides your users with the ability to sign up. It is included as part of the `Authenticator` component.

Usage: `<Authenticator signUpConfig={ signUpConfig }/>`

It can also be used as part of the authentication HOC: `export default withAuthenticator(App, { signUpConfig });`

The SignUp Component accepts a 'signUpConfig' object which allows you to customize it.

import react0 from '/src/fragments/ui-legacy/auth/react/sign-up-attributes.mdx';

<Fragments fragments={{ react: react0 }} />

The signUpFields array in turn consist of an array of objects, each describing a field that will appear in sign up form that your users fill out:

import react1 from '/src/fragments/ui-legacy/auth/react/sign-up-fields.mdx';

<Fragments fragments={{ react: react1 }} />

A Sample signUpFields attribute would look like the following:

```js
const signUpConfig = {
  header: 'My Customized Sign Up',
  hideAllDefaults: true,
  defaultCountryCode: '1',
  signUpFields: [
    {
      label: 'My custom email label',
      key: 'email',
      required: true,
      displayOrder: 1,
      type: 'string'
    },
    ... // and other custom attributes
  ]
};

export default withAuthenticator(App, { signUpConfig });
```

## Sign up/in with email/phone number

If the user pool is set to allow email addresses/phone numbers as the username, you can then change the UI components accordingly by using `usernameAttributes` [(learn more about the setup)](https://docs.amplify.aws/lib/auth/getting-started/q/platform/js).

When you are using `email` as the username:

```js
import { withAuthenticator, Authenticator } from 'aws-amplify-react';

// When using Authenticator
class App {
  // ...

  render() {
    return <Authenticator usernameAttributes="email" />;
  }
}

export default App;

// When using withAuthenticator
class App2 {
  // ...
}

export default withAuthenticator(App2, { usernameAttributes: 'email' });
```

When you are using `phone number` as the username:

```js
import { Authenticator, withAuthenticator } from 'aws-amplify-react';

class App {
  // ...

  render() {
    return <Authenticator usernameAttributes="phone_number" />;
  }
}

export default App;

// When using withAuthenticator
class App2 {
  // ...
}

export default withAuthenticator(App2, { usernameAttributes: 'phone_number' });
```

**Note:** If you are using custom signUpFields to customize the `username` field, then you need to make sure either the label of that field is the same value you set in `usernameAttributes` or the key of the field is `username`.

For example:

```js
import React, { Component } from 'react';
import { Amplify } from 'aws-amplify';
import awsconfig from './aws-exports';
import { withAuthenticator } from 'aws-amplify-react';

Amplify.configure(awsconfig);

class App extends Component {}

const signUpConfig = {
  header: 'My Customized Sign Up',
  hideAllDefaults: true,
  defaultCountryCode: '1',
  signUpFields: [
    {
      label: 'My user name',
      key: 'username',
      required: true,
      displayOrder: 1,
      type: 'string'
    },
    {
      label: 'Password',
      key: 'password',
      required: true,
      displayOrder: 2,
      type: 'password'
    },
    {
      label: 'PhoneNumber',
      key: 'phone_number',
      required: true,
      displayOrder: 3,
      type: 'string'
    },
    {
      label: 'Email',
      key: 'email',
      required: true,
      displayOrder: 4,
      type: 'string'
    }
  ]
};
const usernameAttributes = 'My user name';

export default withAuthenticator(App, {
  signUpConfig,
  usernameAttributes
});
```
