홈 › 인증·로그인 › 02 / 3

2단계: Access/Refresh 토큰과 OAuth2 인가 코드

섹션 7진행 0 / 3

2단계: Access/Refresh 토큰과 OAuth2 인가 코드

1단계에서 만든 JWT 로그인의 약점 "한 번 발급한 토큰은 취소할 수 없다" 를 해결합니다. 토큰을 짧은 Access 와 긴 Refresh 로 나누고, Refresh 를 쓸 때마다 교체(회전)하고, 재사용이 감지되면 세션 전체를 끊습니다. Refresh 는 HttpOnly 쿠키로만 다룹니다. 후반부는 "구글로 로그인" 의 실체인 OAuth2 인가 코드 흐름을 인가 서버·리소스 서버·클라이언트 앱 세 개의 HttpServer 로 직접 구현하고, PKCE 와 state 가 각각 어떤 공격을 막는지 코드 가로채기·로그인 CSRF·코드 재사용을 실제로 시도해 확인합니다. 순수 JDK 이며, 마지막에 Spring Security OAuth2 Client / Resource Server 대응표로 정리합니다.

1. 왜 배우는가

1단계 서버는 로그인하면 1시간짜리 JWT 를 줬습니다. 이 방식에는 실무에서 바로 부딪히는 문제가 셋 있습니다.

첫째, 로그아웃이 안 됩니다. JWT 는 서버가 아무것도 기억하지 않는 대신, 서명이 맞으면 exp 까지 무조건 유효합니다. 사용자가 로그아웃 버튼을 눌러도, 관리자가 계정을 정지해도, 이미 나간 토큰은 1시간 동안 살아 있습니다. 토큰이 유출됐다면 1시간 동안 공격자가 그 사용자입니다.

둘째, TTL 을 줄이면 사용자가 불편합니다. 5분마다 로그인 화면이 뜨는 서비스는 없습니다. 그래서 "짧은 토큰 + 그것을 조용히 갱신하는 긴 토큰" 이라는 두 층 구조가 나왔고, 그 긴 토큰(Refresh)을 어떻게 저장·전달·폐기하느냐가 로그인 보안의 핵심이 됩니다.

셋째, 비밀번호를 우리가 받지 않는 로그인이 필요합니다. "구글로 로그인", "회사 SSO 로 로그인" 은 사용자의 비밀번호가 우리 서버를 거치지 않습니다. 대신 구글이 "이 사용자가 맞고, 프로필 읽기를 허락했다" 는 증표(토큰)를 줍니다. 이 위임 절차의 표준이 OAuth2 이고, 그 중 웹에서 쓰는 방식이 인가 코드(Authorization Code) 흐름입니다.

실무 프로젝트(icr)에도 SAML SSO 가 붙어 있는데, SAML 과 OAuth2 는 형식만 다를 뿐 "외부에 인증을 맡기고 증표를 받아 온다" 는 구조가 같습니다.

이 레슨을 끝내면 Spring Security 설정의 oauth2Login(), oauth2ResourceServer(), application.yml 의 client-id / redirect-uri / scope 가 각각 세 서버 중 어느 역할의 어느 단계인지 보이게 됩니다.