NextAuth.js v4에서 JWT 인증 구현 및 활용 가이드
NextAuth.js v4를 사용하여 JWT 인증을 구현하고 활용하는 다양한 방법을 살펴보겠습니다.
1. JWT 설정
import NextAuth from 'next-auth';
import CredentialsProvider from 'next-auth/providers/credentials';
export default NextAuth({
providers: [
CredentialsProvider({
// 자격 증명 제공자 설정
})
],
jwt: {
secret: process.env.JWT_SECRET,
encryption: false, // JWT 암호화 비활성화
maxAge: 60 * 60 * 24 * 30, // 30일
},
// 기타 설정...
});
2. 커스텀 JWT 토큰 생성
callbacks: {
async jwt({ token, user }) {
if (user) {
token.id = user.id;
token.role = user.role;
token.customField = 'custom value';
}
return token;
},
async session({ session, token }) {
session.user.id = token.id;
session.user.role = token.role;
session.customField = token.customField;
return session;
},
},
3. API 라우트에서 JWT 검증
import { getToken } from 'next-auth/jwt';
export default async function handler(req, res) {
const token = await getToken({ req, secret: process.env.JWT_SECRET });
if (token) {
// 토큰이 유효한 경우
res.json({ message: 'Authenticated', user: token });
} else {
res.status(401).json({ message: 'Unauthorized' });
}
}
4. 미들웨어에서 JWT 활용
import { withAuth } from 'next-auth/middleware';
import { NextResponse } from 'next/server';
export default withAuth(
function middleware(req) {
if (req.nextauth.token.role !== 'admin') {
return NextResponse.rewrite(new URL('/unauthorized', req.url));
}
},
{
callbacks: {
authorized: ({ token }) => token?.role === 'admin',
},
}
);
export const config = { matcher: ['/admin/:path*'] };
5. 클라이언트에서 JWT 사용
import { useSession } from 'next-auth/react';
import { useState, useEffect } from 'react';
function ProfilePage() {
const { data: session } = useSession();
const [userDetails, setUserDetails] = useState(null);
useEffect(() => {
if (session) {
fetch('/api/user-details', {
headers: {
'Authorization': `Bearer ${session.customField}`,
},
})
.then(res => res.json())
.then(data => setUserDetails(data));
}
}, [session]);
if (!session) return Access Denied
;
return (
Welcome, {session.user.name}
{userDetails && User Role: {userDetails.role}
}
);
}
6. JWT 갱신 구현
callbacks: {
async jwt({ token, user }) {
if (user) {
token.accessToken = user.accessToken;
token.refreshToken = user.refreshToken;
token.accessTokenExpires = Date.now() + 60 * 60 * 1000; // 1 hour
}
// 액세스 토큰이 만료되지 않았다면 그대로 반환
if (Date.now() < token.accessTokenExpires) {
return token;
}
// 액세스 토큰이 만료되었다면 갱신
return refreshAccessToken(token);
},
async session({ session, token }) {
session.accessToken = token.accessToken;
return session;
},
},
async function refreshAccessToken(token) {
try {
// 리프레시 토큰을 사용하여 새 액세스 토큰 요청
const response = await fetch('https://your-auth-server.com/token', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: `grant_type=refresh_token&refresh_token=${token.refreshToken}`,
});
const refreshedTokens = await response.json();
if (!response.ok) {
throw refreshedTokens;
}
return {
...token,
accessToken: refreshedTokens.access_token,
accessTokenExpires: Date.now() + refreshedTokens.expires_in * 1000,
refreshToken: refreshedTokens.refresh_token ?? token.refreshToken, // 새 리프레시 토큰이 발급되지 않았다면 기존 것을 사용
};
} catch (error) {
console.error('RefreshAccessTokenError', error);
return {
...token,
error: 'RefreshAccessTokenError',
};
}
}
결론
NextAuth.js v4를 사용하여 JWT 인증을 구현하고 활용하는 다양한 방법을 살펴보았습니다. JWT를 통해 안전하고 효율적인 인증 시스템을 구축할 수 있으며, 서버 사이드와 클라이언트 사이드 모두에서 유연하게 활용할 수 있습니다. 보안을 강화하기 위해 HTTPS 사용, 토큰 만료 시간 설정, 그리고 주기적인 토큰 갱신 등의 추가적인 보안 조치를 고려하는 것이 좋습니다.