What is NextAuth and how to use it with Next.js and TypeScript
This beginner friendly guide explains what NextAuth is and shows how to set it up step-by-step in a Next.js + TypeScript project.
We will create a simple app that lets users sign in and sign out using GitHub OAuth.
1. What is NextAuth?
NextAuth.js is an authentication library made for Next.js.
It helps you add login systems easily without writing complex backend logic.
✅ Supports many providers: GitHub, Google, Facebook, etc.
✅ Handles sessions automatically
✅ Works with or without a database
✅ Easy to protect pages and APIs  
2. Project overview
We will create a simple project with:
- A home page (/)
- A protected page (/protected)
- GitHub login using NextAuth
- Navbar with sign in / sign out buttons
Folder structure:
my-nextauth-app/
├─ .env.local
├─ next.config.js
├─ package.json
├─ tsconfig.json
├─ pages/
│  ├─ api/
│  │  └─ auth/
│  │     └─ [...nextauth].ts
│  ├─ _app.tsx
│  ├─ index.tsx
│  └─ protected.tsx
└─ components/
   └─ Navbar.tsx
3. Create a Next.js TypeScript project
Open your terminal and run:
npx create-next-app@latest my-nextauth-app --typescript
cd my-nextauth-app
4. Install NextAuth
Run this command:
npm install next-auth
5. Setup environment variables
Create a file .env.local in your project root and add:
GITHUB_ID=your_github_client_id
GITHUB_SECRET=your_github_client_secret
NEXTAUTH_URL=http://localhost:3000
NEXTAUTH_SECRET=your_random_secret_key
You can get GITHUB_ID and GITHUB_SECRET by creating an OAuth App on GitHub:
- Go to GitHub → Settings → Developer Settings → OAuth Apps
- Create a new app
- Set the Authorization callback URL to
http://localhost:3000/api/auth/callback/github
6. Add NextAuth API route
Now, create a new file pages/api/auth/[...nextauth].ts and add this code:
import NextAuth from "next-auth";
import GithubProvider from "next-auth/providers/github";
import type { NextAuthOptions } from "next-auth";
export const authOptions: NextAuthOptions = {
  providers: [
    GithubProvider({
      clientId: process.env.GITHUB_ID || "",
      clientSecret: process.env.GITHUB_SECRET || "",
    }),
  ],
  session: {
    strategy: "jwt",
  },
  callbacks: {
    async jwt({ token, account, profile }) {
      if (account) {
        token.accessToken = account.access_token;
      }
      if (profile) {
        token.login = (profile as any).login; // Add GitHub username
      }
      return token;
    },
    async session({ session, token }) {
      session.accessToken = token.accessToken as string;
      (session.user as any).login = token.login;
      return session;
    },
  },
};
const handler = NextAuth(authOptions);
export { handler as GET, handler as POST };
7. Wrap the app with SessionProvider
In pages/_app.tsx, wrap your app with SessionProvider so that session data is available everywhere:
import type { AppProps } from "next/app";
import { SessionProvider } from "next-auth/react";
export default function App({
  Component,
  pageProps: { session, ...pageProps },
}: AppProps) {
  return (
    <SessionProvider session={session}>
      <Component {...pageProps} />
    </SessionProvider>
  );
}
8. Create Navbar component
Create a new file components/Navbar.tsx:
import { useSession, signIn, signOut } from "next-auth/react";
export default function Navbar() {
  const { data: session, status } = useSession();
  return (
    <nav
      style={{
        padding: "12px",
        borderBottom: "1px solid #ddd",
        display: "flex",
        justifyContent: "space-between",
        alignItems: "center",
      }}
    >
      <span style={{ fontWeight: "bold" }}>My App</span>
      {status === "loading" ? (
        <span>Loading...</span>
      ) : session ? (
        <div>
          <span style={{ marginRight: 12 }}>
            Signed in as {session.user?.name || (session.user as any).login}
          </span>
          <button onClick={() => signOut()}>Sign out</button>
        </div>
      ) : (
        <button onClick={() => signIn("github")}>Sign in with GitHub</button>
      )}
    </nav>
  );
}
9. Create Home page
Open pages/index.tsx and add this:
import Navbar from "../components/Navbar";
import Link from "next/link";
import { useSession } from "next-auth/react";
export default function Home() {
  const { data: session } = useSession();
  return (
    <div>
      <Navbar />
      <main style={{ padding: "16px" }}>
        <h1>Welcome to NextAuth Example</h1>
        {session ? (
          <>
            <p>Hello {session.user?.name || (session.user as any).login} 👋</p>
            <p>
              Go to your <Link href="/protected">Protected Page</Link>
            </p>
          </>
        ) : (
          <>
            <p>You are not signed in yet.</p>
            <p>Click “Sign in with GitHub” to continue.</p>
          </>
        )}
      </main>
    </div>
  );
}
10. Create Protected page (client-side)
Create pages/protected.tsx:
import Navbar from "../components/Navbar";
import { useSession } from "next-auth/react";
import { useRouter } from "next/router";
import { useEffect } from "react";
export default function Protected() {
  const { data: session, status } = useSession();
  const router = useRouter();
  useEffect(() => {
    if (status === "unauthenticated") {
      router.push("/");
    }
  }, [status, router]);
  if (status === "loading") {
    return (
      <>
        <Navbar />
        <main style={{ padding: "16px" }}>Loading...</main>
      </>
    );
  }
  return (
    <>
      <Navbar />
      <main style={{ padding: "16px" }}>
        <h1>Protected Page</h1>
        <p>This page is only for signed-in users.</p>
        <p>Welcome {session?.user?.name || (session?.user as any).login}</p>
      </main>
    </>
  );
}
11. Create Server-side Protected page (optional)
If you want to protect a page on the server side, create pages/ssr-protected.tsx:
import Navbar from "../components/Navbar";
import { getSession } from "next-auth/react";
import type { GetServerSideProps } from "next";
export default function SSRProtected({ session }: any) {
  return (
    <>
      <Navbar />
      <main style={{ padding: "16px" }}>
        <h1>Server Side Protected Page</h1>
        <p>Hello {session.user?.name || session.user?.login}</p>
      </main>
    </>
  );
}
export const getServerSideProps: GetServerSideProps = async (context) => {
  const session = await getSession(context);
  if (!session) {
    return {
      redirect: {
        destination: "/",
        permanent: false,
      },
    };
  }
  return {
    props: { session },
  };
};
12. How the authentication flow works
- The user clicks Sign in with GitHub.
- NextAuth redirects the user to GitHub OAuth.
- GitHub asks the user to authorize your app.
- GitHub sends the user back to your app with a token.
- NextAuth creates a session for the user.
- You can access user data using useSession()anywhere.
13. Common issues and fixes
❌ GitHub login fails
✅ Check your GITHUB_ID, GITHUB_SECRET, and callback URL.
❌ NEXTAUTH_SECRET missing
✅ Add NEXTAUTH_SECRET to your .env.local file.
❌ Callback URL mismatch
✅ Make sure the callback URL in GitHub matches
http://localhost:3000/api/auth/callback/github.
14. Summary
- NextAuth makes authentication easy in Next.js.
- Supports multiple providers like GitHub, Google, etc.
- Works both with and without databases.
- Simple hooks: useSession,signIn,signOut.
- Pages can be protected on the client or server side.
15. Quick setup steps
- 
npx create-next-app@latest my-nextauth-app --typescript
- 
npm install next-auth
- Add .env.localwith GitHub credentials
- Create pages/api/auth/[...nextauth].ts
- Wrap your app with SessionProvider
- Use signInandsignOutin your Navbar
- Protect pages with useSessionorgetSession
🎉 You did it!
You now have a working Next.js + NextAuth + TypeScript project.
You can extend it by:
- Adding Google login
- Using Prisma or MongoDB for database sessions
- Building a custom sign-in page
- Managing user roles and permissions
 
 
              
 
    
Top comments (0)