클라이언트 API
NextAuth.js 클라이언트 라이브러리는 React 애플리케이션에서 세션과 상호 작용을 쉽게 할 수 있게 해줍니다.
예제 세션 객체
{
user: {
name: string
email: string
image: string
},
expires: Date // 이는 세션의 만료 시간으로, 세션 내의 토큰의 만료 시간이 아닙니다
}
클라이언트에 반환되는 세션 데이터에는 세션 토큰이나 OAuth 토큰과 같은 민감한 정보가 포함되어 있지 않습니다. 이는 사용자가 로그인한 상태에서 페이지에 사용자 정보를 표시하는 데 필요한 최소한의 페이로드(예: 이름, 이메일, 이미지)를 포함하고 있습니다.
세션 객체에 추가 데이터를 반환해야 하는 경우 세션 콜백을 사용하여 클라이언트에 반환되는 세션 객체를 사용자 정의할 수 있습니다.
expires 값은 순환되므로 세션이 REST API에서 검색될 때마다 만료를 방지하기 위해 이 값도 업데이트됩니다.
useSession()
- 클라이언트 측: 예
- 서버 측: 아니요
NextAuth.js 클라이언트의 useSession() React 훅은 누군가가 로그인했는지 확인하는 가장 쉬운 방법입니다.
<SessionProvider>가 pages/_app.js에 추가되어 있는지 확인하세요.
예제
import { useSession } from "next-auth/react"
export default function Component() {
const { data: session, status } = useSession()
if (status === "authenticated") {
return <p>{session.user.email}로 로그인 됨</p>
}
return <a href="/api/auth/signin">로그인</a>
}
useSession()은 두 가지 값을 포함하는 객체를 반환합니다: data와 status:
data: 이 값은 세 가지 중 하나일 수 있습니다:Session/undefined/null.- 세션이 아직 가져와지지 않은 경우,
data는undefined입니다. - 세션을 가져오는 데 실패한 경우,
data는null입니다. - 성공한 경우,
data는Session입니다.
- 세션이 아직 가져와지지 않은 경우,
status: 세 가지 가능한 세션 상태에 매핑되는 열거형:"loading" | "authenticated" | "unauthenticated"
세션 요구
Next.js가 getServerSideProps 및 getInitialProps를 처리하는 방식 때문에 보호된 페이지를 로드할 때마다 세션이 유효한지 확인한 다음 요청된 페이지(SSR)를 생성하기 위해 서버 측 요청을 수행해야 합니다. 이로 인해 서버 부하가 증가하며 클라이언트에서 요청을 수행하는 데 능숙한 경우 대안이 있습니다. 항상 유효한 세션이 있는지 확인하는 방식으로 useSession을 사용할 수 있습니다. 초기 로딩 상태 이후에 세션을 찾을 수 없는 경우 적절한 조치를 정의하여 응답할 수 있습니다.
기본 동작은 사용자를 로그인 페이지로 리디렉션하는 것이며, 로그인에 성공하면 사용자가 처음 시작한 페이지로 다시 전송됩니다. 다른 작업을 수행하려는 경우 onUnauthenticated() 콜백을 정의할 수도 있습니다:
예제
import { useSession } from "next-auth/react"
export default function Admin() {
const { status } = useSession({
required: true,
onUnauthenticated() {
// 사용자가 인증되지 않았을 때 처리할 로직
},
})
if (status === "loading") {
return "로딩 중이거나 인증되지 않음..."
}
return "인증된 유저"
}
커스텀 클라이언트 세션 처리
Next.js가 getServerSideProps / getInitialProps를 처리하는 방식 때문에, 모든 보호된 페이지 로드는 세션이 유효한지 확인하기 위해 서버 측 요청을 해야 하고, 그 다음에 요청된 페이지를 생성해야 합니다. 이 대안 솔루션은 초기 검사 시 로딩 상태를 표시하고, 이후 모든 페이지 전환은 클라이언트 측에서 이루어져 서버와 다시 확인하거나 페이지를 재생성할 필요가 없도록 합니다.
export default function AdminDashboard() {
const { data: session } = useSession()
// 세션은 이 페이지 내에서 항상 null이 아닌상태, React 트리 하위에서도 동일합니다.
return "엄청 비밀스러운 대시보드!"
}
AdminDashboard.auth = true
export default function App({
Component,
pageProps: { session, ...pageProps },
}) {
return (
<SessionProvider session={session}>
{Component.auth ? (
<Auth>
<Component {...pageProps} />
</Auth>
) : (
<Component {...pageProps} />
)}
</SessionProvider>
)
}
function Auth({ children }) {
// 매개변수로`{ required: true }`가 넘어온 경우, `status`는 "loading" 또는 "authenticated"이여야 합니다
const { status } = useSession({ required: true })
if (status === "loading") {
return <div>Loading...</div>
}
return children
}
역할 기반 인증을 페이지에 지원하기 위한 옵션 객체와 같은 것을 지원하도록 쉽게 확장/수정할 수 있습니다. 예를 들어:
AdminDashboard.auth = {
role: "admin",
loading: <AdminLoadingSkeleton />,
unauthorized: "/login-with-different-user", // 이 URL로 리디렉션
}
_app이 작성된 방식 때문에, 인증이 필요하지 않은 페이지에 대해 불필요하게 /api/auth/session 엔드포 인트에 연락하지 않습니다.
자세한 정보는 다음 GitHub 이슈를 참조하세요.
세션 업데이트
useSession() 훅은 페이지를 다시 로드하지 않고도 세션을 업데이트할 수 있는 update(data?: any): Promise<Session | null> 메소드를 제공합니다.
첫 번째 인수로 임의의 객체를 전달할 수 있으며, 이는 서버에서 세션 객체와 병합됩니다.
인수를 전달하지 않으면 서버에서 세션을 다시 로드합니다. (이는 데이터베이스에서 업데이트와 같은 서버 측 변형 후에 세션을 업데이트하려는 경우 유용합니다.)
데이터 객체는 클라이언트에서 오기 때문에 저장하기 전에 서버에서 검증해야 합니다.
예제
import { useSession } from "next-auth/react"
export default function Page() {
const { data: session, status, update } = useSession()
if (status === "authenticated") {
return (
<>
<p>Signed in as {session.user.name}</p>
{/* 백엔드에 전송하여 값을 업데이트합니다. */}
<button onClick={() => update({ name: "John Doe" })}>이름 변경</button>
{/*
* 서버 측에서 이미 값을 업데이트했다고 가정하고 세션 업데이트만 트리거합니다.
* 모든 `useSession().data` 참조가 업데이트됩니다.
*/}
<button onClick={() => update()}>이름 변경</button>
</>
)
}
return <a href="/api/auth/signin">로그인</a>
}
strategy: "jwt"가 사용된다고 가정하면, update() 메소드는 trigger: "update" 옵션과 함께 jwt 콜백을 트리거합니다. 이를 사용하여 서버에서 세션 객체를 업데이트할 수 있습니다.
...
callbacks: {
async jwt({ token, account }) {
// '...rest` 매개변수를 사용하여 '트리거'를 기준으로 유형 범위를 좁힐 수 있습니다.
if (account) {
token.accessToken = account.access_token
}
return token
},
async session({ session, token, user }) {
// '세션'은 임의의 객체일 수 있으므로 유효성을 검사하는 것을 잊지 마세요!
session.accessToken = token.accessToken
return session
}}
...
strategy: "database"가 사용된다고 가정하면, update() 메소드는 trigger: "update" 옵션과 함께 session 콜백을 트리거합니다. 이를 사용하여 서버에서 세션 객체를 업데이트할 수 있습니다.
...
const adapter = PrismaAdapter(prisma)
export default NextAuth({
...
adapter,
callbacks: {
async session({ session, trigger, newSession }) {
// '...rest` 매개변수를 사용하여 '트리거'를 기준으로 유형 범위를 좁힐 수 있습니다.
if (trigger === "update" && newSession?.name) {
// 아직 업데이트되지 않은 경우 데이터베이스에서 세션을 업데이트할 수 있습니다.
// await adapter.updateUser(session.user.id, { name: newSession.name })
// 업데이트된 값이 클라이언트에 반영되었는지 확인합니다.
session.name = newSession.name
}
return session
}
}
})
세션 재조회
SessionProvider#refetchInterval과 SessionProvider#refetchOnWindowFocus는 update() 메소드로 대체할 수 있습니다.
update() 메소드는 refetchInterval 및 refetchOnWindowFocus 옵션과 달리 탭 간 동기화를 하지 않습니다.
import { useEffect } from "react"
import { useSession } from "next-auth/react"
export default function Page() {
const { data: session, status, update } = useSession()
// 세션을 매 1시간마다 폴링합니다
useEffect(() => {
// 팁: `navigator.onLine`과 몇 가지 추가 이벤트 핸들러를 사용하여
// 사용자가 온라인 상태인지 확인하고 온라인 상태인 경우에만 세션을 업데이트할 수도 있습니다.
// https://developer.mozilla.org/en-US/docs/Web/API/Navigator/onLine
const interval = setInterval(() => update(), 1000 * 60 * 60)
return () => clearInterval(interval)
}, [update])
// 사용자가 탭을 전환하고 다시 탭을 표시하는 경우 페이지가 표시되는 시점을 기다립니다.
// 탭이 다시 표시되면 세션을 다시 가져옵니다.
useEffect(() => {
const visibilityHandler = () =>
document.visibilityState === "visible" && update()
window.addEventListener("visibilitychange", visibilityHandler, false)
return () =>
window.removeEventListener("visibilitychange", visibilityHandler, false)
}, [update])
return <pre>{JSON.stringify(session, null, 2)}</pre>
}
getSession()
- 클라이언트 측: 예
- 서버 측: 아니요 (참조:
getServerSession())
NextAuth.js는 현재 활성 세션을 반환하기 위해 클라이언트 측에서만 호출해야 하는 getSession() 헬퍼를 제공합니다.
서버 측에서도 아직은 사용 가능하지만, 앞으로는 getServerSession을 사용하는 것을 권장합니다. 그 이유는 서버 측에서 불필요한 추가 fetch 호출을 피하기 위함입니다. 자세한 내용은 이 이슈를 참고하세요.
이 헬퍼는 React 컨텍스트 외부에서 세션을 읽고자 할 때 유용합니다.
호출 시, getSession()은 /api/auth/session에 요청을 보내고 세션 객체를 포함한 프로미스를 반환하며, 세션이 없으면 null을 반환합니다.
async function myFunction() {
const session = await getSession()
/* ... */
}
서버 측 호출에서 getServerSession()을 사용하여 세션을 가져오는 방법을 배우려면 페이지 및 API 경로 보호하기 튜토리얼을 읽어보세요.
getCsrfToken()
- 클라이언트 측: 예
- 서버 측: 예
getCsrfToken() 메소드는 POST 요청(예: 로그인 및 로그아웃)을 수행하는 데 필요한 현재 교차 사이트 요청 위조 토큰(CSRF 토큰)을 반환합니다.
내장된 signIn() 및 signOut() 메소드를 사용하지 않는 경우에만 이를 사용할 필요가 있습니다.
클라이언트 측 예제
async function myFunction() {
const csrfToken = await getCsrfToken()
/* ... */
}
서버 측 예제
import { getCsrfToken } from "next-auth/react"
export default async (req, res) => {
const csrfToken = await getCsrfToken({ req })
/* ... */
res.end()
}