24.09.06 13:49 작성
·
53
·
수정됨
0
안녕하세요 강의를 듣고 next-auth를 활용하여 개발 중에 궁금한 점이 생겨 질문 드립니다.
프로젝트에서 일반 로그인과 소셜 로그인을 모두 사용하고 있어
next-auth의 signin callback에서 로그인일 경우 자체 서버에 요청하여 accessToken과 refreshToken을 발급 받고 jwt callback에서 엑세스 토큰의 만료 시간을 체크하여 만료 시에 재발급 요청이 되도록 구현하고 있습니다.
이렇게 구현했을 경우 간헐적으로 서버 시간과의 타이밍 이슈 때문인지 api 요청 시에 401 토큰 만료 에러가 발생하는 순간이 존재합니다.
따라서 401 상태코드일 경우에 refreshToken 토큰 재발급 요청을 하려고 하는데 refreshToken이 현재 next-auth에서 jwt 콜백에서 리턴되어 jwt토큰으로 생성되어 있습니다.
이 401일 경우 재발급 요청 처리를 클라이언트 단에서 할 경우 refreshToken이 노출되어 보안상 이슈가 있을 것으로 예상이 되는데 서버단에서 처리를 하려면 next에서 어디서 처리를 하면 좋을 지 문의드립니다.
async signIn({ account, user, credentials }) {
const cookieStore = cookies();
const authorizationParams = JSON.parse(
cookieStore.get("authorization-params")?.value ?? ""
);
const action = authorizationParams.action;
user.platform = authorizationParams.platform;
if (!account?.provider || !sns_type_map[account.provider]) {
throw new Error("Unsupported provider");
}
user.snsType = sns_type_map[account.provider];
if (action === auth_action_type.signin) {
return handleSignIn(user); // getAccessToken
}
if (action === auth_action_type.signup) {
return handleSignUp();
}
return false;
},
async jwt({ token, account, user }) {
// Initial sign in
if (account && user) {
return {
...token,
...user,
accessToken: user.refreshToken,
expiresAt: new Date(
Date.now() + (user?.expiresIn ?? 0)
).toISOString(),
refreshToken: "refreshtoken",
};
}
// Return previous token if the access token has not expired yet
if (new Date() < new Date(token.expiresAt as string)) {
console.log("@@@@@@valid");
return token;
} else {
// Access token has expired, try to update it
console.log("@@@@@@expired");
const cookieStore = cookies();
const authorizationParams = JSON.parse(
cookieStore.get("authorization-params")?.value ?? ""
);
const body = {
....
};
const tokenData = await authApi.reissueAccessToken(body);
// reissue token
return {
...token,
...user,
accessToken: tokenData.accessToken,
expiresAt: new Date(
Date.now() + (tokenData.expiresIn ?? 0)
).toISOString(),
refreshToken: tokenData.refreshToken,
};
}
},
미들웨어에서 401 상태 코드 처리하는 것도 알아보았으나 일반적인 방식인지 궁금합니다.
미들웨어에서 401일때 재발급 요청 시 새로운 엑세스 토큰으로 재요청이 정상적으로 되는 것은 확인했으나 다시 next-auth의 jwt토큰에 재발급된 값을 세팅해줘야 하는데 어떻게 해야할지도 궁금합니다.
import { NextResponse } from 'next/server';
import { getToken } from 'next-auth/jwt';
export async function middleware(request) {
const token = await getToken({ req: request, secret: process.env.AUTH_SECRET });
if (request.nextUrl.pathname.startsWith('/gateway')) {
const accessToken = token?.accessToken;
const headers = new Headers(request.headers);
if (response.status === 401) {
const refreshToken = token?.refreshToken;
const refreshResponse = await fetch("/reissueToken")
const refreshData = await refreshResponse.json();
if (refreshResponse.ok) {
const newAccessToken = refreshData.accessToken;
headers.set('Authorization', `Bearer ${newAccessToken}`);
const newResponse = NextResponse.next({
request: {
headers: request.headers,
},
});
}
// 토큰 재발급 실패 시 처리
return NextResponse.redirect('/login');
}
return NextResponse.next(response);
}
return NextResponse.next();
}
답변 1
0
2024. 09. 06. 17:37
현재 jwt 메서드에서 return에 엑세스토큰과 리프레시토큰을 다 넣고 계신데 이렇게 하면 프론트에 액세스토큰과 리프레시 토큰이 다 전송될 것 같고요(물론 JWE라서 암호화는 되어있겠지만)
리프레시 토큰은 그냥 DB에 저장하거나 Redis에 저장하시면 됩니다. 그리고 그걸 업데이트하거나 불러오는 건 api routes로 만들어두시면 되고요. middleware든 어디든 리프레시토큰을 수정/사용할 때 그 api routes를 호출하시면 됩니다. api routes 호출할 때는 fetch에 header로 cookie 넣어주셔야 하고요.
2024. 09. 06. 17:45
넵 답변 감사합니다! Api routes 호출할때 헤더로 크키를 넣어야한다고 하셨는데 jwt로 암호화된 값을 말씀하시는걸까요??