M

Next.js 13 Authentication with NextAuth and Upstash Redis

Published: Jul 17, 2023

Authentication plays a crucial role in modern applications. And for Next.js developers, NextAuth.js emerges as a popular solution. It seamlessly integrates with Next.js and combines the speed and security of Upstash Redis, a serverless Redis database service. By leveraging this powerful duo, Next.js applications can achieve optimized and efficient authentication. In this post, we'll explore Next.js authentication with NextAuth.js and Upstash Redis.

Warning: Before moving forward, make sure you have installed Node.js (version ≥ 18) on your machine.

Setup Next.js App

Let’s create a Next.js app with App directory by using the following command:

npx create-next-app@latest nextauth-upstash-redis --typescript --tailwind

Now, our basic Next.js app has been created. Let’s add some necessary packages:

npm i next-auth @upstash/redis @auth/upstash-redis-adapter

Create Auth API route

Now, go to the app folder and create api/auth/[...nextauth]/route.ts inside the app folder. Paste the following code in the route.ts file:

api/auth/[...nextauth]/route.ts
import NextAuth from "next-auth";
import GithubProvider from "next-auth/providers/github";
import { UpstashRedisAdapter } from "@auth/upstash-redis-adapter";
import { Redis } from "@upstash/redis";
import { type Adapter } from "next-auth/adapters";
 
const redis = Redis.fromEnv();
 
const handler = NextAuth({
  adapter: UpstashRedisAdapter(redis) as Adapter,
  providers: [
    GithubProvider({
      clientId: process.env.GITHUB_CLIENT_ID as string,
      clientSecret: process.env.GITHUB_CLIENT_SECRET as string,
    }),
  ],
});
 
export { handler as GET, handler as POST };

Here we have implemented Auth API Endpoint with NextAuth and Upstash redis.

In 7th line, it takes env variables from .env file and creates redis client for our Upstash Redis Apdater and from 9th to 17th line, it creates our route handler using Github Provider and UpstashRedisAdapter.

Setup Env Variables

Now, We need to create .env file at the root of our app with the following:

.env
GITHUB_CLIENT_ID="GITHUB_CLIENT_ID"
GITHUB_CLIENT_SECRET="GITHUB_CLIENT_SECRET"
 
UPSTASH_REDIS_REST_URL="UPSTASH_REDIS_URL"
UPSTASH_REDIS_REST_TOKEN="UPSTASH_REDIS_TOKEN"

To get Github Provider credentials, go to https://github.com/settings/developers and create a new Oauth App like this:

Github OAuth App

after registering your app, you will get the Client ID and can generate the Client Secret by clicking on the generate new client secret button.

To get Upstash credentials, go to Upstash and create a new account if you don’t have any. Then create a new Redis database. now, go below and you will see a block named “REST API”, click on the .env tab and click copy icon at the right to copy the content.

Upstash Console

That’s it. Now, we need to do one more thing to start working on our app. and that is to move the authoption from our auth API route so that we can reuse it wherever we need it.

Create lib/auth.ts and paste the following:

lib/auth.ts
import GithubProvider from "next-auth/providers/github";
import { UpstashRedisAdapter } from "@auth/upstash-redis-adapter";
import { Redis } from "@upstash/redis";
import { type Adapter } from "next-auth/adapters";
 
const redis = Redis.fromEnv();
 
export const authOptions = {
  adapter: UpstashRedisAdapter(redis) as Adapter,
  providers: [
    GithubProvider({
      clientId: process.env.GITHUB_CLIENT_ID as string,
      clientSecret: process.env.GITHUB_CLIENT_SECRET as string,
    }),
  ],
};

Now, make the following changes in our Auth API route:

app/api/auth/[...nextauth]/route.ts
import NextAuth from "next-auth";
import { authOptions } from "@/lib/auth";
 
const handler = NextAuth(authOptions);
 
export { handler as GET, handler as POST };

Create Auth Page

Now, Let’s work on our homepage. Remove everything in the app/page.tsx file and paste the following:

app/page.tsx
import { getServerSession } from "next-auth";
import { authOptions } from "@/lib/auth";
 
export default async function Home() {
  const session = await getServerSession(authOptions);
  return (
    <main className="flex min-h-screen flex-col items-center bg-slate-900 text-gray-100 gap-y-20 p-24">
      <h1 className="md:leading-snug text-3xl max-w-[1000px] md:text-5xl  [&>a]:text-green-500 font-bold text-center">
        <a href="https://nextjs.org" target="_blank">
          Next.js
        </a>{" "}
        Authentication with{" "}
        <a href="https://next-auth.js.org/" target="_blank">
          NextAuth.js{" "}
        </a>{" "}
        +{" "}
        <a href="https://upstash.com/" target="_blank">
          Upstash Redis
        </a>
      </h1>
 
      {session ? (
        <div className="space-y-4">
          <div className="flex flex-col items-center gap-y-2">
            <div className="relative w-40 h-40">
              <Image
                fill
                src={session.user?.image as string}
                alt={session.user?.name as string}
              />
            </div>
            <span className="text-xl font-bold">{session.user?.name}</span>
            <span className="text-gray-400">{session.user?.email}</span>
          </div>
          <button
            className="bg-slate-800 w-full hover:bg-slate-700 text-gray-100 font-bold py-2 px-4 rounded"
            onClick={() => signOut()}
          >
            Sign out
          </button>
        </div>
      ) : (
        <button
          className="bg-slate-800 hover:bg-slate-700 text-gray-100 font-bold py-2 px-4 rounded"
          onClick={() => signIn("github")}
        >
          Sign in with GitHub
        </button>
      )}
    </main>
  );
}
  • Here we are getting the session using getServerSession and check if session is valid or not.
  • Then, if session is invalid, then show Sign In button.
  • If session is valid, then show User and Sign Out button.

Now, start dev server using npm run dev and visit http://localhost:3000 to see the preview.

Preview

If you have followed all the steps carefully, now your app should work perfectly.

Wrap Up

Check out the preview here. The code is available on GitHub.

If you face any trouble, please let me know on Twitter