Published on

Auth.js: Session Management

Authors
  • avatar
    Name
    Shelton Ma
    Twitter

1. Signin and Signout

Signin

"use client"
import { signIn } from "next-auth/react"
 
export function SignIn() {
  return (
    <>
      <button onClick={() => signIn()}>Sign In</button>
      <button onClick={() => signIn("github", { redirectTo: "/dashboard" })}>
        Sign in with GitHub
      </button>
    </>
  )
}

Signout

"use client"
import { signOut } from "next-auth/react"
 
export function SignOut() {
  return <button onClick={() => signOut()}>Sign Out</button>
}

2. Get Session

1. Server component

import { auth } from "../auth"
 
export default async function UserAvatar() {
  const session = await auth()
 
  if (!session?.user) return null
 
  return (
    <div>
      <img src={session.user.image} alt="User Avatar" />
    </div>
  )
}

2. Next.js Client

  1. SessionProvider

    // layout.tsx
    import { SessionProvider } from "next-auth/react"
    import { Dashboard } from "./Dashboard"
    
    export default function Layout() {
      return (
        <SessionProvider>
          <Dashboard />
        </SessionProvider>
      )
    }
    
  2. useSession

    // 
    "use client"
    import { useSession } from "next-auth/react"
    
    export default function Dashboard() {
      const { data: session } = useSession()
    
      if (session?.user?.role === "admin") {
        return <p>You are an admin, welcome!</p>
      }
    
      return <p>You are not authorized to view this page!</p>
    }
    

3. Protecting Resources

1. Protect single page

import { auth } from "@/auth"

const session = await auth()
if (!session) return <div>Not authenticated</div>

// client
import { useSession } from "next-auth/react"
const { data: session } = useSession()

2. Middleware

  1. Create middleware

    // src/middleware.ts
    export { auth as middleware } from "@/auth"
    
    export const config = {
      matcher: ["/((?!api|_next/static|_next/image|favicon.ico).*)"],
    }
    
  2. Define authorized callback

    // src/auth.config.ts
    import NextAuth from "next-auth"
    
    export const { auth, handlers } = NextAuth({
      ...
      callbacks: {
        authorized: async ({ auth }) => {
          return !!auth
        },
      },
      ...
    })
    
  3. Or use the auth method as a wrapper

    // src/middleware.ts
    import { auth } from "@/auth"
    
    export default auth((req) => {
      if (!req.auth && req.nextUrl.pathname !== "/login") {
        const newUrl = new URL("/login", req.nextUrl.origin)
        return Response.redirect(newUrl)
      }
    })
    

4. Custom Pages

export const config = {
  providers: [GitHub],
  pages: {
    signIn: "/login",
  },
}

5. More config

  1. custom session

    session: {
      strategy: "jwt",
      maxAge: 30 * 24 * 60 * 60, // 30 days
      updateAge: 24 * 60 * 60, // 24 hours
    },
    
  2. callbacks

    callbacks: {
      session: async ({ session, token }) => {
        if (token.id) {
          session.user.id = token.id as string;
        }
        return session;
      },
      jwt: async ({ token, user }) => {
        if (user) {
          token.id = user.id;
        }
        return token;
      },
      redirect: async ({ url, baseUrl }) => {
        if (url.startsWith("/")) return `${baseUrl}${url}`;
        return baseUrl;
      },
    },