framework/NextJS

๐Ÿ” Next.js App Router ์ธ์ฆ ๊ตฌํ˜„ ๊ฐ€์ด๋“œ

octo54 2025. 4. 30. 11:00
๋ฐ˜์‘ํ˜•

๐Ÿ” Next.js App Router ์ธ์ฆ ๊ตฌํ˜„ ๊ฐ€์ด๋“œ

Next.js App Router ๊ธฐ๋ฐ˜ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ์ธ์ฆ(Authentication) ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ •๋ฆฌํ–ˆ์Šต๋‹ˆ๋‹ค.
NextAuth.js, ๋ฏธ๋“ค์›จ์–ด, ์„ธ์…˜ ๊ด€๋ฆฌ ๋“ฑ ์‹ค์ „์—์„œ ๋ฐ”๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์ „๋žต ์œ„์ฃผ๋กœ ๊ตฌ์„ฑ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.


โœ… 1. ์ธ์ฆ์˜ ํ•ต์‹ฌ ๊ฐœ๋…

  • Authentication: ์‚ฌ์šฉ์ž์˜ ์‹ ์›์„ ํ™•์ธ (๋กœ๊ทธ์ธ)
  • Authorization: ๊ถŒํ•œ ๋ถ€์—ฌ (์ ‘๊ทผ ์ œ์–ด)
  • Session Management: ๋กœ๊ทธ์ธ ์ƒํƒœ ์œ ์ง€ (์ฟ ํ‚ค, JWT ๋“ฑ)

โœ… 2. NextAuth.js๋กœ ์ธ์ฆ ๊ตฌํ˜„ํ•˜๊ธฐ

์„ค์น˜

npm install next-auth

ํ™˜๊ฒฝ๋ณ€์ˆ˜ ์„ค์ • (.env)

NEXTAUTH_URL=http://localhost:3000
NEXTAUTH_SECRET=long-random-string

→ secret ๊ฐ’์€ openssl rand -base64 32 ๋ช…๋ น์–ด๋กœ ์ƒ์„ฑ ๊ฐ€๋Šฅ


API ๋ผ์šฐํŠธ ์ƒ์„ฑ

// app/api/auth/[...nextauth]/route.ts
import NextAuth from 'next-auth';
import GitHubProvider from 'next-auth/providers/github';

const handler = NextAuth({
  providers: [
    GitHubProvider({
      clientId: process.env.GITHUB_ID!,
      clientSecret: process.env.GITHUB_SECRET!,
    }),
  ],
});

export { handler as GET, handler as POST };

โœ… 3. ๋กœ๊ทธ์ธ/๋กœ๊ทธ์•„์›ƒ UI

๋ฐ˜์‘ํ˜•
// app/login/page.tsx
'use client';
import { signIn } from 'next-auth/react';

export default function LoginPage() {
  return (
    <div>
      <h2>๋กœ๊ทธ์ธ</h2>
      <button onClick={() => signIn('github')}>GitHub ๋กœ๊ทธ์ธ</button>
    </div>
  );
}
// app/dashboard/page.tsx
'use client';
import { signOut } from 'next-auth/react';

export default function DashboardPage() {
  return (
    <div>
      <h2>๋Œ€์‹œ๋ณด๋“œ</h2>
      <button onClick={() => signOut()}>๋กœ๊ทธ์•„์›ƒ</button>
    </div>
  );
}

โœ… 4. ์„ธ์…˜ ํ™•์ธ ๋ฐ ๋ฆฌ๋””๋ ‰์…˜

'use client';
import { useSession } from 'next-auth/react';
import { useEffect } from 'react';
import { useRouter } from 'next/navigation';

export default function Dashboard() {
  const { data: session, status } = useSession();
  const router = useRouter();

  useEffect(() => {
    if (status === 'unauthenticated') {
      router.push('/login');
    }
  }, [status]);

  if (status === 'loading') return <p>๋กœ๋”ฉ ์ค‘...</p>;

  return <div>ํ™˜์˜ํ•ฉ๋‹ˆ๋‹ค, {session?.user?.name}๋‹˜!</div>;
}

โœ… 5. ๋ผ์šฐํŠธ ๋ณดํ˜ธ ๋ฏธ๋“ค์›จ์–ด ์„ค์ •

// middleware.ts
import { NextRequest, NextResponse } from 'next/server';

export function middleware(req: NextRequest) {
  const token = req.cookies.get('next-auth.session-token');
  const isProtected = req.nextUrl.pathname.startsWith('/dashboard');

  if (isProtected && !token) {
    return NextResponse.redirect(new URL('/login', req.url));
  }

  return NextResponse.next();
}

export const config = {
  matcher: ['/dashboard/:path*'],
};

์ธ์ฆ๋œ ์‚ฌ์šฉ์ž๋งŒ ํŠน์ • ๊ฒฝ๋กœ ์ ‘๊ทผ ๊ฐ€๋Šฅํ•˜๊ฒŒ ๋งŒ๋“ญ๋‹ˆ๋‹ค.


โœ… 6. ๊ธฐํƒ€ ์ธ์ฆ ์†”๋ฃจ์…˜ ๋Œ€์•ˆ

์†”๋ฃจ์…˜ ํŠน์ง•

Auth0 OAuth, MFA, ๊ทœ์ • ์ค€์ˆ˜
Clerk UI/์„ธ์…˜ ํ†ตํ•ฉ ์ œ๊ณต
Supabase Firebase ๋Œ€์ฒด, ๋‚ด์žฅ ์ธ์ฆ
Firebase Google ์ƒํƒœ๊ณ„ ํ†ตํ•ฉ

๐Ÿ”— ์ฐธ๊ณ  ๋ฌธ์ž์—ด (URL)

https://nextjs.org/docs/app/guides/authentication


 

Next.js, App Router, ์ธ์ฆ ๊ตฌํ˜„, NextAuth, ๋กœ๊ทธ์ธ, OAuth, ์„ธ์…˜ ๊ด€๋ฆฌ, ๋ฏธ๋“ค์›จ์–ด ๋ณดํ˜ธ, ํด๋ผ์ด์–ธํŠธ ์ธ์ฆ, ๋ณด์•ˆ ์ „๋žต, SEO ์ตœ์ ํ™” 10๊ฐœ