Next.js Functions

 

Implementing User Authentication in NEXT.js with Firebase

User authentication is a crucial aspect of modern web applications, enabling secure access and personalized experiences for users. If you’re developing a web application with NEXT.js, Firebase can be an excellent choice for handling user authentication due to its ease of use and robust features. In this tutorial, we’ll walk you through the process of implementing user authentication in your NEXT.js app using Firebase.

Implementing User Authentication in NEXT.js with Firebase

1. Prerequisites

Before we begin, make sure you have the following prerequisites in place:

  1. Basic knowledge of React and NEXT.js.
  2. Node.js and npm installed on your development machine.
  3. A Firebase account. If you don’t have one, sign up for free at firebase.google.com.

2. Setting up the NEXT.js Project

If you don’t have a NEXT.js project already, let’s set one up first. Open your terminal and execute the following commands:

bash
# Create a new NEXT.js project
npx create-next-app your-auth-app

# Navigate to the project directory
cd your-auth-app

Now that we have our project ready, let’s integrate Firebase into it.

3. Integrating Firebase in NEXT.js

3.1. Install Required Packages

To get started, we need to install the Firebase SDK and other necessary packages. In your project directory, run:

bash
npm install firebase

3.2. Set up Firebase Configurations

Next, create a new file called firebaseConfig.js inside a config folder in the root of your project. This file will contain your Firebase configuration details. Head over to the Firebase console, select your project, and click on the “Web” icon to add a new app. Register the app with the name you prefer (e.g., “NextApp”).

After registering, Firebase will provide you with a configuration object. Copy this object and paste it into firebaseConfig.js as follows:

javascript
// config/firebaseConfig.js

const firebaseConfig = {
  apiKey: "YOUR_API_KEY",
  authDomain: "YOUR_AUTH_DOMAIN",
  projectId: "YOUR_PROJECT_ID",
  storageBucket: "YOUR_STORAGE_BUCKET",
  messagingSenderId: "YOUR_MESSAGING_SENDER_ID",
  appId: "YOUR_APP_ID",
  measurementId: "YOUR_MEASUREMENT_ID",
};

export default firebaseConfig;

Remember to replace YOUR_API_KEY, YOUR_AUTH_DOMAIN, and other placeholders with your actual Firebase configuration values.

3.3. Initialize Firebase in the App

Now, we’ll create a Firebase initialization file that will connect our app to Firebase services. Create a new file named firebase.js in the config folder and add the following code:

javascript
// config/firebase.js

import firebase from "firebase/app";
import "firebase/auth";

import firebaseConfig from "./firebaseConfig";

if (!firebase.apps.length) {
  firebase.initializeApp(firebaseConfig);
}

export const auth = firebase.auth();

3.4. Create the Login Page

With Firebase integrated into our app, we can now create a simple login page to test the authentication flow. Create a new file called login.js inside the pages folder and add the following code:

jsx
// pages/login.js

import { useState } from "react";
import { auth } from "../config/firebase";

const LoginPage = () => {
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");
  const [error, setError] = useState("");

  const handleLogin = async (e) => {
    e.preventDefault();
    try {
      await auth.signInWithEmailAndPassword(email, password);
      // Login successful, redirect or do something else here
    } catch (err) {
      setError(err.message);
    }
  };

  return (
    <div>
      <h1>Login Page</h1>
      <form onSubmit={handleLogin}>
        <input
          type="email"
          value={email}
          onChange={(e) => setEmail(e.target.value)}
          placeholder="Email"
        />
        <input
          type="password"
          value={password}
          onChange={(e) => setPassword(e.target.value)}
          placeholder="Password"
        />
        <button type="submit">Login</button>
      </form>
      {error && <p>{error}</p>}
    </div>
  );
};

export default LoginPage;

In this code, we imported the auth object from firebase.js and used it to handle the login functionality. When the user submits the form, we call signInWithEmailAndPassword to authenticate the user with the provided email and password. If there’s an error during login, we display it on the page.

3.5. Create the Sign-Up Page

Let’s also create a sign-up page where new users can create their accounts. Create a new file called signup.js inside the pages folder and add the following code:

jsx
// pages/signup.js

import { useState } from "react";
import { auth } from "../config/firebase";

const SignupPage = () => {
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");
  const [error, setError] = useState("");

  const handleSignup = async (e) => {
    e.preventDefault();
    try {
      await auth.createUserWithEmailAndPassword(email, password);
      // Signup successful, redirect or do something else here
    } catch (err) {
      setError(err.message);
    }
  };

  return (
    <div>
      <h1>Sign Up Page</h1>
      <form onSubmit={handleSignup}>
        <input
          type="email"
          value={email}
          onChange={(e) => setEmail(e.target.value)}
          placeholder="Email"
        />
        <input
          type="password"
          value={password}
          onChange={(e) => setPassword(e.target.value)}
          placeholder="Password"
        />
        <button type="submit">Sign Up</button>
      </form>
      {error && <p>{error}</p>}
    </div>
  );
};

export default SignupPage;

The sign-up page works similarly to the login page. It uses the createUserWithEmailAndPassword method provided by Firebase’s authentication API to create a new user account with the given email and password.

3.6. Implementing Protected Routes

In many applications, you’ll have certain routes or pages that should only be accessible to authenticated users. We can create a higher-order component (HOC) to handle this functionality. Create a new file called withAuth.js in the utils folder and add the following code:

jsx
// utils/withAuth.js

import { useEffect } from "react";
import { useRouter } from "next/router";
import { auth } from "../config/firebase";

const withAuth = (WrappedComponent) => {
  const AuthenticatedComponent = (props) => {
    const router = useRouter();

    useEffect(() => {
      const unsubscribe = auth.onAuthStateChanged((user) => {
        if (!user) {
          router.push("/login");
        }
      });

      return () => unsubscribe();
    }, [router]);

    return <WrappedComponent {...props} />;
  };

  return AuthenticatedComponent;
};

export default withAuth;

The withAuth HOC in the utils folder listens for changes in the user’s authentication state using Firebase’s onAuthStateChanged method. If the user is not authenticated (i.e., not logged in), it redirects them to the login page.

3.7. Creating a Protected Page

Now that we have the withAuth HOC, let’s create a protected page that will only be accessible to authenticated users. Create a new file called dashboard.js inside the pages folder and add the following code:

jsx
// pages/dashboard.js

import withAuth from "../utils/withAuth";

const DashboardPage = () => {
  return (
    <div>
      <h1>Dashboard Page</h1>
      {/* Your dashboard content here */}
    </div>
  );
};

export default withAuth(DashboardPage);

In this code, we import the withAuth HOC and wrap the DashboardPage component with it. Now, when a user tries to access the dashboard page, they will be redirected to the login page if they are not authenticated.

3.8. Setting Up Navigation

To enable navigation between the login page, sign-up page, and the dashboard, we’ll set up a simple navigation bar. Create a new file called Navbar.js inside the components folder and add the following code:

jsx
// components/Navbar.js

import Link from "next/link";
import { auth } from "../config/firebase";

const Navbar = ({ user }) => {
  const handleLogout = async () => {
    try {
      await auth.signOut();
    } catch (err) {
      console.error("Error signing out:", err);
    }
  };

  return (
    <nav>
      <ul>
        {!user ? (
          <>
            <li>
              <Link href="/login">Login</Link>
            </li>
            <li>
              <Link href="/signup">Sign Up</Link>
            </li>
          </>
        ) : (
          <li>
            <button onClick={handleLogout}>Logout</button>
          </li>
        )}
        {user && (
          <li>
            <Link href="/dashboard">Dashboard</Link>
          </li>
        )}
      </ul>
    </nav>
  );
};

export default Navbar;

Here, we import the auth object from firebase.js to handle user authentication. The Navbar component displays different links based on whether the user is logged in or not. If the user is logged in, it shows a “Logout” button and a link to the dashboard; otherwise, it displays links to the login and sign-up pages.

3.9. Using the Navbar

Now, let’s use the Navbar component in our app. Open the pages/_app.js file and add the following code:

jsx
// pages/_app.js

import "../styles/globals.css";
import Navbar from "../components/Navbar";

function MyApp({ Component, pageProps }) {
  const user = null; // Replace this with your authentication state
  // You can use Firebase's onAuthStateChanged to set the user state

  return (
    <>
      <Navbar user={user} />
      <Component {...pageProps} />
    </>
  );
}

export default MyApp;

In this code, we imported the Navbar component and added it to the top of the app. You should replace the user variable with your actual authentication state. You can use Firebase’s onAuthStateChanged in the _app.js file to listen for changes in the user’s authentication state and update the user variable accordingly.

3.10. Testing the Authentication Flow

With everything set up, it’s time to test the authentication flow in your NEXT.js app with Firebase. Start your development server using the following command:

bash
npm run dev

Open your web browser and navigate to http://localhost:3000. You should see the navigation bar with “Login” and “Sign Up” links. Click on the “Sign Up” link and create a new account. After signing up, you’ll be redirected to the login page.

Now, log in using your newly created account, and you should be redirected to the dashboard page. If you try to access the dashboard page without logging in, you’ll be redirected to the login page.

Congratulations! You’ve successfully implemented user authentication in your NEXT.js app with Firebase.

Conclusion

User authentication is a critical aspect of modern web applications, providing secure access and personalized experiences for users. In this tutorial, we walked through the process of implementing user authentication in a NEXT.js app using Firebase. We covered setting up Firebase, creating login and sign-up pages, protecting routes, and implementing navigation.

Remember that security is a top priority when handling user authentication. Always follow best practices and ensure that your application is secure against common vulnerabilities.

Firebase provides additional features like social authentication, password recovery, and more. As your application grows, consider exploring these features to enhance your user authentication flow further.

I hope this tutorial has been helpful in getting you started with user authentication in NEXT.js using Firebase. Happy coding!

Previously at
Flag Argentina
Brazil
time icon
GMT-3
Accomplished Senior Software Engineer with Next.js expertise. 8 years of total experience. Proficient in React, Python, Node.js, MySQL, React Hooks, and more.