Next.js 13 Authentication: Using GitHub OAuth with NextAuth.js in the App Route
NextAuth.js
NextAuth.js is an open-source authentication solution for Next.js applications. It simplifies the process of implementing authentication, including features like social logins (via OAuth providers like Google, Facebook, Twitter, etc.), email and password authentication, and more.
How to implement NextAuth.js into an app route in Next.js:
We will create a simple implementation of NextAuth.js in Next.js but by using the app route instead of the page route. So here is a step-by-step of the process:
Create a new Next.js project by writing this line in the terminal (since we are using the app route. use a Next.js version 13.2 or higher):
npx create-next-app@latest
(For the next steps, we will be following the NextAuth.js documentation in the link https://next-auth.js.org/getting-started/introduction since it will help us with the implementation).
Open the terminal of the project and print :
npm install next-auth
to install NextAuth in the project.
In this project, we will use GitHub as a sign-in method and also a username and password. So before you start to code, you need to provide 3 random codes. The first is that you need to set a NEXTAUTH_SECRET as an environment variable by generating a random code by printing this in the terminal:
$ openssl rand -base64 32
After obtaining the random code, copy it and save it to use later.
Returning to the NextAuth.js documentation, look into
configuration>providers
, you will find:
OAuth: is to sign in using Google, Facebook Github...etcEmail: is to sign in using email
credentials: is to sign in using a username and passwordYou need to use them depending on how you want the user to sign in to the web.
Since we are using GitHub to sign in, we will use OAuth. First, return to the NextAuth.js documentation and look into providers, you will find how to use each method of authentication (go to GitHub since that is what we are using).
Use the link in Configuration to create a new OAuth app for GitHub.(In the Homepage URL write
http://localhost:3000
since it is a dev environment and in the Authorization callback URL writehttp://localhost:3000/api/auth/callback/github
)After registering the application, you need to copy and save the client ID, and then generate a new client secret. Also, copy and save the newly generated client secret.
Create a
.env.local
file (it needs to be at the same level as thepackage.json
file) and in the file, write:NEXTAUTH_SECRET = 'paste the generated code' GITHUB_SECRET = 'paste the newly generated client secret' GITHUB_ID = 'paste the client ID'
(The GitHub client ID will always change every time you generate a new OAuth )
Now, we need to start coding by first creating a file in a new directory like this
/app/api/auth/[...nextauth]/route.ts
or if you have thesrc
directory, then it will be like/src/app/api/auth/[...nextauth]/route.ts
.In the
route.ts
file, write:import NextAuth from 'next-auth' import type { NextAuthOptions } from 'next-auth' // import each provider that you are going to use import GitHubProvider from 'next-auth/providers/github' import CredentialsProviders from 'next-auth/providers/credentials' // define the options object const options: NextAuthOptions = { providers: [ // this is were we put the providers we want to import and use in the application // in here we put the GitHub and Credentials providers since that is what we are using GitHubProvider({ // this is were we use the values that we wrote in the .env.local file clientId: process.env.GITHUB_ID as string, clientSecret: process.env.GITHUB_SECRET as string, }), // using credentials to give the user the ability to sign-in using a username and password CredentialsProviders({ name: "Credentials", credentials: { username:{ label: "Username: ", type: "text", placeholder: "Username" }, password:{ label: "Password: ", type: "Password", placeholder: "Password" } }, async authorize(credentials) { // in here you can write your own logic to retrieve tha data form the user database // to verify the credentials // i hardcoded a user since it's only for a simple project const user = { id:"2", name:"Dan", password:"11"} // here i wrote a simple way to verify the credentials if (credentials?.username === user.name && credentials?.password === user.password){ return user } else { return null } } }) ], } // only pass the options to NextAuth and it will do the rest const handler = NextAuth(options) // export the handler as GET and POST since NextAuth.js needs them export { handler as GET, handler as POST }
And now to actually use the authentication, we need to first create a sign-in button. Create a
SignInButton.tsx
file in the directory/src/app/SignInButton.tsx
. In the file, write:'use client' import { useSession, signIn, signOut } from 'next-auth/react' export default function SignInButton() { const { data: session } = useSession() if (session) { return ( <> Signed in as {session.user.email} <br /> <button onClick={() => signOut()}>Sign out</button> </> ) } return ( <> Not signed in <br /> <button onClick={() => signIn()}>Sign in</button> </> ) }
(I copied the code from the Getting Started page in the documentation with some minor changes).
On the
page.tsx
file in/src/app/page.tsx
, write:import SignInButton from './SignInButton' export default function Home() { return ( <div> <SignInButton /> </div> )}
Were in here you recall the SignInButton.
Create a
Providers.tsx
file in/src/app/Providers.tsx
and then write:'use client' import { SessionProvider } from 'next-auth/react' export default function Providers({ children }) { return ( <SessionProvider> {children} </SessionProvider> ) }
Here you are setting up a shared session state that can be accessed and managed across different parts of your application while using NextAuth.js for authentication.
The code is also available in the documents on the Getting Started page.Go to the layout.tsx page in the Next.js project then import the providers and wrap it around the children
import './globals.css' import type { Metadata } from 'next' import { Inter } from 'next/font/google' // here i imported the providors import Providers from './Providers' const inter = Inter({ subsets: ['latin'] }) export const metadata: Metadata = { title: 'Create Next App', description: 'Generated by create next app', } export default function RootLayout({ children, }: { children: React.ReactNode }) { return ( <html lang="en"> // and here i wraped the providers around the children prop <body className={inter.className}><Providers>{children}</Providers></body> </html> ) }
Running the app
After finishing all the steps, go ahead and run the app. The outcome will be on the first page:
Click the Sign in button to find:
Try to sign-in using GitHub, and when you're done, the page will change to:
It will show your email for GitHub and a Sign-out button that you can use to return to the Sign-in page.
It's obvious that this project is not user-experience-friendly, but that can be fixed by adding some changes to the SignInButton and the page and layout file.
Conclusion
The example provided demonstrates how to set up a basic authentication system using NextAuth.js and GitHub as authentication providers. However, it's important to note that the provided code is for demonstration purposes and may need further refinement for a production environment. Additionally, enhancing the user experience by customizing UI components and error handling would contribute to a more user-friendly application.
Overall, NextAuth.js is a powerful open-source authentication solution designed for Next.js applications. It simplifies the authentication process by offering features such as social logins, email and password authentication, and more.