Build the Create Post feature with image capture, preview, captions, and optimized performance.
In this chapter of our series, we’ll delve into setting up authentication for your social network app. Authentication is a fundamental component of any app, ensuring that user actions and data are tied to verified identities. Before diving into the technical details, it’s important to revisit Replyke and its role in authentication.
Accumulated reading time so far: 6 minutes.
Part 3 completed repo on GitHub for reference
Replyke is the backbone of our project, enabling seamless integration of various features like commenting, voting, and notification systems. A critical aspect of these features is associating actions and data with specific users, which is achieved through authentication. While we’ve already introduced Replyke in the tutorial’s introduction, this chapter marks the point where we begin setting up our Replyke project, as authentication is required to proceed further.
For the purposes of this tutorial, Replyke’s built-in authentication system is the most practical starting point. It allows us to move forward with minimal complexity and keeps the focus on building the app rather than getting bogged down in authentication details. Replyke supports email and password authentication, which is sufficient for getting the project off the ground.
If you prefer a more robust or specialized authentication system, or if you already have an existing one, you can easily integrate it later. Replyke is designed with flexibility in mind, making it straightforward to replace its built-in authentication with your own setup once the app is more developed. For now, I recommend sticking with Replyke’s authentication to simplify the process and keep things moving efficiently.
Authentication is crucial to set up at the start of the project because many features we’ll build rely on having a user system in place. Without it, our code would have significant gaps and missing parts, making development unnecessarily complex. Establishing authentication now ensures a solid foundation for building interactive features and avoids the need for major refactoring later.
Let’s get started with the technical setup!
Now, let’s set up Replyke in our project. Follow these steps to integrate Replyke and prepare for authentication:
Install Replyke for Expo: In your terminal run npx expo install replyke-expo
to install the latest version of Replyke for Expo. Note: looking at the GitHub references you might notice that the imports come from replyke-rn. Previously the React Native CLI package and the React Native Expo package were one, but not anymore. Use replyke-expo for Expo mangaed projects.
app/_layout
file, wrap your app’s content with the ReplykeProvider
from Replyke, passing in the project ID you just copied. This initializes Replyke within your app.ReplykeProvider
, include the TokenManager
with the expoManaged
flag. The TokenManager
does not need to wrap anything.With these steps completed, you’ve successfully set up Replyke in your project.
Here’s how the return statement of your layout file should look after making these changes:
<ReplykeProvider projectId={process.env.EXPO_PUBLIC_REPLYKE_PROJECT_ID!}>
<TokenManager expoManaged />
<SafeAreaProvider>
<SafeAreaView className="flex-1">
<Stack
screenOptions={{
headerShown: false,
}}
>
<Stack.Screen name="(tabs)" options={{ headerShown: false }} />
</Stack>
</SafeAreaView>
<StatusBar style="dark" />
</SafeAreaProvider>
</ReplykeProvider>
With this foundational setup complete, you’re now ready to proceed with implementing authentication using Replyke. Let’s continue!
Now that we’ve integrated Replyke into our project, it’s time to set up the authentication screens. These screens will allow users to sign in and sign up for your social network app. Follow these steps to create the necessary screens and understand their logic.
In your app
folder, create two new files:
sign-in.tsx
sign-up.tsx
Add the following code to each file respectively.
sign-in.tsx
:
import { Redirect, useRouter } from "expo-router";
import React, { useState } from "react";
import { View, Text, TextInput, TouchableOpacity } from "react-native";
import validator from "validator";
import { useAuth, useUser } from "replyke-expo";
const SignInScreen = () => {
const router = useRouter();
const { signInWithEmailAndPassword } = useAuth();
const { user } = useUser();
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [errors, setErrors] = useState({ email: "", password: "" });
const handleSignIn = async () => {
const newErrors = { email: "", password: "" };
if (!validator.isEmail(email)) {
newErrors.email = "Please enter a valid email.";
}
if (validator.isEmpty(password)) {
newErrors.password = "Password cannot be empty.";
}
setErrors(newErrors);
if (!newErrors.email && !newErrors.password) {
await signInWithEmailAndPassword?.({
email,
password,
});
}
};
if (user) return <Redirect href="/" />;
return (
<View className="flex-1 bg-white justify-center p-6">
<Text className="text-2xl font-bold text-center mb-6">Sign In</Text>
<TextInput
placeholder="Email"
keyboardType="email-address"
autoCapitalize="none"
value={email}
onChangeText={setEmail}
className={`border rounded-lg px-4 py-3 mb-2 text-gray-700 ${
errors.email ? "border-red-500" : "border-gray-300"
}`}
/>
{errors.email ? (
<Text className="text-red-500 text-sm mb-4">{errors.email}</Text>
) : null}
<TextInput
placeholder="Password"
secureTextEntry
value={password}
onChangeText={setPassword}
className={`border rounded-lg px-4 py-3 mb-2 text-gray-700 ${
errors.password ? "border-red-500" : "border-gray-300"
}`}
/>
{errors.password ? (
<Text className="text-red-500 text-sm mb-6">{errors.password}</Text>
) : null}
<TouchableOpacity
onPress={handleSignIn}
className="bg-blue-500 py-3 rounded-lg mb-4"
>
<Text className="text-white text-center font-medium">Log In</Text>
</TouchableOpacity>
<Text className="text-center text-gray-500 mb-4">
Don't have an account?{" "}
<Text
onPress={() => router.replace("/sign-up")}
className="text-blue-500 font-medium"
>
Sign up instead
</Text>
</Text>
<Text className="text-xs text-center text-gray-400 mt-auto">
By continuing, you agree to the{" "}
<Text className="text-blue-500 underline">terms and conditions</Text>{" "}
and our <Text className="text-blue-500 underline">privacy policy</Text>.
</Text>
</View>
);
};
export default SignInScreen;
sign-up.tsx
:
import { Redirect, useRouter } from "expo-router";
import React, { useState } from "react";
import { View, Text, TextInput, TouchableOpacity } from "react-native";
import validator from "validator";
import { useAuth, useUser } from "replyke-expo";
const SignUpScreen = () => {
const router = useRouter();
const { signUpWithEmailAndPassword } = useAuth();
const { user } = useUser();
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [confirmPassword, setConfirmPassword] = useState("");
const [errors, setErrors] = useState({
email: "",
password: "",
confirmPassword: "",
});
const handleSignUp = async () => {
const newErrors = { email: "", password: "", confirmPassword: "" };
if (!validator.isEmail(email)) {
newErrors.email = "Please enter a valid email.";
}
if (validator.isEmpty(password)) {
newErrors.password = "Password cannot be empty.";
} else if (password.length < 6) {
newErrors.password = "Password must be at least 6 characters long.";
}
if (password !== confirmPassword) {
newErrors.confirmPassword = "Passwords do not match.";
}
setErrors(newErrors);
if (!newErrors.email && !newErrors.password && !newErrors.confirmPassword) {
await signUpWithEmailAndPassword?.({ email, password });
}
};
if (user) return <Redirect href="/" />;
return (
<View className="flex-1 bg-white justify-center p-6">
<Text className="text-2xl font-bold text-center mb-6">Sign Up</Text>
<TextInput
placeholder="Email"
keyboardType="email-address"
autoCapitalize="none"
value={email}
onChangeText={setEmail}
className={`border rounded-lg px-4 py-3 mb-2 text-gray-700 ${
errors.email ? "border-red-500" : "border-gray-300"
}`}
/>
{errors.email ? (
<Text className="text-red-500 text-sm mb-4">{errors.email}</Text>
) : null}
<TextInput
placeholder="Password"
secureTextEntry
value={password}
onChangeText={setPassword}
className={`border rounded-lg px-4 py-3 mb-2 text-gray-700 ${
errors.password ? "border-red-500" : "border-gray-300"
}`}
/>
{errors.password ? (
<Text className="text-red-500 text-sm mb-4">{errors.password}</Text>
) : null}
<TextInput
placeholder="Confirm Password"
secureTextEntry
value={confirmPassword}
onChangeText={setConfirmPassword}
className={`border rounded-lg px-4 py-3 mb-2 text-gray-700 ${
errors.confirmPassword ? "border-red-500" : "border-gray-300"
}`}
/>
{errors.confirmPassword ? (
<Text className="text-red-500 text-sm mb-6">
{errors.confirmPassword}
</Text>
) : null}
<TouchableOpacity
onPress={handleSignUp}
className="bg-blue-500 py-3 rounded-lg mb-4"
>
<Text className="text-white text-center font-medium">Sign Up</Text>
</TouchableOpacity>
<Text className="text-center text-gray-500 mb-4">
Already have an account?{" "}
<Text
onPress={() => router.replace("/sign-in")}
className="text-blue-500 font-medium"
>
Sign in instead
</Text>
</Text>
<Text className="text-xs text-center text-gray-400 mt-auto">
By continuing, you agree to the{" "}
<Text className="text-blue-500 underline">terms and conditions</Text>{" "}
and our <Text className="text-blue-500 underline">privacy policy</Text>.
</Text>
</View>
);
};
export default SignUpScreen;
In your app/(tabs)/index.tsx
file, replace the content with the following:
import { useRouter } from "expo-router";
import { Button, View } from "react-native";
export default function HomeScreen() {
const router = useRouter();
return (
<View className="bg-red-500 flex-1 justify-center items-center">
<Button title="Sign in" onPress={() => router.navigate("/sign-in")} />
</View>
);
}
Sign-In Screen (sign-in.tsx
):
Sign-Up Screen (sign-up.tsx
):
Home Screen Update:
With these screens in place, your app now supports user authentication, creating a seamless entry point for users to access personalized features in your social network.
With these screens in place, your app now supports user authentication, creating a seamless entry point for users to access personalized features in your social network. You can try it out by signing up with a new account, and you’ll notice that upon successful sign-up, you are automatically authenticated and redirected back to the home screen.
However, the button on the home screen to navigate to the sign-in page will no longer work as expected because, whenever redirected to the sign-in page, you are immediately redirected back due to being logged in. To address this, and to allow you to explore the authentication flow further, we can add a simple sign-out button. This lets you log out and return to the sign-in page to test the functionality again.
Here’s how you can modify the HomeScreen
component to include a sign-out button:
import { useRouter } from "expo-router";
import { Button, View } from "react-native";
import { useAuth, useUser } from "replyke-expo";
export default function HomeScreen() {
const { signOut } = useAuth();
const { user } = useUser();
const router = useRouter();
return (
<View className="bg-red-500 flex-1 justify-center items-center gap-4">
{user ? (
<Button title="Sign out" onPress={signOut} />
) : (
<Button title="Sign in" onPress={() => router.navigate("/sign-in")} />
)}
</View>
);
}
With this small addition, you now have full control over the authentication flow, enabling you to sign in, sign out, and test the process repeatedly as you build and refine your app.
In the next chapter, we’ll shift gears and set up the essential structure of your app, including the screens, tab navigation, and utility functions that will support your app’s features moving forward. Stay tuned!
Don’t forget to join the Discord server where I post free boilerplate code repos for different types of social networks. Updates about the next article and additional resources will also be shared there. Lastly, follow me for updates here and on X/Twitter & BlueSky.
Powerful, self-serve product and growth analytics to help you convert, engage.
Dive into the heart of innovation with our 'Coding Chronicles' blog section. Explore a rich tapestry of articles, tutorials, and insights that unravel.