코딩:개발일지
JWT vs OAuth2 정리 - 백엔드 개발자가 알아야 할 개념
ZZJJing
2025. 5. 25. 19:36
반응형
■ JWT란?
정의: JSON Web Token의 줄임말, 정보를 안전하게 전송하기 위한 토큰 형식
구조:
Header.Payload.Signature
- Header: 토큰 타입과 해싱 알고리즘
- Payload: 실제 데이터 (Claims)
- Signature: 토큰 검증용 서명
특징:
- Self-contained (토큰 자체에 정보 포함)
- Stateless (서버에 상태 저장 안함)
- Base64로 인코딩됨
- 만료시간 설정 가능
■ OAuth2란?
정의: 인증/인가를 위한 프로토콜, 제3자 앱이 사용자 대신 리소스에 접근할 수 있게 해줌
주요 역할자:
- Resource Owner: 사용자
- Client: 앱
- Authorization Server: 인증 서버
- Resource Server: 리소스 서버
Grant Types:
Grant Type 용도 보안 수준 적용 대상
Authorization Code | 웹앱용 | 가장 안전 | 서버 사이드 앱 |
Implicit | SPA용 | 낮음 (deprecated) | 단일 페이지 앱 |
Client Credentials | 서버간 통신 | 높음 | 백엔드 서비스 |
Resource Owner Password | 신뢰 앱만 | 보통 | 자체 서비스 앱 |
■ 핵심 차이점
구분 JWT OAuth2
성격 | 토큰 형식 | 인증/인가 프로토콜 |
용도 | 정보 전송, 인증 상태 유지 | 제3자 앱 권한 위임 |
상태 | Stateless | Stateful 가능 |
만료 | 토큰 자체에 정의 | 서버에서 관리 |
취소 | 어려움 (만료까지 유효) | 쉬움 (서버에서 제어) |
■ 언제 사용?
구분 JWT OAuth2
코드 예시 | String token = Jwts.builder() <br> .setSubject(userId) <br> .signWith(key).compact(); | @GetMapping("/oauth2/google") <br> OAuth2AuthorizedClient client |
단순 인증/인가 | 적합 | 과도함 |
마이크로서비스 통신 | 적합 | 복잡함 |
모바일 앱 인증 | 적합 | 경우에 따라 |
소셜 로그인 | 불가능 | 필수 |
제3자 API 연동 | 불가능 | 필수 |
세밀한 권한 제어 | 제한적 | 강력함 |
토큰 취소 | 어려움 | 쉬움 |
서버 확장성 | 우수 | 보통 |
■ 함께 사용하기
일반적인 패턴: OAuth2로 인증 후 JWT 발급
@RestController
public class AuthController {
@GetMapping("/oauth2/callback")
public ResponseEntity<TokenResponse> handleCallback(
@RequestParam String code) {
// 1. OAuth2로 사용자 정보 획득
OAuth2User userInfo = oAuth2Service.getUserInfo(code);
// 2. JWT 토큰 생성
String jwtToken = Jwts.builder()
.setSubject(userInfo.getId())
.claim("email", userInfo.getEmail())
.claim("role", userInfo.getRole())
.setExpiration(new Date(System.currentTimeMillis() + 604800000)) // 7일
.signWith(jwtSecret)
.compact();
return ResponseEntity.ok(new TokenResponse(jwtToken));
}
}
## 보안 고려사항
| 구분 | JWT | OAuth2 |
|------|-----|--------|
| **주요 취약점** | XSS 공격 (localStorage 저장 시) | CSRF 공격 |
| **토큰 크기** | 클 수 있음 (정보 포함) | 작음 (참조용) |
| **토큰 취소** | 만료 전까지 불가능 | 언제든 가능 |
| **필수 요구사항** | Secret key 안전 관리 | HTTPS 필수 |
| **추가 보안** | HttpOnly 쿠키 권장 | State 파라미터 CSRF 방지 |
| **검증 방식** | 서명 검증 | Authorization Server 확인 |
| **만료 관리** | 토큰 자체에 포함 | 서버에서 제어 |
## 실제 구현 팁
### JWT 구현 (Spring Boot)
```java
@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
String token = extractTokenFromRequest(request);
if (token == null) {
response.setStatus(HttpStatus.UNAUTHORIZED.value());
return;
}
try {
Claims claims = Jwts.parserBuilder()
.setSigningKey(jwtSecret)
.build()
.parseClaimsJws(token)
.getBody();
String userId = claims.getSubject();
// SecurityContext에 인증 정보 설정
} catch (JwtException e) {
response.setStatus(HttpStatus.FORBIDDEN.value());
return;
}
filterChain.doFilter(request, response);
}
private String extractTokenFromRequest(HttpServletRequest request) {
String bearerToken = request.getHeader("Authorization");
if (bearerToken != null && bearerToken.startsWith("Bearer ")) {
return bearerToken.substring(7);
}
return null;
}
}
OAuth2 구현 (Spring Security)
@Configuration
@EnableWebSecurity
public class OAuth2Config {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.oauth2Login(oauth2 -> oauth2
.loginPage("/login")
.successHandler(customSuccessHandler())
.userInfoEndpoint(userInfo -> userInfo
.userService(customOAuth2UserService())
)
);
return http.build();
}
@Bean
public OAuth2AuthorizedClientService authorizedClientService(
ClientRegistrationRepository clientRegistrationRepository) {
return new InMemoryOAuth2AuthorizedClientService(
clientRegistrationRepository);
}
}
// application.yml 설정
/*
spring:
security:
oauth2:
client:
registration:
google:
client-id: ${GOOGLE_CLIENT_ID}
client-secret: ${GOOGLE_CLIENT_SECRET}
scope:
- profile
- email
*/
JWT: 토큰 형식, 정보 전송 및 상태 유지에 사용
OAuth2: 권한 위임 프로토콜, 제3자 서비스 연동에 사용
둘 다 현대 웹 개발에서 필수적인 기술이며, 상황에 맞게 적절히 조합해서 사용하는 것이 중요함.
728x90
반응형