Page updated Nov 15, 2023

Preview: AWS Amplify's new code-first DX (Gen 2)

The next generation of Amplify's backend building experience with a TypeScript-first DX.

Get started

Add authentication

The next feature you will be adding is authentication.

Authentication with Amplify

Amplify uses Amazon Cognito as its authentication provider. Amazon Cognito is a robust user directory service that handles user registration, authentication, account recovery & other operations. In this tutorial, you'll learn how to add authentication to your application using Amazon Cognito and username/password login.

Create authentication service

To add authentication to your app, run this command:

amplify add auth
1amplify add auth

Select the defaults for the following prompts:

? Do you want to use the default authentication and security configuration? Default configuration Warning: you will not be able to edit these selections. ? How do you want users to be able to sign in? Username ? Do you want to configure advanced settings? No, I am done.
1? Do you want to use the default authentication and security configuration? Default configuration
2Warning: you will not be able to edit these selections.
3? How do you want users to be able to sign in? Username
4? Do you want to configure advanced settings? No, I am done.

To deploy the service, run the push command:

amplify push
1amplify push

Now, the authentication service has been deployed and you can start using it. To view the deployed services in your project at any time, go to Amplify Console by running the following command:

amplify console
1amplify console

Create login UI

Now that you have your authentication service deployed to AWS, it's time to add authentication to your Angular app. Creating a login flow can be quite difficult and time consuming to get right. Luckily, Amplify UI has an Authenticator component that provides an entire authentication flow for you, using the configuration you specified in amplifyconfiguration.json.

Install Amplify UI

The @aws-amplify/ui-react-native package includes React Native specific UI components you'll use to build your app. Install it with the following command:

npm install @aws-amplify/ui-react-native react-native-get-random-values react-native-url-polyfill
1npm install @aws-amplify/ui-react-native react-native-get-random-values react-native-url-polyfill

Add the Amplify UI Authenticator component

Open App.js and make the following changes:

  1. Import the withAuthenticator Higher-Order Component and useAuthenticator hook:
import { withAuthenticator, useAuthenticator } from '@aws-amplify/ui-react-native';
1import {
2 withAuthenticator,
3 useAuthenticator
4} from '@aws-amplify/ui-react-native';
  1. Create a custom SignOutButton component that will be used within the App component and only re-render when its user context changes. Destructure the user and signOut properties returned from the hook.
// retrieves only the current value of 'user' from 'useAuthenticator' const userSelector = (context) => [context.user]; const SignOutButton = () => { const { user, signOut } = useAuthenticator(userSelector); return ( <Pressable onPress={signOut} style={styles.buttonContainer}> <Text style={styles.buttonText}> Hello, {user.username}! Click here to sign out! </Text> </Pressable> ); };
1// retrieves only the current value of 'user' from 'useAuthenticator'
2const userSelector = (context) => [context.user];
3
4const SignOutButton = () => {
5 const { user, signOut } = useAuthenticator(userSelector);
6 return (
7 <Pressable onPress={signOut} style={styles.buttonContainer}>
8 <Text style={styles.buttonText}>
9 Hello, {user.username}! Click here to sign out!
10 </Text>
11 </Pressable>
12 );
13};
  1. Add the SignOutButton component to your App component inside of the containers you defined in the last section:
// ... return ( <SafeAreaView style={styles.container}> <View style={styles.container}> <SignOutButton /> </View> </SafeAreaView> ); //...
1// ...
2return (
3 <SafeAreaView style={styles.container}>
4 <View style={styles.container}>
5 <SignOutButton />
6 </View>
7 </SafeAreaView>
8);
9//...
  1. Lastly, wrap your App export with the withAuthenticator Amplify UI component:
export default withAuthenticator(App);
1export default withAuthenticator(App);

Run the app to see the new authentication flow protecting the app:

npm start
1npm start

Now you should see the app load with an authentication flow allowing users to sign up and sign in. Below you can find a full sample of the code:

import React, { useEffect, useState } from 'react'; import { StyleSheet, Text, View, TextInput, Pressable, SafeAreaView } from 'react-native'; import { generateClient } from 'aws-amplify/api'; import { createTodo } from './src/graphql/mutations'; import { listTodos } from './src/graphql/queries'; import { withAuthenticator, useAuthenticator } from '@aws-amplify/ui-react-native'; import { Amplify } from 'aws-amplify'; import amplifyconfig from './src/amplifyconfiguration.json'; Amplify.configure(awsExports); // retrieves only the current value of 'user' from 'useAuthenticator' const userSelector = (context) => [context.user]; const SignOutButton = () => { const { user, signOut } = useAuthenticator(userSelector); return ( <Pressable onPress={signOut} style={styles.buttonContainer}> <Text style={styles.buttonText}> Hello, {user.username}! Click here to sign out! </Text> </Pressable> ); }; const initialFormState = { name: '', description: '' }; const client = generateClient(); const App = () => { const [formState, setFormState] = useState(initialFormState); const [todos, setTodos] = useState([]); useEffect(() => { fetchTodos(); }, []); function setInput(key, value) { setFormState({ ...formState, [key]: value }); } async function fetchTodos() { try { const todoData = await client.graphql({ query: listTodos }); const todos = todoData.data.listTodos.items; setTodos(todos); } catch (err) { console.log('error fetching todos'); } } async function addTodo() { try { if (!formState.name || !formState.description) return; const todo = { ...formState }; setTodos([...todos, todo]); setFormState(initialFormState); await client.graphql({ query: createTodo, variables: { input: todo } }); } catch (err) { console.log('error creating todo:', err); } } return ( <SafeAreaView style={styles.container}> <View style={styles.container}> <SignOutButton /> <TextInput onChangeText={(value) => setInput('name', value)} style={styles.input} value={formState.name} placeholder="Name" /> <TextInput onChangeText={(value) => setInput('description', value)} style={styles.input} value={formState.description} placeholder="Description" /> <Pressable onPress={addTodo} style={styles.buttonContainer}> <Text style={styles.buttonText}>Create todo</Text> </Pressable> {todos.map((todo, index) => ( <View key={todo.id ? todo.id : index} style={styles.todo}> <Text style={styles.todoName}>{todo.name}</Text> <Text style={styles.todoDescription}>{todo.description}</Text> </View> ))} </View> </SafeAreaView> ); }; export default withAuthenticator(App); const styles = StyleSheet.create({ container: { width: 400, flex: 1, padding: 20, alignSelf: 'center' }, todo: { marginBottom: 15 }, input: { backgroundColor: '#ddd', marginBottom: 10, padding: 8, fontSize: 18 }, todoName: { fontSize: 20, fontWeight: 'bold' }, buttonContainer: { alignSelf: 'center', backgroundColor: 'black', paddingHorizontal: 8 }, buttonText: { color: 'white', padding: 16, fontSize: 18 } });
1import React, { useEffect, useState } from 'react';
2import {
3 StyleSheet,
4 Text,
5 View,
6 TextInput,
7 Pressable,
8 SafeAreaView
9} from 'react-native';
10import { generateClient } from 'aws-amplify/api';
11import { createTodo } from './src/graphql/mutations';
12import { listTodos } from './src/graphql/queries';
13import {
14 withAuthenticator,
15 useAuthenticator
16} from '@aws-amplify/ui-react-native';
17
18import { Amplify } from 'aws-amplify';
19import amplifyconfig from './src/amplifyconfiguration.json';
20Amplify.configure(awsExports);
21
22// retrieves only the current value of 'user' from 'useAuthenticator'
23const userSelector = (context) => [context.user];
24
25const SignOutButton = () => {
26 const { user, signOut } = useAuthenticator(userSelector);
27 return (
28 <Pressable onPress={signOut} style={styles.buttonContainer}>
29 <Text style={styles.buttonText}>
30 Hello, {user.username}! Click here to sign out!
31 </Text>
32 </Pressable>
33 );
34};
35
36const initialFormState = { name: '', description: '' };
37const client = generateClient();
38
39const App = () => {
40 const [formState, setFormState] = useState(initialFormState);
41 const [todos, setTodos] = useState([]);
42
43 useEffect(() => {
44 fetchTodos();
45 }, []);
46
47 function setInput(key, value) {
48 setFormState({ ...formState, [key]: value });
49 }
50
51 async function fetchTodos() {
52 try {
53 const todoData = await client.graphql({
54 query: listTodos
55 });
56 const todos = todoData.data.listTodos.items;
57 setTodos(todos);
58 } catch (err) {
59 console.log('error fetching todos');
60 }
61 }
62
63 async function addTodo() {
64 try {
65 if (!formState.name || !formState.description) return;
66 const todo = { ...formState };
67 setTodos([...todos, todo]);
68 setFormState(initialFormState);
69 await client.graphql({
70 query: createTodo,
71 variables: { input: todo }
72 });
73 } catch (err) {
74 console.log('error creating todo:', err);
75 }
76 }
77
78 return (
79 <SafeAreaView style={styles.container}>
80 <View style={styles.container}>
81 <SignOutButton />
82 <TextInput
83 onChangeText={(value) => setInput('name', value)}
84 style={styles.input}
85 value={formState.name}
86 placeholder="Name"
87 />
88 <TextInput
89 onChangeText={(value) => setInput('description', value)}
90 style={styles.input}
91 value={formState.description}
92 placeholder="Description"
93 />
94 <Pressable onPress={addTodo} style={styles.buttonContainer}>
95 <Text style={styles.buttonText}>Create todo</Text>
96 </Pressable>
97 {todos.map((todo, index) => (
98 <View key={todo.id ? todo.id : index} style={styles.todo}>
99 <Text style={styles.todoName}>{todo.name}</Text>
100 <Text style={styles.todoDescription}>{todo.description}</Text>
101 </View>
102 ))}
103 </View>
104 </SafeAreaView>
105 );
106};
107
108export default withAuthenticator(App);
109
110const styles = StyleSheet.create({
111 container: { width: 400, flex: 1, padding: 20, alignSelf: 'center' },
112 todo: { marginBottom: 15 },
113 input: {
114 backgroundColor: '#ddd',
115 marginBottom: 10,
116 padding: 8,
117 fontSize: 18
118 },
119 todoName: { fontSize: 20, fontWeight: 'bold' },
120 buttonContainer: {
121 alignSelf: 'center',
122 backgroundColor: 'black',
123 paddingHorizontal: 8
124 },
125 buttonText: { color: 'white', padding: 16, fontSize: 18 }
126});

Using Amplify UI connected components makes it easier to manage styling across your entire app.