코드 출처 : https://github.com/Cluster-Taek/next14-boilerplate
GitHub - Cluster-Taek/next14-boilerplate
Contribute to Cluster-Taek/next14-boilerplate development by creating an account on GitHub.
github.com
import { tokenRefresh } from '@/lib/common/account';
import dayjs from 'dayjs';
import { jwtDecode } from 'jwt-decode';
import { NextAuthOptions, User } from 'next-auth';
import CredentialsProvider, { CredentialsConfig } from 'next-auth/providers/credentials';
const credentialsProviderOption: CredentialsConfig = {
type: 'credentials',
id: 'login-credentials',
name: 'login-credentials',
credentials: {
login: { label: 'Email', type: 'text' },
password: { label: 'Password', type: 'password' },
},
async authorize(credentials: Record<string, unknown> | undefined) {
try {
if (credentials?.login === 'test@gmail.com' && credentials?.password === '1234') {
const user = {
name: 'John Doe',
accessToken:
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c',
refreshToken: 'refreshToken',
};
return {
id: credentials?.login as string,
name: user.name,
accessToken: user.accessToken,
refreshToken: user.refreshToken,
};
} else {
return null;
}
} catch (error) {
console.error(error);
return null;
}
},
};
export const authOptions: NextAuthOptions = {
pages: {
signIn: '/login',
error: '/login',
},
providers: [CredentialsProvider(credentialsProviderOption)],
callbacks: {
async jwt({ token, user, account, trigger, session }) {
if (trigger === 'update') {
token.user = session.user;
return token;
}
// [1] 최초 로그인 시
if (account && user) {
return {
user,
accessToken: user.accessToken,
refreshToken: user.refreshToken,
exp: jwtDecode(user.accessToken as string).exp as number,
};
}
// [2] 로그인 이후 토큰 만료 전
if (dayjs().isBefore(dayjs((token.exp as number) * 1000))) {
return token;
}
// [3] 로그인 이후 토큰 만료 후
const { accessToken, refreshToken } = await tokenRefresh(token.refreshToken as string);
token.accessToken = accessToken;
token.refreshToken = refreshToken;
token.exp = jwtDecode(accessToken).exp as number;
return token;
},
async session({ session, token }) {
if (token.user) {
session.user = token.user as User;
}
return session;
},
},
};
- 로그인:
- 사용자가 입력한 자격 증명(credentials)을 검증하여 사용자 정보 및 토큰을 반환.
- JWT 관리:
- 최초 로그인 시 토큰 생성.
- 토큰 만료 전에는 기존 토큰 유지.
- 만료 후에는 새 토큰 갱신(tokenRefresh 함수 호출).
- 세션 관리:
- 사용자 정보를 세션에 포함하여 클라이언트에서 접근 가능하도록 설정.
1. CredentialsProvider 설정
credentialsProviderOption은 사용자 로그인을 처리하기 위한 CredentialsProvider의 옵션을 정의합니다.
- type: 로그인 방식으로 credentials(사용자 입력 정보 기반)을 사용.
- id, name: 제공자 식별자와 이름을 정의.
- credentials: 사용자로부터 받을 입력 필드를 설정 (login과 password).
- authorize(credentials):
- 사용자가 입력한 자격 증명을 기반으로 인증을 처리합니다.
- 예제에서는 login이 "test@gmail.com"이고, password가 "1234"일 때만 인증 성공 처리합니다.
- 성공 시, 사용자 정보를 반환하고 실패 시 null을 반환.
2. authOptions 설정
authOptions는 NextAuth의 설정 객체로 다음과 같은 요소를 포함합니다.
(1) pages
- signIn: 로그인 페이지 경로 (/login).
- error: 인증 오류 시 표시할 페이지 경로 (/login).
(2) providers
- CredentialsProvider(credentialsProviderOption)를 추가하여 사용자 정의 자격 증명 방식을 사용.
(3) callbacks
- 콜백은 특정 인증 단계에서 커스터마이징이 필요할 때 사용됩니다.
- (a) jwt
- JWT(JSON Web Token)를 생성하거나 갱신합니다.
- trigger 값에 따라 동작이 다르게 정의됩니다.
- 최초 로그인 시:
- 사용자 정보(user)와 인증 정보(account)가 전달됩니다.
- 반환된 토큰에 사용자 정보, accessToken, refreshToken, 만료 시간(exp)을 저장합니다.
- 로그인 이후, 토큰이 유효한 경우:
- 현재 시간이 만료 시간보다 이전일 경우(dayjs().isBefore(dayjs((token.exp as number) * 1000))), 기존 토큰을 반환합니다.
- 로그인 이후, 토큰이 만료된 경우:
- tokenRefresh 함수를 호출해 새로운 accessToken과 refreshToken을 발급받습니다.
- 토큰 정보를 갱신하고 반환합니다.
- 최초 로그인 시:
- (b) session
- 세션 객체에 사용자 정보를 포함시킵니다.
- JWT 토큰에서 사용자 정보를 추출하여 session.user에 저장.
다음 글에서 어떻게 이 코드가 상호작용하는지 작성하겠습니다
'개발 공부 > React' 카테고리의 다른 글
| NextAuth.js 사용자 인증 로직 (3) NextAuth 동작 방식 (0) | 2025.01.19 |
|---|---|
| NextAuth.js 사용자 인증 로직 (2) (1) | 2025.01.12 |
| Next.js usePathname, useRouter, useSearchParams (0) | 2025.01.08 |
| React-query useQuery, useMutation (0) | 2025.01.06 |
| Next.js 에서 모달 띄우기와 서버작업을 통한 유저 정보 받기 및 등록 (4) (0) | 2025.01.05 |