1. 이번 작업의 목표
지난 작업에서는 이메일과 비밀번호로 로그인하고 JWT Access Token을 발급했다.
이번에는 발급한 토큰을 실제 API 요청에서 검증하고, 인증된 사용자만 보호된 API에 접근하도록 구성했다.
클라이언트는 요청 헤더에 다음 형식으로 토큰을 전달한다.
Authorization: Bearer <accessToken>
서버는 전달받은 토큰의 서명과 만료시간을 검증한 뒤 인증 정보를 등록한다.
2. Spring Security Resource Server 적용
처음에는 JWT 인증 필터를 직접 구현할 계획이었다. 요청 헤더에서 토큰을 추출하고, 검증한 뒤 인증 정보를 등록하는 흐름을 작성하려고 했다.
이후 Spring Security Resource Server가 해당 인증 흐름을 제공한다는 것을 확인하고 프로젝트에 적용했다. 직접 관리할 인증 코드를 줄이고, Spring Security의 필터 체인을 활용하기 위한 선택이었다.
Security 설정에는 다음 코드를 추가했다.
.oauth2ResourceServer(oauth2 ->
oauth2.jwt(withDefaults())
)
이 설정과 JwtDecoder를 연결해 Bearer Token 기반 JWT 인증을 처리하도록 구성했다.
검증에 성공하면 Spring Security가 JwtAuthenticationToken을 생성하고, 현재 요청의 인증 정보를 보관하는 SecurityContext에 등록한다.
3. JwtDecoder와 사용자 식별
토큰 발급에 사용한 Secret Key와 HS256 알고리즘을 검증에도 동일하게 사용하도록 JwtDecoder를 구성했다.
역할은 다음과 같이 나뉜다.
JwtEncoder → 로그인 성공 시 Access Token 발급
JwtDecoder → API 요청으로 전달된 Access Token 검증
로그인할 때 토큰의 sub에는 사용자 ID를 저장했다. 인증이 완료되면 이 값을 이용해 요청한 사용자를 식별할 수 있다.
전체 인증 흐름은 다음과 같다.
Authorization 헤더로 토큰 전달
→ JwtDecoder로 서명·만료시간 검증
→ 인증 객체 생성
→ SecurityContext 등록
→ 보호 API 접근
이 인증 정보를 이후 메모와 일정 API에서 사용자 기준으로 데이터를 처리하는 데 활용할 예정이다.
4. 공개 API와 보호 API 구분
회원가입과 로그인처럼 인증 전에 필요한 API는 공개 경로로 유지했다.
GET /api/health
POST /api/auth/signup
POST /api/auth/signin
GET /api/auth/check-email
그 외 API는 기본적으로 인증을 요구하도록 구성했다. 보호 API는 유효한 Access Token을 전달해야 접근할 수 있다.
이번 단계에서는 Access Token 인증까지 구현했다. Refresh Token, 토큰 재발급, 로그아웃과 Role 기반 인가는 이후 확장 항목으로 남겼다.
5. 적용 결과
보호 API에 토큰 없이 요청하거나 잘못된 토큰, 만료된 토큰을 전달하면 401 Unauthorized가 반환되는 것을 확인했다.
정상 토큰으로는 보호 API에 접근할 수 있었고, 공개 API는 토큰 없이도 호출할 수 있었다.
이번 작업으로 로그인에서 발급한 Access Token을 실제 API 인증에 연결했다.
다음에는 인증된 사용자의 ID를 활용해 자신의 메모를 작성·조회·수정·삭제할 수 있는 Note CRUD를 구현한다.