Next Auth
Note on Next Auth
What is next auth?
NextAuth is a library that lets you do authentication in Next.js
Can you do it w/o next-auth - Yes
Should you - Probably not!
Popoular choices while doing auth include -
- External provider -
- https://auth0.com/
- https://clerk.com/
- Firebase auth
- In house using cookies
- NextAuth
Why not use JWT + localstorage?
Next.js is slightly different from React + Express apps
Express app

NextJS app

NextAuth
Nextjs lets you add Authentication to your Next.js app
- It supports various
providers- Login with email
- Login with google
- Login with facebook
- …

Catch all routes
If you want to add a single route handler for
/api/auth/user/api/auth/random/api/auth/123/api/auth/...
You can create a catch all route
- Create a simple next.js app
npx create-next-app@latest
- Create
app/api/auth/[...nextauth]/route.ts
import { NextRequest, NextResponse } from "next/server"
export function GET(req: NextRequest) {
return NextResponse.json({
message: "Handler"
})
}
- Try going to a few endpoints
http://localhost:3000/api/auth/signin
http://localhost:3000/api/auth/123
http://localhost:3000/api/auth/random/random2
- Try logging the sub-route you’re at
import { NextRequest, NextResponse } from "next/server"
export function GET(req: NextRequest, { params }: { params: { nextauth: string[] } }) {
console.log(params.nextauth[0])
return NextResponse.json({
message: "Handler"
})
}
Give NextAuth access to a catch-all
Ref https://next-auth.js.org/configuration/initialization#route-handlers-app
- Create
/api/auth/[…nextauth]/route.ts - Install next-auth
npm install next-auth
- Updated handler
import NextAuth from "next-auth"
const handler = NextAuth({
...
})
export { handler as GET, handler as POST }
- Adding providers - There are three broad types of providers
- OAuth (Login with google)
- Email (Passwordless Email login via email OTP)
- Credentials (your own strategy)
Let’s them one by one
Credentials provider
This lets you create your own authentication strategy
For example
- Email + Password
- Phone number
- Login with Metamask
Steps to follow
- Add a credentials provider
import NextAuth from "next-auth"
import CredentialsProvider from 'next-auth/providers/credentials';
const handler = NextAuth({
providers: [
CredentialsProvider({
name: 'Credentials',
credentials: {
username: { label: 'email', type: 'text', placeholder: '' },
password: { label: 'password', type: 'password', placeholder: '' },
},
async authorize(credentials: any) {
return {
id: "user1"
};
},
})
],
secret: process.env.NEXTAUTH_SECRET
})
export { handler as GET, handler as POST }
- Add NEXTAUTH_URL to
.env
NEXTAUTH_URL=http://localhost:3000
NEXTAUTH_SECRET=password_nextauth
- Update
App.tsxto have a simple Appbar
"use client";
import { signIn, signOut } from "next-auth/react"
export const Appbar = () => {
return `<div>`
<button onClick={() => signIn()}>Signin`</button>`
<button onClick={() => signOut()}>Sign out`</button>`
`</div>`
}Click
- Add
providers.tsx
'use client';
import React from 'react';
import { SessionProvider } from 'next-auth/react';
export const Providers = ({ children }: { children: React.ReactNode }) => {
return (
`<SessionProvider>`
{children}
`</SessionProvider>`
);
};
- Wrap
layoutwithProviders
import { Providers } from "./provider";
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="en">
<body className={inter.className}>
`<Providers>`
{children}
`</Providers>`
`</body>`
`</html>`
);
}
- Get the user details in the top level
page.tsx(client component)
"use client"
import { useSession } from "next-auth/react";
export default function Home() {
const session = useSession();
return (
`<div>`
{JSON.stringify(session.data?.user)}
`</div>`
);
}
- Get the user details on the server (server component)
import { getServerSession } from "next-auth"
async function getUser() {
const session = await getServerSession();
return session;
}
export default async function Home() {
const session = await getUser();
return (
`<div>`
{JSON.stringify(session?.user?.name)}
`</div>`
);
}
- Get user in an api route (/api/user)
import { getServerSession } from "next-auth"
import { NextResponse } from "next/server";
export async function GET() {
const session = await getServerSession();
return NextResponse.json({
name: session?.user?.name
})
}
- Persist more data (user id) (Ref https://next-auth.js.org/getting-started/example#using-nextauthjs-callbacks) (Ref https://next-auth.js.org/configuration/callbacks)
callbacks: {
jwt: async ({ user, token }: any) => {
if (user) {
token.uid = user.id;
}
return token;
},
session: ({ session, token, user }: any) => {
if (session.user) {
session.user.id = token.uid
}
return session
}
},
- Move auth config to
lib/auth.tshttps://github.com/nextauthjs/next-auth/issues/7658#issuecomment-1683225019
import CredentialsProvider from 'next-auth/providers/credentials';
export const NEXT_AUTH_CONFIG = {
providers: [
CredentialsProvider({
name: 'Credentials',
credentials: {
username: { label: 'email', type: 'text', placeholder: '' },
password: { label: 'password', type: 'password', placeholder: '' },
},
async authorize(credentials: any) {
return {
id: "user1",
name: "asd",
userId: "asd",
email: "ramdomEmail"
};
},
}),
],
secret: process.env.NEXTAUTH_SECRET,
callbacks: {
jwt: async ({ user, token }: any) => {
if (user) {
token.uid = user.id;
}
return token;
},
session: ({ session, token, user }: any) => {
if (session.user) {
session.user.id = token.uid
}
return session
}
},
}
Final code -
https://github.com/100xdevs-cohort-2/week-16-auth-2
Adding Google Provider
Ref https://next-auth.js.org/providers/google
Adding Github provider
Ref - https://next-auth.js.org/providers/github
Custom Signup page
What if you want to change how your signup page looks
-
Add
pagesto next authRef - https://github.com/code100x/cms/blob/main/src/lib/auth.ts#L207
-
Add
app/signin/page.tsxRef - https://github.com/code100x/cms/blob/main/src/app/signin/page.tsx Ref - https://github.com/code100x/cms/blob/main/src/components/Signin.tsx#L39
"use client"
import { signIn } from 'next-auth/react';
import { useRouter } from 'next/navigation';
export default function() {
const router = useRouter();
return `<div>`
<button onClick={async () => {
await signIn("google");
}}>Login with google`</button>`
`<br />`
<button onClick={async () => {
await signIn("github");
}}>Login with Github`</button>`
`<br />`
<button onClick={async () => {
const res = await signIn("credentials", {
username: "",
password: "",
redirect: false,
});
console.log(res);
router.push("/")
}}>Login with email`</button>`
`</div>`
}
Final code -