JWT - Access Token, Refresh Token은 무엇인가
서버에서 클라이언트 인증을 확인하는 방식으로는 Cookie/ Session / Token 이렇게 3가지 방식이 있다.
JWT에 대해서 알기 전 해당 내용을 간단하게 정리부터 해보려고 한다.
Cookie / Session / Token 인증
Cookie 인증
쿠키는 key-value 형식의 문자열의 모음집이다.
클라이언트가 방문하는 사이트가 사용하고 있는 서버를 통해 클라이언트 브라우저에 저장이 된다.
Cookie의 단점
1. 보안에 취약 : 요청 시 쿠키의 값을 그대로 보여줌
2. 용량 제한 : 많은 정보를 담기 어려움
3. 브라우저마다 지원하는 쿠키의 형태가 다름 : 공유가 불가능
Session 인증
클라이언트의 민감한 인증 정보를 브라우저가 아닌 서버에 저장하고 관리
서버는 세션 ID를 클라이언트에게 전달 (세션 ID를 쿠키나 헤더를 통해 전달) > 서버 측에 저장된 데이터로 토큰을 사용하지 않음
서버의 메모리에 저장, 서버의 로컬 파일이나 데이터베이스에 저장
Session 단점
1. 서버에서 session 저장소를 사용하므로 요청이 많아지면 서버에 부하가 심해짐
Token 인증
인증과 권한 부여를 위한 정보가 담긴 문자열
사용자의 ID, 권한, 만료 시간등의 정보가 담겨있음
아래에서 설명하겠지만 JWT의 경우가 이 방식에 해당된다. (Access Token, Refresh Token)
Session과 Token의 주요 차이점
세션 인증은 서버에서 상태를 관리, 세션 ID를 이용해 인증을 처리
토큰 인증은 클라이언트가 토큰을 관리, 토큰을 이용해 인증을 처리
* 참고로 과제를 진행 중에 Supabase로 로그인을 진행했을 때 Acess Token이 로컬 서버에 저장되는 것을 볼 수 있었다.
하지만 로그인 유무를 처리하기 위해서는 쿠키에 저장해야하는 이슈가 생겨서 accessToken을 쿠키에 저장한 경험이 있다.
위에 Cookie의 단점이 보안이라고 했지만...
HttpOnly와 Secure 플래그를 함께 사용하면 자바스크립트가 쿠키에 접근할 수 없게 만들고 HTTPS연결에서만 쿠키가 전송되게 만들 수 있다.
그럼 이제 JWT 토큰에 대해서 알아보자
JWT(Json Web Token)
웹 어플리케이션에서 사용자 인증 및 정보 교환을 위해 사용되는 토큰 기반의 인증 방식
Header, Payload, Signature 3가지 주용 부분으로 구성된다.
Header는 토큰의 유형과 서명 알고리즘
Payload에는 민감하지 않은 사용자의 정보와 데이터, 토큰의 내용이 담김
Signature는 JWT의 무결성을 보장하기위해 비밀키로 서명하여 서버에서 검증
JWT는 기본적으로 클라이언트-서버 간의 인증을 위해 사용
서버에서 발급, 클라이언트에서 사용
Access Token
서버에서 클라이언트에게 발급되는 인증 토큰
API 요청 시 인증을 위해 사용
클라이언트는 Access Token을 서버에 전송해 인증된 사용자임을 증명, 서버는 검증하고 필요한 리소스를 반환
Access Token 특징
짧은 유효 기간 : 보안을 강화
클라이언트는 로컬 스토리지, 세션 스토리지, 쿠키 등에 저장을 하고 요청 시에 헤더에 포함해서 전송
fetch('/api/protected', {
method: 'GET',
headers: {
'Authorization': `Bearer ${accessToken}`
}
})
위에서 짧은 유효 기간이 특징이라 했는데 Refresh Token을 사용하면 새로운 Access Token을 발급 받을 수 있음
Refresh Token
Access Token의 유효기간이 만료된 후 새로운 Access Token을 다시 발급받기 위해 사용하는 비교적 긴 유효 기간을 가진 토큰
서버에서 관리 되고, 클라이언트가 사용하지 않도록 보호됨
Refresh Token 특징
긴 유효 기간 : 수개월간 유효할 수도 있음, 사용자는 지속적인 인증상태를 유지할 수 있음
서버에서 사용 > 클라이언트인 HTTPOnly 쿠키나 로컬 저장소에 저장
// Refresh Token을 사용하여 새로운 Access Token 요청
fetch('/api/refresh-token', {
method: 'POST',
headers: {
'Authorization': `Bearer ${refreshToken}`
}
})
.then(response => response.json())
.then(data => {
const newAccessToken = data.accessToken;
// 새로운 Access Token을 저장하고 사용
});