인증(Authentication)과 인가(Authorization)
✅ 인증 (Authentication)
사용자의 신원을 확인하는 작업이다.
✅ 인가(Authorization)
인증된 사용자가 특정 리소스에 대한 접근 권한을 가지고 있는지 확인하는 과정으로 “어서와 ~” 로 기억해보자 !
JWT의 경우, 사용자의 신원을 나타내는 정보를 안전하게 클라이언트와 서버 간에 주고받기 위한 방식으로 설계되었으므로 “인증”의 개념과 더 밀접하게 연관이 있다.
JWT (Json Web Token) 이란 ?
JWT(JSON Web Token)란 인증에 필요한 정보들을 암호화시킨 JSON 토큰을 의미한다. 그리고 JWT 기반 인증은 JWT 토큰(Access Token)을 HTTP 헤더에 실어 서버가 클라이언트를 식별하는 방식이다
JWT 구조
JWT는 . 을 구분자로 나누어지는 세 가지 문자열의 조합이다.
. 을 기준으로 좌측부터 Header, Payload, Signature를 의미한다.
https://jwt.io/ 에서 서버에서 생성한 JWT를 넣기만 해도 볼 수 있는 화면이다. JWT에서 header와 payload는 특별한 암호화 없이 흔히 사용할 수 있는 base64 인코딩을 사용하기 때문에 서버가 아니더라도 그 값을 확인할 수 있다.
☑️ Header
헤더에는 토큰의 타입이나 서명 생성에 어떤 알고리즘이 사용되었는지 저장한다.
{
"alg": "HS256",
"typ": "JWT"
}
☑️ Payload
토큰에서 사용할 정보의 조각들인 Claim(key-value 형식으로 이루어진 한 쌍의 정보)이 담겨있다. 서버와 클라이언트가 주고 받는 시스템에서 실제로 사용될 정보에 대한 내용을 담고 있다.
{
"sub": "1234567890",
"name": "John Doe",
"iat": 1516239022
}
Claims의 종류
- Registered Claims : 미리 정의된 Claims
- iss(issuer) : 발행자
- exp(expiration time) : 만료시간
- sub(subject) : 제목
- iat(issued At) : 발행 시간
- jti(JWT ID) : 토큰의 고유 식별자
- Public Claims : 사용자가 정의할 수 있는 클레임, 공개용 정보 전달 목적
- Private Claims : 사용자 지정 클레임, 당사자들 간에 정보를 공유하기 위한 목적
☑️ Signature
헤더에서 정의한 알고리즘 방식(alg)를 활용한다. Signature는 header와 payload를 디코딩한 값을 합치고 이를 your-256-bit-secret, 즉 서버가 가지고 있는 개인키로 암호화된 상태다.
따라서 Signature는 서버에 있는 개인키로만 암호화를 풀 수 있고 다른 클라이언트는 임의로 Signature를 복호화할 수 없다.
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
your-256-bit-secret
) secret base64 encoded
base64UrlEncode는 값을 URL에서 사용할 수 있도록 +, /를 각각 -, _로 표기한다.
Header와 Payload는 Encoding된 값이기 때문에 복호화 혹은 값을 수정할 수 있지만 Signature는 서버에서 관리하는 값이기 때문에 Secret Key가 유출되지 않는 이상 복호화 할 수 없다.
JWT를 이용한 인증 과정
1️⃣ 클라이언트가 로그인 요청
- 사용자가 아이디와 비밀번호 등의 인증 정보를 입력하여 POST 요청을 통해서버로 전송한다.
POST /login HTTP/1.1
Content-Type: application/json
{
"username": "user123",
"password": "securepassword"
}
2️⃣ 서버에서 사용자 정보 확인 및 JWT 생성
- 서버는 전달받은 사용자 정보를 DB에서 확인하여 사용자를 인증한다.
- 인증 성공 시 사용자의 신원을 나타내는 정보(Header, Payload, Signature)를 담아 JWT를 생성하고 Access Token과 Refresh Token을 발급한다.
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJ1c2VySWQiOiJ1c2VyMTIzIiwidXNlcm5hbWUiOiJKb2huIERvZSIsImV4cCI6MTcxMDIzNDU2NywiaWF0IjoxNzEwMjMwOTY3fQ.
0FHwVL3JpcyV5zxkXHcHyiycmEKb2h_yIk6sS0ebqD0
3️⃣ 서버가 클라이언트에게 JWT 발급(전달)
- 서버는 생성된 Access Token 과 Refresh Token 을 클라이언트에게 반환한다.
- 클라이언트는 받은 JWT를 저장한다. (보통 Local Storage, 쿠키, 또는 Secure Storage 사용)
HTTP/1.1 200 OK
Content-Type: application/json
{
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
4️⃣ 클라이언트가 이후 요청에 JWT 포함
- 클라이언트는 인증이 필요한 요청 시, 서버에서 발급받은 JWT를 HTTP 헤더의
Authorization
헤더에 담아 서버에 보낸다.
GET /user/profile
Authorization: Bearer <JWT토큰값>
5️⃣ 서버가 JWT 검증 후 인증 처리
- 서버는 클라이언트의 요청을 받을 때마다 JWT를 검증한다.
JWT 검증 과정은 다음과 같다.
✅ 서명(Signature) 검증 : 서버가 가지고 있는 비밀키로 JWT 서명을 검증하여 변조되지 않았는지 확인
✅ 유효기간(expiration time, exp) 검증 : 토큰이 만료되었는지 확인
✅ 필요한 사용자 정보가 JWT에 존재하는지 확인(선택적)
JWT 유효성 검증 절차
- A의 JWT를 B가 탈취
- B가 탈취한 JWT를 임의로 수정
- B가 수정한 JWT로 Server에 요청
- 서버는 Signature를 사용하여 유효성 검사(Signature 불일치)
- Header, Payload를 서버의 Secret Key값을 이용해 Signature를 다시 만들어 비교한다.
- 임의로 조작된 데이터를 판별할 수 있다.
6️⃣ Access Token 만료 시 Refresh Token으로 갱신
- 만약 Access Token이 만료되었다면 클라이언트는 Refresh Token 을 이용하여 새로운 Access Token 을 요청한다.
POST /auth/refresh
{
"refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
더 자세한 내용은 해당 동영상을 참고하면 된다.
https://www.youtube.com/watch?v=1QiOXWEbqYQ
https://www.youtube.com/watch?v=XXseiON9CV0
JWT의 장단점 및 한계
JWT의 장점
- Header와 Payload를 가지고 Signature를 생성하므로 데이터 위변조를 막을 수 있다.
- 인증 정보에 대한 별도의 저장소가 필요없고, 클라이언트 인증 정보를 저장하는 세션과 다르게 서버는 무상태가 되어 서버 확장성이 우수해질 수 있다.
- OAuth의 경우, 소셜 계정을 이용하여 다른 웹 서비스에서도 로그인이 가능하다.
- 토큰 기반으로 다른 로그인 시스템에 접근 및 권한 공유가 가능하다. (쿠키와의 차이점)
JWT의 단점 및 한계
- base64 인코딩을 통한 정보를 전달하므로 전달량이 많다. 따라서 네트워크 전달 시 많은 데이터 양으로 부하가 생길 수 있다.
- Payload는 암호화가 되어있지 않으므로 민감 정보를 저장할 수 없다.
- 토큰이 탈취당하면 만료될 때까지 대처가 불가능하다.
AccessToken과 RefreshToekn
JWT 토큰이 탈취 당했을 경우, 서버는 토큰의 주인인 클라이언트와 토큰을 탈취한 도둑을 구분할 수 없다. 따라서 유효 기간을 둔다. 그러나 유효기간을 짧게 두면 사용자가 로그인을 자주 해야하므로 사용자 경험적으로 좋지 않고, 유효기간을 길게 두면 보안상 탈취 위험에서 벗어날 수 없다.
따라서 유효기간이 다른 JWT 토큰 두 개, AccessToken과 RefreshToekn이 등장했다.
기본적인 개념
Access Token
의 유효기간은 짧다. (ex. 60일(마이크로소프트), 1시간(아마존))Refresh Token
의 유효기간은 길다. (ex. 1년 (마이크로소프트))- 평소에 API 통신할 때는 Access Token을 사용하고, Refresh Token은 Access Token이 만료되어 갱신될 때만 사용한다.
구체적인 동작과정
1️⃣사용자 로그인 요청 (POST /login
)
사용자가 아이디와 비밀번호를 입력하여 서버에 로그인 요청을 보낸다.
2️⃣Access Token + Refresh Token 발급
서버는 사용자를 인증한 후, Access Token과 Refresh Token을 발급한다.
- Access Token: 유효 기간이 짧아(수 분~수 시간) 보안성이 높음
- Refresh Token: 유효 기간이 길며(수 일~수 주), Access Token이 만료될 경우 새로운 Access Token을 발급하는 데 사용됨
클라이언트는 Access Token을 저장하여 이후 API 요청에 사용합니다.
3️⃣ API 요청 시 Access Token 사용 (GET /user/profile
)
사용자는 로그인이 완료된 후, 프로필 조회와 같은 API 요청을 보낼 때 Authorization 헤더에 Access Token을 포함하여 서버에 요청을 보낸다.
4️⃣ 서버에서 Access Token 검증
서버는 요청을 받으면 Access Token이 유효한지 확인한다.
- 유효한 경우 : 정상적으로 요청을 처리하고 데이터를 반환한다.
- 만료된 경우: 클라이언트에게 만료되었음을 응답하고 Refresh Token을 사용하여 새 Access Token을 요청하도록 안내한다.
5️⃣ Access Token 만료 시, Refresh Token을 이용해 새 Access Token 요청 (POST /auth/refresh
)
클라이언트는 만료된 Access Token을 삭제하고, Refresh Token을 포함하여 새로운 Access Token을 요청한다.
6️⃣ 서버에서 Refresh Token 검증 후 새로운 Access Token 발급
서버는 Refresh Token이 유효한지 확인한 후, 새로운 Access Token을 생성하여 클라이언트에게 반환한다.
- Refresh Token도 만료되지 않았다면 새로운 Access Token을 발급한다.
- 만약 Refresh Token이 만료되었거나 유효하지 않다면, 사용자는 다시 로그인해야한다.
7️⃣ 새로운 Access Token을 사용하여 API 요청 (GET /user/profile
)
클라이언트는 발급받은 새로운 Access Token을 저장한 후, 다시 API 요청을 보낸다.
이후부터는 새로운 Access Token을 이용하여 정상적인 API 요청을 수행할 수 있다.
8️⃣ Refresh Token도 만료된 경우 → 재로그인 필요
만약 Refresh Token도 만료되었다면, 서버는 더 이상 새 Access Token을 발급해주지 않고,사용자가 다시 로그인해야 함을 응답한다.
사용자는 재로그인하여 새로운 Access Token과 Refresh Token을 받아야 한다.
'Backend > Spring' 카테고리의 다른 글
적절한 책임 분리 - Helper Class (0) | 2025.04.01 |
---|---|
BaseTimeEntity와 JPA Auditing: 왜 사용할까? (0) | 2025.04.01 |
JPA와 영속성 컨텍스트 (0) | 2025.03.31 |
[Spring 기초] 일정 관리 앱 만들기 (0) | 2025.03.26 |
쿠키 세션 토큰 비교하기 (0) | 2025.03.24 |