Next.jsjavascriptfront-end

Secure and Performant Authorization with Firebase and Next.js

Picture of the author
Published on
Secure and Performant Authorization with Firebase and Next.js

Implementing a robust authorization system with Firebase and Next.js requires careful integration. Follow these steps to set up a secure and efficient flow.

1. Firebase Setup

Create and Configure a Firebase Project

  1. Create a Firebase Project:

    • Navigate to the Firebase Console.
    • Click "Add project" and follow the setup instructions.
  2. Enable Authentication:

    • In your project dashboard, click on "Authentication" in the left sidebar.
    • Activate the desired authentication methods (e.g., Email/Password, Google, etc.).
  3. Web App Configuration:

    • In the Firebase console, go to "Project settings".
    • Scroll down to "Your apps" and register a new web app.
    • Copy the provided Firebase config settings for later use.

2. Installing Dependencies

To get started, install Firebase and Next.js packages if they aren’t already installed.

npm install firebase next react-firebase-hooks

3. Firebase Configuration

Create a firebase.js file to initialize Firebase with your project settings.

// firebase.js
import firebase from 'firebase/app';
import 'firebase/auth';
import 'firebase/firestore';

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"
};

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

export default firebase;

4. Creating Custom Authentication Hooks

Develop a custom hook to manage authentication state using React Firebase Hooks.

// useAuth.js
import { useEffect, useState, useContext, createContext } from 'react';
import firebase from './firebase';
import { useAuthState } from 'react-firebase-hooks/auth';

const authContext = createContext();

export const AuthProvider = ({ children }) => {
  const auth = useProvideAuth();
  return <authContext.Provider value={auth}>{children}</authContext.Provider>;
};

export const useAuth = () => {
  return useContext(authContext);
};

function useProvideAuth() {
  const [user, loading, error] = useAuthState(firebase.auth());

  const signin = (email, password) => {
    return firebase.auth().signInWithEmailAndPassword(email, password);
  };

  const signup = (email, password) => {
    return firebase.auth().createUserWithEmailAndPassword(email, password);
  };

  const signout = () => {
    return firebase.auth().signOut();
  };

  return {
    user,
    loading,
    error,
    signin,
    signup,
    signout,
  };
}

5. Protecting Pages with Higher-Order Components

Use a higher-order component (HOC) to guard your pages against unauthorized access.

// withAuth.js
import { useAuth } from './useAuth';
import { useRouter } from 'next/router';
import { useEffect } from 'react';

const withAuth = (WrappedComponent) => {
  return (props) => {
    const { user, loading } = useAuth();
    const router = useRouter();

    useEffect(() => {
      if (!loading && !user) {
        router.push('/login');
      }
    }, [user, loading]);

    if (loading || !user) {
      return <p>Loading...</p>;
    }

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

export default withAuth;

6. Creating a Protected Page

Below is an example of a protected dashboard.js page using the withAuth HOC.

// pages/dashboard.js
import withAuth from '../withAuth';

const Dashboard = () => {
  return <h1>Welcome to Your Dashboard</h1>;
};

export default withAuth(Dashboard);

7. Developing a Login Page

Create a login.js page where users can authenticate themselves.

// pages/login.js
import { useState } from 'react';
import { useAuth } from '../useAuth';

const Login = () => {
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const { signin } = useAuth();

  const handleSubmit = async (e) => {
    e.preventDefault();
    try {
      await signin(email, password);
    } catch (error) {
      console.error('Failed to sign in:', error.message);
    };
  };

  return (
    <form onSubmit={handleSubmit}>
      <div>
        <label>Email:</label>
        <input
          type="email"
          value={email}
          onChange={(e) => setEmail(e.target.value)}
        />
      </div>
      <div>
        <label>Password:</label>
        <input
          type="password"
          value={password}
          onChange={(e) => setPassword(e.target.value)}
        />
      </div>
      <button type="submit">Login</button>
    </form>
  );
};

export default Login;

8. Wrapping Your App with AuthProvider

Ensure your entire application can access authentication state by wrapping it with the AuthProvider.

// pages/_app.js
import { AuthProvider } from '../useAuth';

function MyApp({ Component, pageProps }) {
  return (
    <AuthProvider>
      <Component {...pageProps} />
    </AuthProvider>
  );
}

export default MyApp;

9. Deployment and Testing

Double-check your Firebase settings and confirm that Firestore rules are set up correctly. Deploy your Next.js app and test the authentication and authorization workflows.


By following these steps, you are ensuring that your Next.js application is equipped with a secure and efficient authorization flow with Firebase, while maintaining best practices for SEO and performance.

Stay Tuned

Want to become a Next.js pro?
The best articles, links and news related to web development delivered once a week to your inbox.