개발일지
[NestJS] Refresh token으로 Access token 재발급하기 본문
NestJS, Node.js/#01 Project - 투표 커뮤니티
[NestJS] Refresh token으로 Access token 재발급하기
lyjin 2022. 10. 28.시나리오
제가 생각한 access token 재발급 순서는 다음과 같습니다.
- access token 만료시 error를 반환합니다.
- 클라이언트는 body refresh token를 포함한 뒤 access token 재발급을 요청합니다.
- 서버에서는 refresh token을 검증합니다.
- db에 저장된 refresh token과의 일치 여부를 확인합니다.
- refresh token의 유효성을 검증합니다.
- 검증된 refresh token의 경우 access token을 재생성해 response 합니다.
참고) Refresh token 생명 주기
- 로그인 시 access token과 refresh token이 발급됩니다.
- 로그아웃 시 db에 저장된 refresh token이 삭제됩니다.
- 보안성을 위해 refresh token은 암호화 된 상태로 db에 저장되고 reponse 되어야 합니다.
Refresh token 검증 구현
DB에 저장된 token 값과의 일치여부 확인
컨트롤러에서 @CurrUser()
로 받아온 userId와 refreshToken, 두 데이터와 일치하는 값을 가진 RefreshTokens를 찾습니다. 존재하지 않을 경우 error를 던집니다.
// users/users.service.ts
// class TokenService
async verifyRefreshToken(
userId: number,
encryptRefreshToken: string,
): Promise<VerifiedToken> {
let verifiedToken: VerifiedToken;
// 1-2. 유효성 검증 - refresh token db 검증
const token: RefreshTokens = await this.usersRepository.findRefreshToken(
encryptRefreshToken,
);
if (!token) {
throw new CustomException(UsersException.UNVERIFIED_REFRESH_TOKEN);
}
...
}
async findMatchedRefreshToken(
userId: number,
encryptRefreshToken: string,
): Promise<RefreshTokens> {
return await this.prisma.refreshTokens.findFirst({
where: {
userId: userId,
token: encryptRefreshToken,
},
});
}
Refresh token 검증
access token과 마찬가지로 @nestjs/jwt
의 .verify()
함수를 사용해 검증합니다. 이때 클라이언트로부터 받아온 토큰은 암호화된 상태입니다. 따라서 .verify()
인수로 넣기 위해서는 복호화 해줘야합니다.
async verifyRefreshToken(...): Promise<VerifiedToken> {
// 1-2. 유효성 검증 - refresh token db 검증
...
// 1-3. 유효성 검증 - refresh token 검증
const decryptRefreshToken: string = // 복호화
this._decryptRefreshToken(encryptRefreshToken);
try {
verifiedToken = this.jwtService.verify(decryptRefreshToken, {
secret: 'refresh-secret-key',
});
} catch (error) {
switch (error.message) {
case 'jwt expired':
throw new CustomException(UsersException.EXPIRED_TOKEN);
default:
throw new CustomException(UsersException.UNVERIFIED_REFRESH_TOKEN);
}
}
return verifiedToken;
}
Access token 재발급
완성된 recreateAccessToken service입니다. verifiedUser는 .verify()
된 결과 값으로 검증된 refresh token의 페이로드입니다. 이 페이로드로 access token을 생성해줍니다.
// users/users.service.ts
// class UsersService
async recreateAccessToken(
userId: number,
encryptRefreshToken: string,
): Promise<RecreateAccessToken> {
// 1-1. 유효성 검증 - resuest로부터 token을 받지 못한 경우
if (!encryptRefreshToken) {
throw new CustomException(UsersException.TOKEN_NOT_EXISTS);
}
const verifiedUser: VerifiedToken =
await this.tokenService.verifyRefreshToken(userId, encryptRefreshToken);
const payload: JwtPayload = {
sub: verifiedUser.sub,
nickname: verifiedUser.nickname,
};
const accessToken = this.tokenService.createAccessToken(payload);
return { accessToken };
}
users/users.controller.ts
@UseGuards(JwtAccessGuard)
@Post('recreate/access-token')
async recreateAccessToken(
@CurrUser('id', ParseIntPipe) userId: number,
@Body('refreshToken') encryptRefreshToken: string,
): Promise<RecreateAccessToken> {
return await this.usersService.recreateAccessToken(
userId,
encryptRefreshToken,
);
}
'NestJS, Node.js > #01 Project - 투표 커뮤니티' 카테고리의 다른 글
[NestJS] 투표 글 생성하기 구현 (0) | 2022.11.03 |
---|---|
중간점검: 프로젝트 구조 변경 (0) | 2022.10.30 |
[NestJS] Custom decorators (0) | 2022.10.28 |
[NestJS] 로그인 구현 #2 - Passport, JWT (0) | 2022.10.27 |
[NestJS] 로그인 구현 #1 - 유효성 검증 (0) | 2022.10.27 |