Table Of Contents:
Welcome Back
In the previous article, we tackled adding users (in this case, using the Cognito user pool) and logging in to create and make requests to the GraphQL API (creating a new post, view existing posts etc.)
In this part, we’re going to implement the same thing in the Frontend and create/log users in legitimately using the app.
Sign-up
If you’ve cloned the app that I’m using for these examples, you’ll see that there are a lot of screens that we can use. In this case, we’ll be using the Signup screen to add a new user.
The idea behind this implementation is simple, we want to store values input by user (Email, Username, Password etc.) to be stored in a state and then use these values to make an authentication request.
If we take a moment to follow this link, we have already handled the amplify add auth
segment when we initiated amplify and explicitly mentioned that we need Cognito authentication, so we can skip this section and move to the Sign up, Sign in section linked here.
Copy the following code:
async function signUp() {
try {
const { user } = await Auth.signUp({
username,
password,
attributes: {
email, // optional
phone_number, // optional - E.164 number convention
// other custom attributes
}
});
console.log(user);
} catch (error) {
console.log('error signing up:', error);
}
}
...and paste it in the LoginScreen.js
file here:
const LoginScreen = ({ navigation }) => {
const [showLogin, setShowLogin] = useState(true);
const [formState, setFormState] = useState({});
[PASTE HERE]
useEffect(() => {
// clear formState when switching between login and signup
setFormState({});
}, [showLogin]);
Also, add import { Auth } from 'aws-amplify';
to the import list.
To get this to work, we need to get the username
and password
from the formState
. We already have this code set-up in the app, so add the following line of code to the signUp
function:
const {username, password, email} = formState;
Remove the optional phone number field and call the SignUp
API under the handleSubmit
function:
const handleSubmit = () => {
navigation.navigate(routes.Home);
if (showLogin) {
SignIn();
} else {
SignUp();
}
};
If you face an error at this stage of the project, make sure to do an
npm install
again and restart your app :). Also, theSignIn
API is added below.
The next steps are simple, just enter an email, a username, a password and click on the Signup button. The app will redirect you to the homepage and you can confirm the creation of the user in the Cognito User Pool. Also, remember to confirm the user in the dashboard to enable successful signing in.
Sign-in
In the same manner as above, copy the Sign In code below, destructure username
and password
here as well and call the API.
import { Auth } from 'aws-amplify';
async function signIn() {
Const { username, password } = formState;
try {
const user = await Auth.signIn(username, password);
} catch (error) {
console.log('error signing in', error);
}
}
Now, try signing in. Voila! Success.
Note: You can automate the confirmation of users through Triggers in the Cognito dashboard. Just copy this code:
exports.handler = (event, context, callback) => {
// Set the user pool autoConfirmUser flag after validating the email domain
event.response.autoConfirmUser = true;
callback(null, event);
};
...create a new Lambda Function:
...and paste it there. Save the function, go back to Cognito, follow the Triggers menu and select the recently created function. Save your changes and you’re good to go.
You can test this feature again by creating a new user. It’ll work, I swear.
Handling Navigation
Next up, we need to handle navigation, so that the user is redirected to the home screen upon successfully logging in.
Doing that is fairly simple. Go back to your SignIn()
function and add the following line:
navigation.navigate(routes.Home);
That’s it, really. Now when you log in the next time, the app will redirect you to the home screen on its own. You can use this to set up navigation throughout the app (Hint: Prolly direct the user to the Login screen after successfully signing up?)
There is a problem here. If you press the back button on an Android device, or swipe back on an iPhone, you’ll still be able to go back to the login screen.
Red flag!
We need to stop this behaviour. Now, there are multiple ways to do this in React Navigation, so let’s utilize one of them.
You can use the official docs [here] (reactnavigation.org/docs/auth-flow) to read through the methods.
The concept we will use is simple. We will use a plain ternary operation to manage what the user sees upon signing in/signing out. If the user signs in, they will be shown the isSignedIn
stack that comprises the home screen, the profile screen and the settings screen, otherwise the sign in/ sign up pages.
Here is the code:
isSignedIn ? (
<>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Profile" component={ProfileScreen} />
<Stack.Screen name="Settings" component={SettingsScreen} />
</>
) : (
<>
<Stack.Screen name="SignIn" component={SignInScreen} />
<Stack.Screen name="SignUp" component={SignUpScreen} />
</>
)
Copy the above code and direct yourself to the AppNavigation.js
file in the app code. Define isSignedIn
in the same file as follows:
const [isSignedIn, setIsSignedIn] = useState(false);
This means that isSignedIn
will initially be set as false
. When the user logs in, it will be set as true
, thanks to the ternary operator and the home screen will be shown (according to the code above).
The only issue with this solution right now is that the navigation is handled in a separate file, which makes it necessary to pass a context to the login screen, that will make sure the app knows to come back to AppNavigation.js
to look for logic.
Context File.
Let’s create a new file to add the context and call it AuthContext.js
. Add the following code to the file:
import React, { createContext, useState } from 'react';
export const AuthContext = createContext();
export default function AuthProvider({ children }) {
const [isSignedIn, setIsSignedIn] = useState(false);
const [user, setUser] = useState({});
return (
<AuthContext.Provider value={{ isSignedIn, setIsSignedIn, user, setUser }}>
{children}
</AuthContext.Provider>
);
}
In the above code, this component’s children will be able to access the boolean condition and change it when a user logs in. Now, we just need to import this context into the LoginScreen.js
file:
const { setIsSignedIn, setUser } = useContext(AuthContext);
Sign-out
We’ll handle the signout function the same way as we handled the sign-in function.
Copy the following code in the Header.js
file:
import { Auth } from 'aws-amplify';
async function signOut() {
try {
await Auth.signOut();
} catch (error) {
console.log('error signing out: ', error);
}
}
Don’t forget to import useContext
and the actual context in the file and set setIsSignedIn
to false
, so the app signs the user out after pressing the Signout button.
Preface to Part 3
In the final part of this series, we will start making requests to create, edit and fetch posts as well as check which users are currently signed in.
This experiment has been carried out by Sankhadeep Roy , Engineering Manager and AWS expert GeekyAnts and documented by Digvijay Wanchoo , A. Manager, Marketing & Communications GeekyAnts