Authentication in React with Next.js and TypeScript: A Step-by-Step Guide

Authentication is crucial for most web applications to ensure that users can securely access resources and keep their data private. In this guide, I’ll walk you through setting up authentication in a React application using Next.js with the latest App Router and TypeScript.

Step 1: Setting Up Your Next.js Project

First things first, make sure you have Node.js installed on your machine. Then, create a new Next.js project with TypeScript:

npx create-next-app@latest my-auth-app --typescript
cd my-auth-app

This command will scaffold a new Next.js project with TypeScript support out of the box.

Step 2: Install Necessary Packages

We’ll need some additional packages to handle authentication. For this guide, we’ll use next-auth, which is a popular authentication library for Next.js.

npm install next-auth @types/next-auth

Step 3: Set Up NextAuth.js

Create a new file at app/api/auth/[...nextauth]/route.ts. This file will handle the authentication logic using NextAuth.js.

import NextAuth from 'next-auth';
import GitHubProvider from 'next-auth/providers/github';

const handler = NextAuth({
  providers: [
    GitHubProvider({
      clientId: process.env.GITHUB_CLIENT_ID!,
      clientSecret: process.env.GITHUB_CLIENT_SECRET!,
    }),
    // Add more providers here
  ],
  callbacks: {
    async jwt({ token, user }) {
      if (user) {
        token.id = user.id;
      }
      return token;
    },
    async session({ session, token }) {
      session.user.id = token.id;
      return session;
    },
  },
});

export { handler as GET, handler as POST };

Don’t forget to add your GitHub client ID and secret in a .env.local file at the root of your project:

GITHUB_CLIENT_ID=your-github-client-id
GITHUB_CLIENT_SECRET=your-github-client-secret

Step 4: Add Authentication to Your App

Next, we’ll integrate the authentication logic into our React components. Let’s start by creating a simple navigation bar that displays the sign-in and sign-out links.

Create a new file components/NavBar.tsx:

'use client';

import { signIn, signOut, useSession } from 'next-auth/react';

const NavBar: React.FC = () => {
  const { data: session } = useSession();

  return (
    <nav>
      {session ? (
        <>
          <span>Welcome, {session.user?.name}!</span>
          <button onClick={() => signOut()}>Sign out</button>
        </>
      ) : (
        <button onClick={() => signIn()}>Sign in</button>
      )}
    </nav>
  );
};

export default NavBar;

Step 5: Protecting Pages

To ensure that only authenticated users can access certain pages, we’ll create a Higher Order Component (HOC). Create a file components/ProtectedRoute.tsx:

'use client';

import { useSession } from 'next-auth/react';
import { useRouter } from 'next/navigation';
import { useEffect } from 'react';

const ProtectedRoute: React.FC<{ children: React.ReactNode }> = ({ children }) => {
  const { data: session, status } = useSession();
  const router = useRouter();

  useEffect(() => {
    if (status === 'unauthenticated') {
      router.push('/api/auth/signin');
    }
  }, [status, router]);

  if (status === 'loading') {
    return <div>Loading...</div>;
  }

  return <>{session ? children : null}</>;
};

export default ProtectedRoute;

Now, you can wrap your protected pages with this HOC. For example, in app/dashboard/page.tsx:

import ProtectedRoute from '../../components/ProtectedRoute';

const Dashboard: React.FC = () => {
  return (
    <ProtectedRoute>
      <div>
        <h1>Dashboard</h1>
        <p>This is a protected page.</p>
      </div>
    </ProtectedRoute>
  );
};

export default Dashboard;

Step 6: Using the Session

To access the session data in any component, use the useSession hook. For example, in your app/page.tsx:

import { useSession } from 'next-auth/react';
import NavBar from '../components/NavBar';

const Home: React.FC = () => {
  const { data: session } = useSession();

  return (
    <div>
      <NavBar />
      <h1>Welcome to My Auth App</h1>
      {session ? <p>Signed in as {session.user?.email}</p> : <p>You are not signed in.</p>}
    </div>
  );
};

export default Home;

That’s it! You’ve set up authentication in your Next.js application using TypeScript. You now have a secure way for users to sign in and out, and you can protect your pages to ensure only authenticated users have access. Feel free to extend this setup with more providers or customize it further to fit your needs.

Happy coding!



Leave a Reply

Your email address will not be published. Required fields are marked *