ํ๋ก์ ํธ๋ฅผ ์งํํ๋ฉด์ JWT ์ธ์ฆ ์์คํ
์ ์ง์ ๊ตฌํํ๋ ๊ณผ์ ์์ ํ์์ฑ์ ๋๋ผ๊ณ ๊ณต๋ถํ๊ณ ์ ๋ฆฌํ ๋ด์ฉ์ ๋ด์๋ค.
๊ฐ๋ฐ์ ํ๋ค ๋ณด๋ฉด ์ด๋ฐ ์ง๋ฌธ์ด ์์ฐ์ค๋ฝ๊ฒ ์๊ธด๋ค.
"Access Token์ด๋ Refresh Token, ์ด ๋์ ๋๋์ฒด ๋ญ๊ฐ ๋ค๋ฅด๊ณ , ์ด๋ป๊ฒ ๊ด๋ฆฌํด์ผ ํ ๊น?"
ํนํ Refresh Token์ ์ด๋์ ์ ์ฅํด์ผ ํ ์ง, Redis๋ฅผ ์ฌ์ฉํ๋ ์ด์ ๋ ๋ญ์ง ๊ถ๊ธ์ฆ์ด ๋ง์๋ค.
๊ทธ๋์ Access Token๊ณผ Refresh Token ๊ฐ๋
๋ถํฐ Refresh Token์ ์๋ฒ, ํนํ Redis์ ์ ์ฅํด์ผ ํ๋ ์ด์ ๊น์ง ํ ๋ฒ์ ๊น๋ํ๊ฒ ์ ๋ฆฌํด๋ณด๋ ค๊ณ ํ๋ค.
๐ Access Token์ด๋?!
๋ก๊ทธ์ธํ๋ฉด ๋ฐ๊ธ๋ฐ๋ ์งง์ ์๋ช
์ ํ ํฐ์ด๋ค. (ex. 30๋ถ)
์ฌ์ฉ์๋ ๋งค ์์ฒญ๋ง๋ค Access Token์ HTTP ํค๋์ ๋ด์ ๋ณด๋ด๊ณ , ์๋ฒ๋ ์ด ํ ํฐ์ ๊ฒ์ฌํด์
"์ด ์ฌ์ฉ์๊ฐ ์ธ์ฆ๋ ์ฌ์ฉ์์ธ์ง" ํ์ธํ๋ค.
Access Token์ ์๋ช
์ด ์งง๊ธฐ ๋๋ฌธ์, ๋ง๋ฃ๋๋ฉด ๋ค์ ๋ก๊ทธ์ธํด์ผ ํ๋ค.
๐ฏ ๋ชฉ์
"์ด ์ฌ์ฉ์๊ฐ ์ธ์ฆ๋ ์ฌ์ฉ์์ธ์ง ํ๋จํ๊ธฐ ์ํด ์ฌ์ฉํ๋ค."
๐ Refresh Token์ด๋?!
Access Token์ด ๋ง๋ฃ๋ ๋๋ง๋ค ๋ก๊ทธ์ธํ๋ฉด ์ฌ์ฉ์ ๊ฒฝํ(UX)์ด ๋๋ฌด ๋๋น ์ง๋ค.
Refresh Token์ ์ด๋ฐ ๋ถํธ์ ํด๊ฒฐํ๊ธฐ ์ํด ๋ฑ์ฅํ๋ค.
๐ Access Token์ด ๋ง๋ฃ๋์ ๋, ์๋ก์ด Access Token์ ๋ฐ๊ธ๋ฐ๊ธฐ ์ํ ํ ํฐ
๐ ์ฌ์ฉ์์๊ฒ ๋
ธ์ถ๋์ง๋ง, ์๋ฒ์๋ ์ ์ฅ๋๋ค.
๐ ์๋ช
์ด ๊ธธ๋ค. (7์ผ ~ 30์ผ ์ด์)
๐ฏ ๋ชฉ์
"Access Token์ด ๋ง๋ฃ๋์ง๋ง, ์ฌ์ฉ์๊ฐ ๋ก๊ทธ์ธ ์ํ๋ฅผ ์ ์งํ ์ ์๊ฒ ํ๋ค."
Access Token vs Refresh Token
ํญ๋ชฉ | Access Token | Refresh Token |
์ฉ๋ | ์ธ์ฆ(Authentication) | Access Token ์ฌ๋ฐ๊ธ |
์๋ช | ์งง์ (15~30๋ถ) | ๊น (7~30์ผ) |
์ ์ฅ ์์น | ๋ธ๋ผ์ฐ์ (๋ฉ๋ชจ๋ฆฌ/์ฟ ํค) | ๋ธ๋ผ์ฐ์ + ์๋ฒ (Redis ๋ฑ) |
๋ ธ์ถ ๊ฐ๋ฅ์ฑ | ์๋์ ์ผ๋ก ์์ | ํ์ทจ ์ ์ํ ๋์ |
๋ณด์ ๊ด๋ฆฌ ๋ฐฉ์ | ์งง์ ๋ง๋ฃ ์๊ฐ์ผ๋ก ํด๊ฒฐ | ์๋ฒ ์ ์ฅ์๋ฅผ ํตํ ๋ณ๋ ๊ด๋ฆฌ ํ์ |
๊ทธ๋ ๋ค๋ฉด.. Refresh Token์ ์ ํ์ํ๊ฐ?
๊ฐ๋จํ๊ฒ ์ธ์ฆ ํ๋ฆ์ ์์ํด ๋ณด์.
1. ์ฌ์ฉ์๊ฐ ๋ก๊ทธ์ธ → Access Token ๋ฐ๊ธ
2. 30๋ถ ๋ค Access Token ๋ง๋ฃ
3. ๋ค์ ๋ก๊ทธ์ธํ๋ ค๊ณ ํ๋ฉด..? ๋๋ฌด ๊ท์ฐฎ๋ค.
๊ทธ๋์ Access Token์ด ๋ง๋ฃ๋๋๋ผ๋, Refresh Token์ ์ฌ์ฉํด์ ์๋์ผ๋ก ์ฌ๋ฐ๊ธํ๋ ๊ตฌ์กฐ๋ฅผ ๋ง๋ ๋ค.
๊ทธ ๋๋ถ์ ์ฌ์ฉ์๋ ๋ก๊ทธ์ธ ์ํ๋ฅผ ์ ์งํ ์ ์๋ค!
Refresh Token ๋์ ํ๋ฆ
[๋ก๊ทธ์ธ ์]
โฌ๏ธ
Access Token + Refresh Token ๋ฐ๊ธ
โฌ๏ธ
Access Token์ ํด๋ผ์ด์ธํธ์ ์ ์ฅ
Refresh Token์ ์๋ฒ(์: Redis)์ ์ ์ฅ
โฌ๏ธ
[Access Token ๋ง๋ฃ ์]
โฌ๏ธ
Refresh Token์ผ๋ก Access Token ์ฌ๋ฐ๊ธ ์์ฒญ
โฌ๏ธ
์๋ฒ๊ฐ Redis์์ Refresh Token ๊ฒ์ฆ → ์ Access Token ๋ฐ๊ธ
Refresh Token ๋์ ์ ์ฃผ์์ฌํญ
๐ Redis ๊ฐ์ ์ ์ฅ์๋ฅผ ์ฌ์ฉํด์ ์๋ฒ์ Refresh Token์ ์ ์ฅํด์ผ ํ๋ค.
๐ Refresh Token ์ ํจ์ฑ ๊ฒ์ฌ๋ฅผ ๊ผญ ๊ตฌํํด์ผ ํ๋ค.
๐ ๋ก๊ทธ์์ ์ Refresh Token ์ญ์ ์ฒ๋ฆฌ๋ ํ์๋ค! (๋ณด์ ๋ฌธ์ ๋๋น)
๐ป ์ฝ๋ ์์
JwtUtil : Refresh Token ์์ฑ
// Refresh Token ์์ฑ
public String createRefreshToken(Long memberId) {
Date now = new Date();
return BEARER_PREFIX + Jwts.builder()
.setSubject(String.valueOf(memberId))
.setIssuedAt(now)
.setExpiration(new Date(now.getTime() + REFRESH_TOKEN_EXPIRATION))
.signWith(key, signatureAlgorithm)
.compact();
}
AuthService : ๋ก๊ทธ์ธ ์ Access + Refresh ๋ฐ๊ธ
public LoginResponse login(LoginRequest request) {
Member member = memberRepository.findByEmail(request.email())
.orElseThrow(() -> new NotFoundException(ErrorCode.MEMBER_NOT_FOUND));
if (!passwordEncoder.matches(request.password(), member.getPassword())) {
throw new UnauthorizedException(ErrorCode.INVALID_PASSWORD);
}
String accessToken = jwtUtil.createToken(
member.getId(),
member.getEmail(),
member.getNickname(),
member.getAuthority());
String refreshToken = jwtUtil.createRefreshToken(member.getId());
return LoginResponse.from(accessToken, refreshToken);
}
๊ทธ๋ผ.. Refresh Token์ ์ด๋๋ค ์ ์ฅํด์ผ ํ ๊น?
Access Token๊ณผ Refresh Token ๊ฐ๋ ์ ์ดํดํ๋ค๋ฉด, ์ด์ ์ด๋ฐ ๊ณ ๋ฏผ์ด ๋ฐ์ํ๋ค.
"Refresh Token์ ํด๋ผ์ด์ธํธ์๋ง ์ ์ฅํด๋ ๊ด์ฐฎ์๊น..?"
ํ์ง๋ง Refresh Token์ ์๋ช
์ด ๊ธธ๊ณ , ํ์ทจ๋ ๊ฒฝ์ฐ ๋ณด์์ ํฐ ๋ฌธ์ ๊ฐ ๋ ์ ์๋ค.
๊ทธ๋์ ๋ง์ ์์คํ
์์๋ Refresh Token์ Redis ๊ฐ์ ๋น ๋ฅธ ์ ์ฅ์์ ์์ ํ๊ฒ ๋ณด๊ดํ๋ ๋ฐฉ์์ ํํ๋ค.
Refresh Token์ Redis์ ์ ์ฅํด์ผ ํ๋ ์ด์
์๋ฒ๊ฐ Refresh Token์ ๊ด๋ฆฌํด์ผ ํ๋ค.
Access Token์ ํด๋ผ์ด์ธํธ๋ง์ผ๋ก ์ถฉ๋ถํ์ง๋ง, Refresh Token์ ์๋ฒ ์ ์ฅ์ด ํ์์ด๋ค.
์๋ฒ์ ์ ์ฅํ์ง ์์ผ๋ฉด ํํดํ ์ฌ์ฉ์, ๋ก๊ทธ์์ํ ์ฌ์ฉ์์ Refresh Token์ด ์ด์์์ ์ ์๋ค. (๋ณด์ ์ํ)
Redis๊ฐ ์ ํฉํ ์ด์
ํน์ง | ์ค๋ช |
TTL ์ค์ ๊ฐ๋ฅ | ํ ํฐ ๋ง๋ฃ ์์ ์ ๋ง์ถฐ ์๋ ์ญ์ |
Key-Value ๊ตฌ์กฐ | memberId → refreshToken ๋งคํ์ด ๊ฐ๋จ |
๋น ๋ฅธ ์๋ | in-memory ๊ธฐ๋ฐ ์กฐํ/์ญ์ |
์ธ์ ๋ฆฌ์ค ์๋ฒ ํธํ | JWT + Redis = ์ธ์ ๋ฆฌ์ค ๊ตฌ์กฐ ๊ฐ๋ฅ |
๋ณต์ ๊ธฐ๊ธฐ ์ง์ | ๊ธฐ๊ธฐ๋ณ Refresh Token ๊ด๋ฆฌ ๊ฐ๋ฅ |
DB์ ์ ์ฅํ์ง ์๋ ์ด์
์ด์ | ์ค๋ช |
๋์คํฌ IO ๋ถ๋ด | ์์ฑ/์ญ์ ์ฆ์์ ๋ถํ ํผ |
์์์ฑ ๋ถํ์ | ํ ํฐ์ ์์ ๋ฐ์ดํฐ |
TTL ๊ด๋ฆฌ ๋ณต์ก | DB๋ ์๋ ๋ง๋ฃ ๊ด๋ฆฌ๊ฐ ์ด๋ ค์ |
ํ๋ก์ ํธ์ ์ ์ฉํด ๋ณด๋ฉด์ ๋๋ ์
์ด๋ฒ ํ๋ก์ ํธ์์๋ ๋จ์ํ Access Token๊ณผ Refresh Token ๊ฐ๋
๋ง ๊ณต๋ถํ ๊ฒ ์๋๋ผ, ์ง์ JWT ์ธ์ฆ ์์คํ
์ ์ค๊ณํ๊ณ ์ ์ฉํด ๋ณด๋ ๊ฒฝํ์ ํ ์ ์์๋ค.
๐ Refresh Token์ ๋จ์ ์ ์ฅ์ด ์๋๋ผ ์๋ฒ์์ ๋ณ๋๋ก ๊ด๋ฆฌํด์ผ ํ๋ค๋ ๊ฒ
๐ DB ๋์ Redis๋ฅผ ์จ์ผ ํ๋ ์ด์ ๋ฅผ ์ง์ ์ฒด๊ฐ
๋จ์ํ ๊ธฐ๋ฅ๋ง ๊ตฌํํ๋ ๊ฐ๋ฐ์๊ฐ ์๋๋ผ, ๋ณด์๊ณผ ์ด์๊น์ง ๊ณ ๋ฏผํ๋ ๊ฐ๋ฐ์๊ฐ ๋์ด์ผ๊ฒ ๋ค๋ ๋ค์ง์ ํ๊ฒ ๋์๋ค!