LeeYoonSam / auth-tutorial

NextAuth

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Learn how to add advanced authentication to your NextJS App.

Key Features:

  • ๐Ÿ” Next-auth v5 (Auth.js)
  • ๐Ÿš€ Next.js 14 with server actions
  • ๐Ÿ”‘ Credentials Provider
  • ๐ŸŒ OAuth Provider (Social login with Google & GitHub)
  • ๐Ÿ”’ Forgot password functionality
  • โœ‰๏ธ Email verification
  • ๐Ÿ“ฑ Two factor verification (2FA)
  • ๐Ÿ‘ฅ User roles (Admin & User)
  • ๐Ÿ”“ Login component (Opens in redirect or modal)
  • ๐Ÿ“ Register component
  • ๐Ÿค” Forgot password component
  • โœ… Verification component
  • โš ๏ธ Error component
  • ๐Ÿ”˜ Login button
  • ๐Ÿšช Logout button
  • ๐Ÿšง Role Gate
  • ๐Ÿ” Exploring next.js middleware
  • ๐Ÿ“ˆ Extending & Exploring next-auth session
  • ๐Ÿ”„ Exploring next-auth callbacks
  • ๐Ÿ‘ค useCurrentUser hook
  • ๐Ÿ›‚ useRole hook
  • ๐Ÿง‘ currentUser utility
  • ๐Ÿ‘ฎ currentRole utility
  • ๐Ÿ–ฅ๏ธ Example with server component
  • ๐Ÿ’ป Example with client component
  • ๐Ÿ‘‘ Render content for admins using RoleGate component
  • ๐Ÿ›ก๏ธ Protect API Routes for admins only
  • ๐Ÿ” Protect Server Actions for admins only
  • ๐Ÿ“ง Change email with new verification in Settings page
  • ๐Ÿ”‘ Change password with old password confirmation in Settings page
  • ๐Ÿ”” Enable/disable two-factor auth in Settings page
  • ๐Ÿ”„ Change user role in Settings page (for development purposes only)

ํด๋” ๋ฐ ํŒŒ์ผ ์š”์•ฝ

  • actions: "use server" ๋กœ ์„œ๋ฒ„ ์‚ฌ์ด๋“œ ๊ธฐ๋ฐ˜ ๋น„๋™๊ธฐ ์ž‘์—…์‹œ ์‹คํ–‰ ํ•  ์•ก์…˜
  • libs: ์ž์ฃผ ์‚ฌ์šฉํ•˜๋Š” ๊ธฐ๋Šฅ๋“ค์„ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌํ™”
  • data: ๋””๋น„ ์ •๋ณด๋ฅผ ์ด์šฉํ•ด์„œ ๋ฐ์ดํ„ฐ ์ œ๊ณต
  • hooks: ํด๋ผ์ด์–ธํŠธ ์‚ฌ์ด๋“œ์—์„œ ์‚ฌ์šฉ ํ•  hook
  • routes.ts: public, auth ๋“ฑ๋“ฑ Route ๊ด€๋ฆฌ
  • next-auth.d.ts: next-auth ์—์„œ ์‚ฌ์šฉ ํ•˜๋Š” session ์ปค์Šคํ…€
  • middleware.ts: ์ธ์ฆ ์‹œ ๋ฆฌ๋””๋ ‰ํŠธ ๊ด€๋ฆฌ
  • auth.ts: ๋กœ๊ทธ์ธ, ์„ธ์…˜, ์ธ์ฆ ์ฒ˜๋ฆฌ
  • auth.config.ts: ์ธ์ฆ ํ”„๋กœ๋ฐ”์ด๋” ์ œ๊ณต ๋ฐ ์ธ์ฆ ๋กœ์ง

Project setup

ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ - create-next-app

npx create-next-app@latest auth-tutorial
Need to install the following packages:
create-next-app@14.1.0
Ok to proceed? (y) y
โœ” Would you like to use TypeScript? โ€ฆ No / Yes
โœ” Would you like to use ESLint? โ€ฆ No / Yes
โœ” Would you like to use Tailwind CSS? โ€ฆ No / Yes
โœ” Would you like to use `src/` directory? โ€ฆ No / Yes
โœ” Would you like to use App Router? (recommended) โ€ฆ No / Yes
โœ” Would you like to customize the default import alias (@/*)? โ€ฆ No / Yes
Creating a new Next.js app in /Users/user/Documents/Github/auth-tutorial.

Using npm.

Initializing project with template: app-tw 


Installing dependencies:
- react
- react-dom
- next

Installing devDependencies:
- typescript
- @types/node
- @types/react
- @types/react-dom
- autoprefixer
- postcss
- tailwindcss
- eslint
- eslint-config-next


added 360 packages, and audited 361 packages in 24s

128 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities
Initialized a git repository.

Success! Created auth-tutorial at /Users/user/Documents/Github/auth-tutorial
  • shadcn-ui ์ถ”๊ฐ€
npx shadcn-ui@latest init
โœ” Which style would you like to use? โ€บ New York
โœ” Which color would you like to use as base color? โ€บ Slate
โœ” Would you like to use CSS variables for colors? โ€ฆ no / yes

โœ” Writing components.json...
โœ” Initializing project...
โœ” Installing dependencies...

Success! Project initialization completed. You may now add components.

dependencies

  • npx shadcn-ui@latest add button

Routing crash course

Index routes

  • ๋ผ์šฐํ„ฐ๋Š” ์ธ๋ฑ์Šค๋ผ๋Š” ์ด๋ฆ„์˜ ํŒŒ์ผ์„ ๋””๋ ‰ํ† ๋ฆฌ์˜ ๋ฃจํŠธ๋กœ ์ž๋™ ๋ผ์šฐํŒ…ํ•ฉ๋‹ˆ๋‹ค.
- pages/index.js โ†’ /
- pages/blog/index.js โ†’ /blog

Nested routes

  • ๋ผ์šฐํ„ฐ๋Š” ์ค‘์ฒฉ ํŒŒ์ผ์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. ์ค‘์ฒฉ๋œ ํด๋” ๊ตฌ์กฐ๋ฅผ ๋งŒ๋“ค๋ฉด ํŒŒ์ผ์ด ์ž๋™์œผ๋กœ ๋™์ผํ•œ ๋ฐฉ์‹์œผ๋กœ ๋ผ์šฐํŒ…๋ฉ๋‹ˆ๋‹ค.
pages/blog/first-post.js โ†’ /blog/first-post
pages/dashboard/settings/username.js โ†’ /dashboard/settings/username

Home page

  • app/globals.css ์ˆ˜์ •
    • ๊ธฐ๋ณธ ๋†’์ด 100% css ์ถ”๊ฐ€
  • app/page.tsx ์ˆ˜์ •
    • ๊ธฐ๋ณธ ํ™”๋ฉด ๊ตฌ์„ฑ ๋ฐ ๋กœ๊ทธ์ธ ๋ฒ„ํŠผ ์ถ”๊ฐ€
  • components/auth/login-button.tsx ์ƒ์„ฑ
    • ๋กœ๊ทธ์ธ ๋ฒ„ํŠผ ๋ž˜ํ•‘ ์ปดํฌ๋„ŒํŠธ
    • ํด๋ฆญ ์ปจํŠธ๋กค

Note

Gradient ์ ์šฉ ๋ฐฉ๋ฒ•

<main className="bg-[radial-gradient(ellipse_at_top,_var(--tw-gradient-stops))] from-sky-400 to-blue-800">
  • top ์ชฝ์€ from-sky-400 ๋ถ€ํ„ฐ ์•„๋ž˜๋กœ ์ƒ‰์ด ์ง„ํ•ด์ง
  • ์–‘์ชฝ ์‚ฌ์ด๋“œ๋Š” ์•ˆ์ชฝ์—์„œ ๋ถ€ํ„ฐ ๋ฐ”๊นฅ์œผ๋กœ from-sky-400 -> to-blue-800 ์œผ๋กœ ์ง„ํ•ด์ง

Card wrapper

์นด๋“œ ํ˜•ํƒœ์˜ ๋กœ๊ทธ์ธ ์ปดํฌ๋„ŒํŠธ ๊ตฌํ˜„

  • app/auth/login/page.tsx
    • ๋กœ๊ทธ์ธ ํผ
  • app/auth/layout.tsx
    • ๋กœ๊ทธ์ธ ๋ ˆ์ด์•„์›ƒ
  • components/auth/login-form.tsx
    • ๋กœ๊ทธ์ธ ํผ ์˜์—ญ ๊ตฌ์„ฑ
  • components/auth/card-wrapper.tsx
    • ์นด๋“œ๋ฅผ ๊ฐ์‹ธ๋Š” ๋ž˜ํผ
  • components/auth/back-buttons.tsx
    • ๋’ค๋กœ๊ฐ€๊ธฐ ๋ฒ„ํŠผ ์ปดํฌ๋„ŒํŠธ
  • components/auth/header.tsx
    • ํ—ค๋” ์ปดํฌ๋„ŒํŠธ
  • components/auth/social.tsx
    • ์†Œ์…œ ๋กœ๊ทธ์ธ ๋ฒ„ํŠผ

dependencies

  • npx shadcn-ui@latest add card
    • ์นด๋“œ ์ปดํฌ๋„ŒํŠธ
  • npm i react-icons
    • ๋ฆฌ์•กํŠธ ์•„์ด์ฝ˜ ํŒฉ

Login form

  • schemas/index.ts ์ถ”๊ฐ€
    • zod ์Šคํ‚ค๋งˆ ์ƒ์„ฑ
  • components/auth/login-form.tsx ์ˆ˜์ •
    • form ์ถ”๊ฐ€ ๋ฐ useForm
  • components/form-error.tsx ์ถ”๊ฐ€
    • form ์ž‘์„ฑ ์‹คํŒจ์‹œ ๋ณด์—ฌ์ค„ ์ปดํฌ๋„ŒํŠธ
  • components/form-success.tsx ์ถ”๊ฐ€
    • form ์ž‘์„ฑ ์„ฑ๊ณต์‹œ ๋ณด์—ฌ์ค„ ์ปดํฌ๋„ŒํŠธ

dependencies

  • npx shadcn-ui@latest add form
  • npx shadcn-ui@latest add input

Note

zod

  • Zod๋Š” TypeScript์™€ ์ž˜ ์–ด์šธ๋ฆฌ๋Š” ์Šคํ‚ค๋งˆ ์„ ์–ธ ๋ฐ ๊ฒ€์ฆ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ž…๋‹ˆ๋‹ค.
  • Zod๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ฐ์ดํ„ฐ ํƒ€์ž…์„ ํ•œ ๋ฒˆ ์„ ์–ธํ•˜๋ฉด Zod๊ฐ€ ์ž๋™์œผ๋กœ TypeScript ํƒ€์ž…์„ ์ถ”๋ก ํ•ด์ค๋‹ˆ๋‹ค.
  • Zod๋Š” ๊ฐ„๋‹จํ•œ ํƒ€์ž…์„ ๋ณต์žกํ•œ ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ๋กœ ์‰ฝ๊ฒŒ ์กฐํ•ฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • React Hook Form์€ React์—์„œ ์ž์ฃผ ์‚ฌ์šฉ๋˜๋Š” "์„ฑ๋Šฅ, ์œ ์—ฐ์„ฑ, ํ™•์žฅ์„ฑ์ด ๋›ฐ์–ด๋‚œ ํผ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ"์ž…๋‹ˆ๋‹ค.
  • React Hook Form์€ Zod์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, Zod๋ฅผ ํ†ตํ•ด ํผ ๋ฐ์ดํ„ฐ์˜ ์œ ํšจ์„ฑ์„ ๊ฒ€์‚ฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • Next.js 13์—์„œ๋Š” Server Actions๋ผ๋Š” ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์ด ์ถ”๊ฐ€๋˜์—ˆ๋Š”๋ฐ, ์ด๋Š” ์„œ๋ฒ„์—์„œ ํผ ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ณ  ์‘๋‹ต์„ ๋ณด๋‚ด๋Š” ๋ฐ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.

Register form

  • actions/login.ts ์ถ”๊ฐ€
    • ์Šคํ‚ค๋งˆ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ์— ๋”ฐ๋ผ์„œ ์„ฑ๊ณต/์‹คํŒจ ๋ฉ”์‹œ์ง€ ๋ฆฌํ„ด
  • actions/register.ts ์ถ”๊ฐ€
    • ์Šคํ‚ค๋งˆ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ์— ๋”ฐ๋ผ์„œ ์„ฑ๊ณต/์‹คํŒจ ๋ฉ”์‹œ์ง€ ๋ฆฌํ„ด
  • components/auth/login-form.tsx ์ˆ˜์ •
    • ๋กœ๊ทธ์ธ action ์—ฐ๊ฒฐ
    • success, error ์—ฐ๊ฒฐ
  • components/auth/register-form.tsx ์ถ”๊ฐ€
    • ํšŒ์›๊ฐ€์ž… ํผ ์ปดํฌ๋„ŒํŠธ
  • schemas/index.ts ์ˆ˜์ •
    • RegisterSchema ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ์ถ”๊ฐ€

Database & Prisma setup

  • lib/db.ts ์ƒ์„ฑ
    • prisma ํด๋ผ์ด์–ธํŠธ ์ƒ์„ฑ
  • Prisma ์ดˆ๊ธฐ ์„ค์ •
    • npx prisma init
  • Database ์—ฐ๋™
    • ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋Š” Neon Serverless Postgres ์‚ฌ์šฉ
    • Neon ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ
  • prisma/schema.prisma ์„ค์ •
    • database ์ •๋ณด ์„ค์ • (Neon postgre ์‚ฌ์šฉ)
    • model User ์ƒ์„ฑ
    • npx prisma generate - Prisma ํด๋ผ์ด์–ธํŠธ ์Šคํ‚ค๋งˆ ์ƒ์„ฑ
    • npx prisma db push - ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— Prisma ์Šคํ‚ค๋งˆ ๋™๊ธฐํ™”
  • auth/prisma-adapter ์—ฐ๊ฒฐ
    • prisma/schema.prisma ์ˆ˜์ •
      • User ์ˆ˜์ •
      • model Account ์ถ”๊ฐ€

dependencies

  • npm i -D prisma
  • npm i @prisma/client
  • npm i @auth/prisma-adapter

Create user

  • actions/register.ts ์ˆ˜์ •
    • ํšŒ์›๊ฐ€์ž… ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—ฐ๊ฒฐ
    • bcryptjs ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๋น„๋ฐ€๋ฒˆํ˜ธ hash ์ฒ˜๋ฆฌ
    • ์ค‘๋ณต ๊ฐ€์ž… ์—๋Ÿฌ ์ฒ˜๋ฆฌ
  • data/user.ts ์ƒ์„ฑ
    • email, id ๋กœ User ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ฐ์ดํ„ฐ ์ถ”๊ฐ€

dependencies

  • npm i bcryptjs
  • npm i -D @types/bcryptjs

Middleware & Login

  • npm install next-auth@beta
  • auth.ts ์ƒ์„ฑ
  • app/api/auth/[...nextauth]/route.ts ์ƒ์„ฑ
  • http://localhost:3000/api/auth/providers ํ”„๋กœ๋ฐ”์ด๋” ํ™•์ธ
    • AUTH_SECRET ์ƒ์„ฑ
      • npx auth secret
    • .env
      • ์ƒ์„ฑ๋œ AUTH_SECRET ์ถ”๊ฐ€
  • middleware ์ถ”๊ฐ€
    • middleware.ts ์ƒ์„ฑ
  • Edge compatibility
    • ์ธ์ฆ ๊ตฌ์„ฑ ๋ถ„ํ• 
    • NextAuth.js๋Š” ๋‘ ๊ฐ€์ง€ ์„ธ์…˜ ์ „๋žต์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. ์–ด๋Œ‘ํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ ์„ธ์…˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ €์žฅํ•˜๋„๋ก ์„ ํƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋ฐ ํ•ด๋‹น ์–ด๋Œ‘ํ„ฐ๊ฐ€ Edge ๋Ÿฐํƒ€์ž„/์ธํ”„๋ผ์™€ ํ˜ธํ™˜๋˜์ง€ ์•Š๋Š” ํ•œ "๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค" ์„ธ์…˜ ์ „๋žต์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.
    • auth.config.ts ์ƒ์„ฑ
      • next-auth ์—์„œ ์ œ๊ณตํ•˜๋Š” credentila ํ•จ์ˆ˜์˜ authorize ์ฝœ๋ฐฑ์„ ํ†ตํ•ด์„œ DB ์˜ ์œ ์ € ์ •๋ณด์™€ ๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ์ผ์น˜ํ•˜๋Š”์ง€ ๊ฒ€์ฆ
    • auth.ts ์ˆ˜์ •
      • authConfig, PrismaAdapter ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์ธ์ฆํ•˜๋„๋ก ์ˆ˜์ •
      • npm i @auth/prisma-adapter ์–ด๋Œ‘ํ„ฐ ์„ค์น˜
    • ๋ฏธ๋“ค์›จ์–ด๊ฐ€ ์—ฃ์ง€์™€ ํ˜ธํ™˜๋˜์ง€ ์•Š๋Š” ์–ด๋Œ‘ํ„ฐ๋กœ ๊ฐ€์ ธ์˜ค๊ธฐ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์ง€ ์•Š์€์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค:
      - export { auth as middleware } from './auth'
      + import authConfig from "./auth.config"
      + import NextAuth from "next-auth"
      + export const { auth: middleware } = NextAuth(authConfig)
      
  • app/(protected)/settings/page.tsx ์ƒ์„ฑ
    • ์ธ์ฆ ํ…Œ์ŠคํŠธ ํŽ˜์ด์ง€ ์ถ”๊ฐ€
  • routes.ts ์ƒ์„ฑ
    • publicRoutes, apiRoutes ๋“ฑ route ๊ด€๋ จ ์ •๋ณด ์ œ๊ณต
    • middleware.ts ์ˆ˜์ •
      • auth ์ฝœ๋ฐฑ ์ˆ˜์ •
        • ๋กœ๊ทธ์ธ ์œ ๋ฌด์— ๋”ฐ๋ผ์„œ ๋ฆฌ๋””๋ ‰ํŠธ ์ฒ˜๋ฆฌ
  • auth.ts ์ˆ˜์ •
    • signIn, signOut ์ถ”๊ฐ€
  • actions/login.ts ์ˆ˜์ •
    • ๋กœ๊ทธ์ธ ์•ก์…˜์— next-auth ์˜ signIn ์— credentials ํ”„๋กœ๋ฐ”์ด๋”๋กœ ๋กœ๊ทธ์ธ ์ฒ˜๋ฆฌ
    • ๋กœ๊ทธ์ธ ํ›„ settings ํŽ˜์ด์ง€ ๋ฆฌ๋””๋ ‰ํŠธ
  • app/(protected)/settings/page.tsx ์ˆ˜์ •
    • ๋กœ๊ทธ์•„์›ƒ ๊ตฌํ˜„
    • ๋กœ๊ทธ์•„์›ƒ ํ›„ ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€ ๋ฆฌ๋””๋ ‰ํŠธ
  • auth.ts ์ˆ˜์ •
    • NextAuth Callbacks ์ถ”๊ฐ€
      • session, jwt
  • prisma/schema.prisma ์ˆ˜์ •
    • UserRole ์ถ”๊ฐ€ (ADMIN, USER)
    • npx prisma generate
    • npx prisma migrate reset
    • npx prisma db push
  • next-auth.d.ts ์ƒ์„ฑ

Note

NextAuth - Callbacks

  • ์ฝœ๋ฐฑ์€ ๋™์ž‘์ด ์ˆ˜ํ–‰๋  ๋•Œ ๋ฐœ์ƒํ•˜๋Š” ์ƒํ™ฉ์„ ์ œ์–ดํ•˜๋Š” ๋ฐ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋น„๋™๊ธฐ ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค.
  • ์ฝœ๋ฐฑ์€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—†์ด ์•ก์„ธ์Šค ์ œ์–ด๋ฅผ ๊ตฌํ˜„ํ•˜๊ณ  ์™ธ๋ถ€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋˜๋Š” API์™€ ํ†ตํ•ฉํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ํŠนํžˆ JSON ์›น ํ† ํฐ๊ณผ ๊ด€๋ จ๋œ ์‹œ๋‚˜๋ฆฌ์˜ค์—์„œ ๋งค์šฐ ๊ฐ•๋ ฅํ•ฉ๋‹ˆ๋‹ค.

OAuth(Google & GitHub)

  • auth.config.ts ์ˆ˜์ •
  • components/auth/social.tsx ์ˆ˜์ •
    • ์†Œ์…œ ๋กœ๊ทธ์ธ์„ ์ง€์›ํ•˜๋„๋ก ์†Œ์…œ ๋กœ๊ทธ์ธ ๋ฒ„ํŠผ onClick ์ˆ˜์ •
  • ์†Œ์…œ ๊ณ„์ •๊ณผ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ์‚ฌ์šฉ์ž์™€์˜ ์—ฐ๊ฒฐ
    • auth.ts ์ˆ˜์ •
      • events: linkAccount ์ถ”๊ฐ€
        • ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค emailVerifed ํ•„๋“œ ๋ฐ์ดํ„ฐ ์ฑ„์›Œ์ง
      • pages ์ถ”๊ฐ€
        • ๋กœ๊ทธ์ธ, ์—๋Ÿฌ path ์ง€์ •
        • app/auth/error/page.tsx ์—๋Ÿฌ ํŽ˜์ด์ง€ ์ถ”๊ฐ€
          • components/auth/error-card.tsx ์—๋Ÿฌ ์ปดํฌ๋„ŒํŠธ ์นด๋“œ ์ถ”๊ฐ€
  • components/auth/login-form.tsx ์ˆ˜์ •
    • ์†Œ์…œ ๊ณ„์ • ์ด๋ฉ”์ผ ์ค‘๋ณต์‹œ ์—๋Ÿฌ ์ถ”๊ฐ€ (OAuthAccountNotLinked ์—๋Ÿฌ)

GitHub OAuth ์„ค์ •

  • GitHub(login) > Settings > Developer Settings > OAuth Apps > Register a new application
  • ์ƒˆ๋กœ์šด ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์ƒ์„ฑ๋˜๋ฉด clientId๋ฅผ ๋ฐ›์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • Client secrets > Generate a new client secret ์œผ๋กœ Secret ์ƒ์„ฑ

Google OAuth ์„ค์ •

  • google api console ๊ฒ€์ƒ‰
  • ์ƒ๋‹จ ํ”„๋กœ์ ํŠธ ์„ ํƒ > ์ƒˆ ํ”„๋กœ์ ํŠธ > ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ
  • APIs & Services ๊ฒ€์ƒ‰ or ๋ฉ”๋‰ด ํด๋ฆญ > OAuth consent screen(OAuth ๋™์˜ ํ™”๋ฉด)
    • External(์™ธ๋ถ€) ํƒ€์ž… ์„ ํƒ > ๋งŒ๋“ค๊ธฐ
    • ์•ฑ ์ด๋ฆ„, ์‚ฌ์šฉ์ž ์ง€์› ์ด๋ฉ”์ผ, ๊ฐœ๋ฐœ์ž ์—ฐ๋ฝ์ฒ˜ ์ •๋ณด ๋“ฑ ํ•„์ˆ˜ ์ •๋ณด ์ž…๋ ฅ ํ›„ ์ง„ํ–‰
    • ๋‚˜๋จธ์ง€ ๋‹จ๊ณ„๋Š” ๋ณ„๋‹ค๋ฅธ ์ž…๋ ฅ์—†์ด ํ†ต๊ณผ
  • Credentials
  • OAuth client created - Client ID, Client secret ๋งŒ๋“ค๊ธฐ ์™„๋ฃŒ
  • ํ…Œ์ŠคํŠธ๋ฅผ ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ํ…Œ์ŠคํŠธ ์‚ฌ์šฉ์ž ์ถ”๊ฐ€ ํ•„์š”

Note

OAuthAccountNotLinked ์—๋Ÿฌ ๋ฐœ์ƒ(์†Œ์…œ ๋กœ๊ทธ์ธ ์ด๋ฉ”์ผ ์ค‘๋ณต)

  • Social ๊ณ„์ •์œผ๋กœ ๋กœ๊ทธ์ธ ์‹œ ๊ฐ™์€ ์ด๋ฉ”์ผ์„ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ OAuthAccountNotLinked ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒ
    • ๋”ฐ๋กœ ์ฒ˜๋ฆฌํ•˜๋ ค๋ฉด ๋ณ„๋„์˜ ํŽ˜์ด์ง€๋ฅผ ๊ตฌํ˜„ํ•ด์„œ ์ฒ˜๋ฆฌ
    • ํ…Œ์ŠคํŠธ์‹œ์—๋Š” ๋””๋น„์— ๋ฐ์ดํ„ฐ๋ฅผ ์‚ญ์ œ ํ›„ ํ…Œ์ŠคํŠธ

Resend(Sending emails)

  • prisma/schema.prisma ์ˆ˜์ •
    • VerificationToken ๋ชจ๋ธ ์ถ”๊ฐ€
  • data/verification-token.ts ์ƒ์„ฑ
    • ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ email, token ์œผ๋กœ verification token ๊ฐ€์ ธ์˜ค๊ธฐ
  • lib/tokens.ts ์ƒ์„ฑ
    • ์ƒˆ๋กœ์šด ํ† ํฐ ์ƒ์„ฑ(๊ธฐ์กด ํ† ํฐ์ด ์žˆ์œผ๋ฉด ์‚ญ์ œ)
    • npm i uuid ์„ค์น˜
    • from "uuid" ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด npm i --save-dev @types/uuid ์„ค์น˜
  • actions/register.ts ์ˆ˜์ •
    • ํšŒ์› ๊ฐ€์ž…์‹œ ์ธ์ฆ ํ† ํฐ ์ƒ์„ฑ
  • actions/login.ts ์ˆ˜์ •
    • ๋กœ๊ทธ์ธ์‹œ ์ด๋ฉ”์ผ ์ธ์ฆ์ด ์•ˆ๋˜์–ด ์žˆ์„ ๊ฒฝ์šฐ ํ† ํฐ ์žฌ์ƒ์„ฑ ํ›„ ๋ฉ”์‹œ์ง€๋งŒ ์ „๋‹ฌ
  • lib/mail.ts ์ƒ์„ฑ
    • resend ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์ด๋ฉ”์ผ ์ „์†ก(ํ† ํฐ ์ธ์ฆ)
  • actions/register.ts | actions/login.ts ์ˆ˜์ •
    • ํšŒ์›๊ฐ€์ž…/๋กœ๊ทธ์ธ ์‹œ ์ด๋ฉ”์ผ ์ „์†ก
  • ์ด๋ฉ”์ผ ์ „์†ก ์„œ๋น„์Šค
  • ํšŒ์›๊ฐ€์ž… > ํŒ€ ๋งŒ๋“ค๊ธฐ > API Key ์ถ”๊ฐ€
  • npm install resend ์„ค์น˜
  • .env RESEND_API_KEY ์ถ”๊ฐ€

dependencies

  • npm i uuid
  • npm i --save-dev @types/uuid

Email verification

  • routes.ts ์ˆ˜์ •
    • public routes ์— ์ด๋ฉ”์ผ ์ธ์ฆ์‹œ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ๋กœ ์ถ”๊ฐ€
  • app/auth/new-verification/page.tsx ์ƒ์„ฑ
    • ์ด๋ฉ”์ผ ์ธ์ฆ ํŽ˜์ด์ง€
  • components/auth/new-verification-form.tsx ์ƒ์„ฑ
    • ์ด๋ฉ”์ผ ์ธ์ฆ ํผ
    • searchParmas ์˜ token ์œผ๋กœ ์ž๋™ ์ธ์ฆ ์ฒ˜๋ฆฌ
    • success, error ๋ฉ”์‹œ์ง€ ์ฒ˜๋ฆฌ
  • actions/new-verification.ts ์ƒ์„ฑ
    • ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ํ† ํฐ ์ •๋ณด์— ๋”ฐ๋ผ ์œ ํšจ์„ฑ ์ฒดํฌ
    • ์œ ํšจํ•œ ํ† ํฐ์ด๋ฉด ์œ ์ €์ •๋ณด ์—…๋ฐ์ดํŠธ

dependencies

  • npm i react-spinners

Reset password email

  • components/auth/login-form.tsx ์ˆ˜์ •
    • ๋น„๋ฐ€๋ฒˆํ˜ธ ์žฌ์„ค์ • ๋ฒ„ํŠผ ์ถ”๊ฐ€
    • ๋น„๋ฐ€๋ฒˆํ˜ธ ์žฌ์„ค์ • ํ™”๋ฉด ์ด๋™
  • routes.ts ์ˆ˜์ •
    • authRoutes ์— ๋น„๋ฐ€๋ฒˆํ˜ธ ์žฌ์„ค์ • path ์ถ”๊ฐ€
  • app/auth/reset/page.tsx ์ƒ์„ฑ
    • ๋น„๋ฐ€๋ฒˆํ˜ธ ์žฌ์„ค์ • ํ™”๋ฉด
  • components/auth/reset-form.tsx ์ƒ์„ฑ
    • ๋น„๋ฐ€๋ฒˆํ˜ธ ์žฌ์„ค์ • ํผ
  • schemas/index.ts ์ˆ˜์ •
    • ResetSchema ์ถ”๊ฐ€
  • actions/reset.ts ์ƒ์„ฑ
    • ์ด๋ฉ”์ผ ์žฌ์ „์†ก์„ ์œ„ํ•œ ์•ก์…˜
    • ์ด๋ฉ”์ผ ์œ ํšจ์„ฑ ์ฒดํฌ
    • ์ด๋ฉ”์ผ ์žฌ์ „์†ก
  • prisma/schema.prisma ์ˆ˜์ •
    • PasswordResetToken ๋ชจ๋ธ ์ถ”๊ฐ€
  • data/password-reset-token.ts ์ƒ์„ฑ
    • ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ passwordResetToken ๋ชจ๋ธ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ์—ญํ• 
  • lib/tokens.ts ์ˆ˜์ •
    • passwordResetToken ์—์„œ ์‚ฌ์šฉ ํ•  ํ† ํฐ ๋ฐ ์œ ํšจ๊ธฐ๊ฐ„ ๋ฐ์ดํ„ฐ ์ƒ์„ฑ
    • ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ํ† ํฐ ๋ฐ์ดํ„ฐ ์ตœ์‹ ํ™”
  • lib/mail.ts ์ˆ˜์ •
    • ํŒจ์Šค์›Œ๋“œ ์žฌ์„ค์ • ์ด๋ฉ”์ผ ๋ฐœ์†ก ์ถ”๊ฐ€

Reset password form

  • routes.ts ์ˆ˜์ •
    • authRoutes ์— /auth/new-password ์ถ”๊ฐ€
  • app/auth/new-password/page.tsx ์ƒ์„ฑ
    • ํŒจ์Šค์›Œ๋“œ ์žฌ์„ค์ • ํ™”๋ฉด
  • components/auth/new-password-form.tsx ์ƒ์„ฑ
    • ํŒจ์Šค์›Œ๋“œ ์žฌ์„ค์ • ํ™”๋ฉด ํผ
  • schemas/index.ts ์ˆ˜์ •
    • NewPasswordSchema ์ถ”๊ฐ€
  • actions/new-password.ts ์ƒ์„ฑ
    • ๋น„๋ฐ€๋ฒˆํ˜ธ ์žฌ์„ค์ • ํ™”๋ฉด์—์„œ ์‚ฌ์šฉ ํ•  ๋ฒ„ํŠผ ์•ก์…˜
    • ์œ ํšจ์„ฑ ์ฒดํฌ(๊ธธ์ด, ํ† ํฐ ๋งŒ๋ฃŒ, ํ† ํฐ ํŒŒ๋ผ๋ฏธํ„ฐ ๋“ฑ)
    • ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์œ ์ € ์—…๋ฐ์ดํŠธ, ์‚ฌ์šฉ ํ•œ ํ† ํฐ ์ œ๊ฑฐ

Two factor authentication

  • prisma/schema.prisma ์ˆ˜์ •
    • TwoFactorConfirmation ๋ชจ๋ธ ์ถ”๊ฐ€
    • TwoFactorToken ๋ชจ๋ธ ์ถ”๊ฐ€
    • User ๋ชจ๋ธ์— twoFactor ๊ด€๋ จ ํ•„๋“œ ์ถ”๊ฐ€
    • prisma
      • npx prisma generate
      • npx prisma migrate reset
      • npx prisma db push
  • data/two-factor-token.ts ์ƒ์„ฑ
    • token, email ๋กœ 2๋‹จ๊ณ„ ํ† ํฐ ์ •๋ณด ๊ฐ€์ ธ์˜ด
  • data/two-factor-confirmation.ts ์ƒ์„ฑ
    • ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ 2๋‹จ๊ณ„ ์ธ์ฆ ์ •๋ณด ๊ฐ€์ ธ์˜ด
  • lib/tokens.ts ์ˆ˜์ •
    • 2 ๋‹จ๊ณ„ ์ธ์ฆ์—์„œ ์‚ฌ์šฉํ•  ํ† ํฐ ์ƒ์„ฑ
    • crypto ๋‚ด์žฅ ํ•จ์ˆ˜ ์‚ฌ์šฉํ•ด์„œ ํ† ํฐ ์ƒ์„ฑ
  • lib/mail.ts ์ˆ˜์ •
    • 2๋‹จ๊ณ„ ์ธ์ฆ ๋ฉ”์ผ ์ „์†ก
  • auth.ts ์ˆ˜์ •
    • signIn ์ฝœ๋ฐฑ์— 2FA ์ธ์ฆ ์—…๋ฐ์ดํŠธ
  • actions/login.ts ์ˆ˜์ •
    • ๋กœ๊ทธ์ธ์‹œ 2FA ํ™œ์„ฑ ์ƒํƒœ ์ฒดํฌ ํ›„ ๋ถ„๊ธฐ
    • 2FA ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ •๋ณด ์‚ญ์ œ ๋ฐ ์˜ˆ์™ธ์ฒ˜๋ฆฌ ์ถ”๊ฐ€
  • components/auth/login-form.tsx ์ˆ˜์ •
    • 2FA ํ™œ์„ฑ/๋น„ํ™œ์„ฑํ™” UI ๋ณ€๊ฒฝ
    • 2FA ํ™œ์„ฑ ์ƒํƒœ์ผ๊ฒฝ์šฐ ์ด๋ฉ”์ผ๋กœ ์ฝ”๋“œ๋ฅผ ๋ฐ›์•„์„œ ๋กœ๊ทธ์ธ

User button

  • app/(protected)/settings/page.tsx ์ˆ˜์ •
    • useSession ํ›…์„ ํ†ตํ•ด์„œ ์„ธ์…˜ ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ค๋„๋ก ์ˆ˜์ •
  • app/layout.tsx ์ˆ˜์ •
    • Root ์— SessionProvider ์ถ”๊ฐ€ session ์ •๋ณด ์„ธํŒ…
  • actions/logout.ts ์ƒ์„ฑ
    • ๋กœ๊ทธ์•„์›ƒ ์ฒ˜๋ฆฌ
  • app/(protected)/layout.tsx ์ƒ์„ฑ
    • navbar ๋ฅผ ๊ฐ€์ง„ ์ƒ์œ„ ๋ ˆ์ด์•„์›ƒ ์ถ”๊ฐ€
  • app/(protected)/_components/navbar.tsx ์ƒ์„ฑ
    • ์„ค์ • ๋ฉ”๋‰ด ๋„ค๋น„๊ฒŒ์ด์…˜ ๋ฒ„ํŠผ
  • hooks/use-current-user.ts ์ƒ์„ฑ
    • useSession ์œผ๋กœ ํ˜„์žฌ ์œ ์ € ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ํ›… ์ƒ์„ฑ
  • components/auth/logout-button.tsx ์ƒ์„ฑ
    • ๋กœ๊ทธ์•„์›ƒ ์ปดํฌ๋„ŒํŠธ
  • components/auth/user-button.tsx ์ƒ์„ฑ
    • ์œ ์ € ์•„๋ฐ”ํƒ€ ์ปดํฌ๋„ŒํŠธ
    • ๋“œ๋กญ๋‹ค์šด ๋ฉ”๋‰ด ๊ตฌํ˜„
      • ๋กœ๊ทธ์•„์›ƒ

dependencies

  • npx shadcn-ui@latest add dropdown-menu
  • npx shadcn-ui@latest add avatar

Server & Client example

  • app/(protected)/server/page.tsx ์ƒ์„ฑ
    • ๋„ค๋น„๊ฒŒ์ด์…˜ Server ์—์„œ ๋ณด์—ฌ์ค„ ์œ ์ € ์ •๋ณด ํ™”๋ฉด
  • components/user-info.tsx ์ƒ์„ฑ
    • ์œ ์ € ์ •๋ณด ์ปดํฌ๋„ŒํŠธ
    • shadcn-ui Badge ์ถ”๊ฐ€
      • variant.success ํƒ€์ž… ์ถ”๊ฐ€
  • auth.ts ์ˆ˜์ •
    • jwt: ํ† ํฐ ์ •๋ณด์— isTwoFactorEnabled ์ •๋ณด ์ „๋‹ฌ
    • session: ํ† ํฐ ์ •๋ณด๋กœ session.user.isTwoFactorEnabled ์„ค์ •
  • next-auth.d.ts ์ˆ˜์ •
    • ExtendedUser.isTwoFactorEnabled ์ถ”๊ฐ€
  • app/(protected)/client/page.tsx ์ƒ์„ฑ
    • ์„œ๋ฒ„์™€ ๋™์ผํ•œ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ณต์‚ฌํ•ด์„œ Client ์œ ์ € ์ •๋ณด ํ™”๋ฉด ์ถ”๊ฐ€

dependencies

  • npx shadcn-ui@latest add badge

Admin example

  • app/(protected)/admin/page.tsx ์ƒ์„ฑ
    • ๊ด€๋ฆฌ์ž๋งŒ ์‚ฌ์šฉํ•˜๋Š” ํ™”๋ฉด
    • role-gate ๋กœ ๊ถŒํ•œ ๋ฉ”์‹œ์ง€ ํ‘œ์‹œ
    • ๊ด€๋ฆฌ์ž์šฉ ์•ก์…˜ ์ƒ์„ฑ
  • hooks/use-current-role.ts ์ƒ์„ฑ
    • role ๊ฐ€์ ธ์˜ค๋Š” hook ์ƒ์„ฑ
  • components/auth/role-gate.tsx ์ƒ์„ฑ
    • ๊ถŒํ•œ ๋ฉ”์‹œ์ง€ ์ปดํฌ๋„ŒํŠธ
  • app/api/admin/route.ts ์ƒ์„ฑ
    • ๊ด€๋ฆฌ์ž๊ฐ€ ์‚ฌ์šฉ ํ•  API
  • app/layout.tsx ์ˆ˜์ •
    • ์ƒ์œ„์— ์ถ”๊ฐ€ (sonner)

dependencies

  • npx shadcn-ui@latest add sonner : toast

Settings page

  • schemas/index.ts ์ˆ˜์ •
    • SettingsSchema ์ถ”๊ฐ€
  • app/(protected)/settings/page.tsx ์ˆ˜์ •
    • ์นด๋“œ ํ˜•ํƒœ ์ปดํฌ๋„ŒํŠธ ์ถ”๊ฐ€
    • ์œ ์ € ์ด๋ฆ„ ์—…๋ฐ์ดํŠธ
  • actions/settings.ts ์ƒ์„ฑ
    • ์„ธ์…˜์— ์ €์žฅ๋œ ์œ ์ €์ •๋ณด๋ฅผ ๊ฐ€์ ธ์™€์„œ ๋””๋น„ ์œ ์ € ์ •๋ณด ์กฐํšŒ ํ›„ name ์—…๋ฐ์ดํŠธ
  • auth.ts ์ˆ˜์ •
    • jwt ์ธ์ฆ์— ํ† ํฐ ์ •๋ณด(name, email) ์ถ”๊ฐ€
  • data/account.ts ์ƒ์„ฑ
    • ์œ ์ € ๊ณ„์ • ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” API
  • next-auth.d.ts ์ˆ˜์ •
    • isOAuth ํ•„๋“œ ์ถ”๊ฐ€

dependencies

  • npx shadcn-ui@latest add switch
  • npx shadcn-ui@latest add select

Deployment

  • Dialog ์ถ”๊ฐ€
  • actions/login.ts ์ˆ˜์ •
    • ์ฝœ๋ฐฑ URL ๋ฆฌ๋””๋ ‰ํŠธ ์ ์šฉ
  • middleware.ts ์ƒ์„ฑ
    • ์ฝœ๋ฐฑ URL ์ถ”๊ฐ€
  • components/auth/login-button.tsx ์ˆ˜์ •
    • modal Dialog ์ง€์›
  • components/auth/login-form.tsx ์ˆ˜์ •
    • ๋กœ๊ทธ์ธ ์•ก์…˜ ์ˆ˜์ •
  • components/auth/social.tsx ์ˆ˜์ •
    • ์ฝœ๋ฐฑ URL ๋ฐ›์•„์„œ ์ฒ˜๋ฆฌ
  • lib/mail.ts ์ˆ˜์ •
    • ํ•˜๋“œ์ฝ”๋”ฉ ๋„๋ฉ”์ธ ๋ณ€๊ฒฝ

๋ฐฐํฌ ํ›„ ์ž‘์—…

  • GitHub, Google API Authorized domain ๋ณ€๊ฒฝ

dependencies

  • npx shadcn-ui@latest add dialog

About

NextAuth


Languages

Language:TypeScript 98.2%Language:CSS 1.7%Language:JavaScript 0.2%