Day 04 Day 4

Day 4

Day 4

~1 hour Intermediate Hands-on Precision AI Academy

Today's Objective

A Next.js app with working GitHub OAuth login, a protected dashboard page that shows user info, and a database-backed session so users stay logged in across refreshes.

A Next.js app with working GitHub OAuth login, a protected dashboard page that shows user info, and a database-backed session so users stay logged in across refreshes.

Install and Configure NextAuth.js

NextAuth.js (now Auth.js) handles OAuth, JWT sessions, database sessions, and credential auth. It integrates directly with Next.js and requires minimal configuration for common providers.

terminal
BASH
npm install next-auth @auth/prisma-adapter
src/app/api/auth/[...nextauth]/route.ts
TYPESCRIPT
import NextAuth from 'next-auth'
import GithubProvider from 'next-auth/providers/github'
import { PrismaAdapter } from '@auth/prisma-adapter'
import { prisma } from '@/lib/prisma'

const handler = NextAuth({
  adapter: PrismaAdapter(prisma),
  providers: [
    GithubProvider({
      clientId: process.env.GITHUB_ID!,
      clientSecret: process.env.GITHUB_SECRET!,
    })
  ],
  callbacks: {
    session({ session, user }) {
      session.user.id = user.id  // add user ID to session
      return session
    }
  }
})

export { handler as GET, handler as POST }

Get Session in Server and Client Components

Use getServerSession() in Server Components and useSession() in Client Components. Wrap your app in SessionProvider to make client-side session available everywhere.

src/app/dashboard/page.tsx (Server Component)
TYPESCRIPT
import { getServerSession } from 'next-auth'
import { redirect } from 'next/navigation'

export default async function Dashboard() {
  const session = await getServerSession()

  if (!session) {
    redirect('/api/auth/signin')
  }

  return (
    <div>
      <h1>Welcome, {session.user?.name}</h1>
      <img src={session.user?.image ?? ''} alt="avatar" />
    </div>
  )
}
src/components/NavUser.tsx (Client Component)
TYPESCRIPT
'use client'
import { useSession, signIn, signOut } from 'next-auth/react'

export default function NavUser() {
  const { data: session, status } = useSession()

  if (status === 'loading') return <span>Loading...</span>
  if (session) return <button onClick={() => signOut()}>Sign Out</button>
  return <button onClick={() => signIn('github')}>Sign In</button>
}

Add Auth Models to Prisma Schema

The Prisma Adapter stores sessions and accounts in your database. Add the required models to your schema.

prisma/schema.prisma (add these models)
TEXT
model Account {
  id                String  @id @default(cuid())
  userId            String
  type              String
  provider          String
  providerAccountId String
  access_token      String?
  expires_at        Int?
  user              User    @relation(fields: [userId], references: [id], onDelete: Cascade)
  @@unique([provider, providerAccountId])
}

model Session {
  id           String   @id @default(cuid())
  sessionToken String   @unique
  userId       String
  expires      DateTime
  user         User     @relation(fields: [userId], references: [id], onDelete: Cascade)
}

// Update User model to add:
// accounts  Account[]
// sessions  Session[]

Credential Authentication

For email/password login, use the Credentials provider. Always hash passwords — never store them in plaintext.

auth config (credentials provider)
TYPESCRIPT
import CredentialsProvider from 'next-auth/providers/credentials'
import bcrypt from 'bcryptjs'

CredentialsProvider({
  name: 'credentials',
  credentials: {
    email: { label: 'Email', type: 'email' },
    password: { label: 'Password', type: 'password' }
  },
  async authorize(credentials) {
    if (!credentials?.email || !credentials.password) return null

    const user = await prisma.user.findUnique({
      where: { email: credentials.email }
    })

    if (!user?.password) return null

    const valid = await bcrypt.compare(credentials.password, user.password)
    return valid ? user : null
  }
})

Go Further on Your Own

Nice work. Keep going.

Day 5 is ready when you are.

Course Progress
80%

Want live instruction and hands-on projects? Join the AI bootcamp — 3 days, 5 cities.

What's Next

The foundations from today carry directly into Day 5. In the next session the focus shifts to Day 5 — building directly on everything covered here.

Supporting Videos & Reading

Go deeper with these external references.

Day 4 Checkpoint

Before moving on, verify you can answer these without looking:

Live Bootcamp

Learn this in person — 2 days, 5 cities

Thu–Fri sessions in Denver, Los Angeles, New York, Chicago, and Dallas. $1,490 per seat. June–October 2026.

Reserve Your Seat →
Continue To Day 5
Day 5