Auth0를 사용하여 NextJS 14 로그인을 구한하는 방법을 정리하였습니다.
Auth0 설정
- https://auth0.com/ 계정이 없다면, 회원 가입을 먼저 해야 합니다. (우측 상단
Sign up
클릭)
- 테넌트(Tenant)를 생성합니다. 테넌트 이름을 입력하고, 리즌을 선택합니다. 저는 Auth0에서 제공하는 리즌 중에 한국과 가장 가까운 Japan 리즌을 선택하였습니다.
테넌트 (Tenant)
SaaS(Software as a Service)에서 'Tenant' 개념은 아파트 건물에 비유될 수 있으며, 각각의 '세대'(테넌트)는 서로 독립된 공간을 가지는 다른 고객을 의미합니다. 이러한 구조는 데이터, 설정, 사용자 관리 등에서 테넌트 간에 서로 영향을 주지 않게 하며, 모든 테넌트는 같은 애플리케이션과 인프라를 공유하면서도 개별적으로 관리하고 맞춤 설정할 수 있습니다.
이 개념은 SaaS 환경에서 다양한 고객이 같은 서비스를 사용하면서도 각자의 데이터와 환경을 독립적으로 유지할 수 있게 하는 핵심 방식입니다. 이를 통해 SaaS 제공업체는 서비스를 효율적으로 확장하고 다양한 고객의 요구를 충족시킬 수 있습니다.
- 좌측 메뉴의
Applications
→Applications
→Create Application
클릭
- 어플리케이션 이름을 입력하고,
Regular Web Applications
을 선택후Create
를 클릭합니다.
- 생성된 어플리케이션의
Settings
탭으로 가서 Domain, Client ID, Client Secret를 기록해 둡니다.
- Settings에 필요한 설정을 추가 후
Save Changes
를 클릭하여 저장 합니다. - Allowed Callback URLs:
http://localhost:3000/api/auth/callback
- Allowed Logout URLs:
http://localhost:3000
로컬 개발에는
http://localhost:3000
주소를 설정하고, 스테이징이나 프로덕션 환경은 웹 앱 URL로 설정해야 합니다. Auth0는 테넌트별로 환경 분리하는 것을 추천합니다.
Auth0 대쉬보드 Settings
→ General
→ Environment Tag
에서 현재 테넌트의 환경 태그를 지정 할 수 있습니다. (Development | Staging | Production)NextJS 14 설정
새로운 NextJS 14 웹 앱을 생성합니다. (
nextjs-auth0-example
)npx create-next-app@latest nextjs-auth0-example --use-pnpm --ts --tailwind --eslint --app --no-src-dir --import-alias "@/*"
cd nextjs-auth0-example
Auth0 Next.js SDK를 설치 합니다.
pnpm install @auth0/nextjs-auth0
아래 커맨드로 Secret 문자열 생성해서 복사합니다.
openssl rand -hex 32
개발에 사용할 환경 변수를 설정합니다. Auth0 어플리케이션 Settings에서 복사한 Domain, Client ID, Client Secret을 입력합니다.
.env.local
파일
AUTH0_SECRET='use [openssl rand -hex 32] to generate a 32 bytes value' AUTH0_BASE_URL='http://localhost:3000' AUTH0_ISSUER_BASE_URL='https://<Auth0의 Domain>' AUTH0_CLIENT_ID='<Auth0의 Client ID>' AUTH0_CLIENT_SECRET='<Auth0의 Client Secret>'
app/api/auth/[auth0]/route.ts
에 파일을 생성합니다. 이 파일은 동적 경로 세그먼트가 있는 경로 핸들러 파일입니다.app/api/auth/[auth0]/route.ts
import { handleAuth } from '@auth0/nextjs-auth0'; export const GET = handleAuth();
그러면 다음과 같은 경로가 자동 생성됩니다:
/api/auth/login
: Auth0으로 로그인에 사용되는 경로입니다.
/api/auth/logout
: 로그아웃에 사용되는 경로입니다.
/api/auth/callback
: 로그인 성공 후 사용자를 리디렉션하는 경로입니다.
/api/auth/me
: 사용자 프로필을 가져오는 경로입니다.
UserProvider 컴포넌트 추가
프론트엔드는 React 컨텍스트를 사용하여 사용자의 인증 상태를 관리합니다. 모든 페이지에서 해당 상태를 사용할 수 있게 하려면 루트 레이아웃 컴포넌트를 재정의하고
app/layout.tsx
파일에서 <body>
태그를 UserProvider
로 래핑해야 합니다.app/layout.tsx
import { UserProvider } from '@auth0/nextjs-auth0/client'; import type { Metadata } from "next"; import { Inter } from "next/font/google"; import "./globals.css"; const inter = Inter({ subsets: ["latin"] }); export const metadata: Metadata = { title: "Create Next App", description: "Generated by create next app", }; export default function RootLayout({ children, }: Readonly<{ children: React.ReactNode; }>) { return ( <html lang="en"> <UserProvider> <body className={inter.className}>{children}</body> </UserProvider> </html> ); }
로그인 버튼 추가
이제 사용자는 SDK에서 제공하는
/api/auth/login
경로를 방문하여 애플리케이션에 로그인할 수 있습니다. 앵커 태그(<a>
태그)를 사용하여 로그인 경로를 가리키는 링크를 추가합니다. 이 링크를 클릭하면, Auth0이 사용자를 인증할 수 있는 Auth0 유니버설 로그인 페이지로 리디렉션됩니다. 인증에 성공하면 Auth0은 사용자를 애플리케이션으로 다시 리디렉션합니다.app/page.tsx
export default function Home() { return ( <main className="flex min-h-screen flex-col items-center justify-between p-24"> <div className="z-10 max-w-5xl w-full items-center justify-between font-mono text-sm lg:flex"> <button className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"> <a href='/api/auth/login'>Login</a> </button> (......)
로그인 필요한 페이지
로그인을 해야 접근이 가능하고, 로그인시 첫 화면인
/dashboard
페이지를 만들어봅시다.app/dashboard/page.tsx
export default function DashbaordPager() { return <div>로그인이 필요한 대쉬보드 페이지 입니다.</div>; }
홈 화면에서 세션을 확인하여, 로그인 상태면 대쉬보드 페이지로 넘어가는 로직을 추가하겠습니다.
app/page.tsx
import { getSession } from '@auth0/nextjs-auth0'; import { redirect } from "next/navigation"; export default async function Home() { const session = await getSession(); if (session?.user) { // 로그인 세션이 있으면 "/dashboard" 경로로 리디렉션 redirect("/dashboard"); } return ( (......) ); }
대쉬보드 페이지에 접속시 로그인 사용자 정보 출력과 로그아웃 버튼을 추가합니다.
app/dashboard/page.tsx
import { getSession } from '@auth0/nextjs-auth0'; export default async function DashbaordPager() { const session = await getSession(); return <div> {!!session?.user && ( <div> <p>안녕하세요. {session.user.name} 님! 👋</p> </div> )} 로그인이 필요한 대쉬보드 페이지 입니다. </div>; }
대쉬보드 페이지에 로그아웃 버튼을 추가합니다.
api/auth/logout
API 경로를 가리키는 링크를 추가합니다. 이 링크를 클릭하면 사용자를 Auth0 로그아웃 엔드포인트(https://YOUR_DOMAIN/v2/logout
)로 리디렉션한 다음 즉시 애플리케이션으로 홈으로 다시 리디렉션 합니다.app/dashboard/page.tsx
import { getSession } from '@auth0/nextjs-auth0'; export default async function DashbaordPager() { const session = await getSession(); return <div> {!!session?.user && ( <div> <p>안녕하세요. {session.user.name} 님! 👋</p> <button className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"> <a href='/api/auth/logout'>Logout</a> </button> </div> )} 로그인이 필요한 대쉬보드 페이지 입니다. </div>; }
로그인/로그아웃을 추가 하였지만 아직 로그인이 필요한
/dashboard
페이지 보호가 되지 않습니다. 즉, 로그인을 하지 않아도 http://localhost:3000/dashboard
URL로 해당 페이지를 볼 수 있습니다.이제 대쉬보드 페이지를 로그인한 사용자만 접근가능하도록 보호 설정을 해야 합니다. NextJS에서 Auth0 SDK로 로그인이 필요한 페이지를 보호하는 것은 세 가지 방법이 있습니다:
- Middware에서 보호하기:
withMiddlewareAuthRequired
사용
- 서버 사이드에서 보호하기:
withPageAuthRequired
사용
- 클라이언트 사이드에서 보호하기:
withPageAuthRequired
사용
옵션 1. Middware에서 로그인 필요한 페이지 보호하기
Next.js 미들웨어의 기능을 활용하여 Auth0을 사용하여 페이지를 보호할 수 있습니다. Next.js 미들웨어는 애플리케이션으로 들어오는 요청이 완료되기 전에 코드를 실행합니다. 그런 다음 들어오는 요청의 특성에 따라 응답을 수정하여 애플리케이션의 비즈니스 요구 사항을 충족할 수 있습니다. 응답을 다시 작성하거나 리디렉션하고, 요청 또는 응답 헤더를 수정하거나, 직접 응답할 수 있습니다.
NextJS 미들웨어 로직은 소스코드 루트 경로에
middlware.ts
(JS 프로젝트는 middleware.js
) 파일에 정의합니다. 미들웨어에 /dashboard
경로 접근시 사용자 인증이 필요하도록 설정 합니다.middleware.ts
import { withMiddlewareAuthRequired } from "@auth0/nextjs-auth0/edge"; export default withMiddlewareAuthRequired(); export const config = { matcher: ["/dashboard"], // '/dashbaord` 경로는 로그인이 필요하도록 설정합니다. };
옵션 2. SSR (Server-Side Rendering) 페이지 보호하기
서버 사이드에서 웹 페이지 렌더링시 사용자 인증이 필요하도록 설정 할 수 있습니다.
withPageAuthRequired()
메서드로 React 서버 컴포넌트(RSC)를 래핑하여 사용자 인증이 필요하도록 설정합니다.app/dashboard/page.tsx
import { getSession, withPageAuthRequired } from '@auth0/nextjs-auth0'; export default withPageAuthRequired( async function DashbaordPager() { const session = await getSession(); return <div> {!!session?.user && ( <div> <p>안녕하세요. {session.user.name} 님! 👋</p> <button className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"> <a href='/api/auth/logout'>Logout</a> </button> </div> )} 로그인이 필요한 대쉬보드 페이지 입니다. </div>; }, { returnTo: '/dashboard'});
옵션 3. CSR (Client-Side Rendering) 페이지 보호하기
클라이언트 사이드에서 웹 페이지 렌더링시 사용자 인증이 필요하도록 설정 할 수 있습니다.
withPageAuthRequired()
메서드로 React 클라이언트 컴포넌트(RCC)를 래핑하여 사용자 인증이 필요하도록 설정합니다.app/dashboard/page.tsx
'use client'; import { useUser, withPageAuthRequired } from '@auth0/nextjs-auth0/client'; import React from 'react'; export default withPageAuthRequired( function DashboardPage(): React.ReactNode { const { user } = useUser(); return ( <div> {!!user?.name && ( <div> <p>안녕하세요. {user.name} 님! 👋</p> <button className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"> <a href='/api/auth/logout'>Logout</a> </button> </div> )} 로그인이 필요한 대쉬보드 페이지 입니다. </div> ); } );
클라이언트 사이드에서는
getSession()
메소드를 사용 할 수 없습니다. 사용자 정보를 가져오기 위한 메소드를useUser()
로 변경하였습니다.소셜 로그인 추가하기
Google 로그인
- Google 자격 증명 만들기
- Google 개발자 콘솔에서 APIs & Services → Creadentials → CREATE CREDENTIALS 를 클릭하여 새 Google 자격 증명을 생성 합니다.
- OAuth client ID 타입으로 생성합니다.
- Application type은 Web application을 선택합니다.
- Authorized JavaScript origins 항목에
https://<Auth0 Domain>
을 입력합니다. - Authorized redirect URIs 항목에
https://<Auth0 Domain>/login/callback
을 입력합니다.
- Auth0로 접속하여, Authentication → Social 메뉴로 들어 갑니다. Social Connections 화면에서 Create Connection 버튼을 클릭합니다.
- 목록에 나오는 여러 소셜 연결 중에 Google / Gmail을 선택합니다. → Continue 클릭
- Client ID 항목과 Client Secret 항목을 Google 개발자 콘솔에 생성된 OAuth 2.0 Client ID의 ID와 Secret으로 설정후 Save Changes 버튼을 클릭하여 저장합니다.
- 생성된 Google 소셜 로그인을 추가할 Auth0 어플리케이션을 선택합니다.
Github 로그인
Github 설정
https://github.com/settings/developers
에 접속하여 새로운 OAuth App을 추가합니다.- OAuth Apps → New OAuth App 클릭
- 아래와 같이 Homepage URL과 Authorization callback URL을 Auth0 어플리케이션 도메인 주소로 입력합니다.
- Homepage URL:
https://<Auth0의 Domain>
- Authorization callback URL:
https://<Auth0의 Domain>/login/callback
- 생성된 OAuth 앱의 Client ID와 Client Secret (없으면 생성)을 복사해 둡니다.
Auth0 설정
- Auth0로 접속하여, Authentication → Social 메뉴로 들어 갑니다. Social Connections 화면에서 Create Connection 버튼을 클릭합니다.
- 목록에 나오는 여러 소셜 연결 중에 GitHub을 선택합니다. → Continue 클릭
- Client ID와 Client Secret을 앞서 GitHub에서 생성된 ID와 Secret으로 입력합니다. → Create 클릭
- 생성된 GitHub 소셜 로그인을 추가할 Auth0 어플리케이션을 선택합니다.
이제 로그인시 Google과 GitHub 소셜 로그인을 사용 할 수 있습니다!
테스트
기본 구현이 완료되었으므로, 이제 테스트 해 봅시다. 아래 커맨드로 NextJS 웹 어플리케이션을 개발 모드로 실행합니다.
pnpm run dev
웹 브라우저에서
http://localhost:3000
주소로 접속하면, create-next-app
으로 생성된 NextJS 기본 홈페이지에 로그인 버튼이 추가 되어 있습니다.Login 버튼을 클릭하면, Auth0 유니버셜 로그인 화면으로 넘어갑니다.
Auth0 → User Management → Users 메뉴에서 테스트용
test@test.com
사용자를 추가 하였습니다.로그인을 하면, 대쉬보드 페이지로 넘어갑니다.
로그아웃을 한 뒤, 대쉬보드 페이지가 보호되고 있는지 확인해 봅시다. 로그아웃 버튼을 클릭후, 웹 브라우저에서
http://localhost:3000/dashboard
주소로 대쉬보드 페이지로 접속을 시도해 보겠습니다. 대쉬보드 페이지는 사용자 인증이 필요하므로, 아래와 같이 로그인 화면으로 리디렉션 됩니다.전체 예제 코드는 다음 링크를 통해 확인하실 수 있습니다.nextjs-auth0-exampleTaehun • Updated Feb 25, 2024