- fix/sso-refresh-session-restore 브랜치의 변경 배경과 목적 정리 - refreshToken 기반 SSO 세션 복원과 토큰 응답 보강 내용을 문서화 - 검증 포인트와 frontend 계약 변화를 함께 정리
8.2 KiB
fix/sso-refresh-session-restore 설명 문서
1. 문서 목적
이 문서는 backend 프로젝트 api의 fix/sso-refresh-session-restore 브랜치에서 반영한 SSO 세션 복원 및 토큰 응답 보강 변경을 설명합니다.
핵심 목적은 다음 두 가지입니다.
ALIST_SSO쿠키가 없더라도, 유효한refreshToken이 있으면 SSO 세션을 복원할 수 있게 한다.- frontend direct API 흐름에서 필요한
accessToken값을/auth/access,/auth/refresh응답 body로도 내려준다.
2. 배경 문제
기존 흐름에서는 SSO 관련 엔드포인트가 주로 ALIST_SSO 쿠키를 기준으로 로그인 상태를 판단했습니다.
이 구조에서는 다음 문제가 있었습니다.
-
브라우저에
refreshToken은 남아 있지만ALIST_SSO쿠키가 사라진 경우/sso/loginChecked/sso/authorize/auth/access에서 로그인 상태를 복원하지 못했습니다.
-
frontend가 direct API 흐름으로 변경되면서
POST /auth/accessPOST /auth/refresh응답 body의accessToken을 직접 사용하도록 바뀌었는데, backend 응답은 cookie만 세팅하고 body에는 토큰을 충분히 내려주지 않았습니다.
즉, refreshToken 기반 세션 복원과 frontend 계약(body accessToken) 이 동시에 필요했습니다.
3. 변경 대상 파일
이 브랜치의 핵심 변경 파일은 아래 7개입니다.
src/main/java/com/alist/api/modules/auth/AuthController.javasrc/main/java/com/alist/api/modules/auth/SsoController.javasrc/main/java/com/alist/api/modules/auth/dto/SsoAuthorizeDto.javasrc/main/java/com/alist/api/modules/auth/service/AuthService.javasrc/main/java/com/alist/api/modules/auth/service/SsoService.javasrc/main/java/com/alist/api/modules/auth/vo/LoginTokenVo.javasrc/main/resources/mapper/auth/LoginMapper.xml
4. 핵심 변경 요약
4-1. refreshToken 기반 SSO 세션 복원 추가
SsoService에 아래 역할이 추가되었습니다.
loginChecked(String ssoSessionId, String refreshToken)resolveOrRestoreSsoSessionId(String ssoSessionId, String refreshToken)restoreSsoSessionIfNeeded(String ssoSessionId, String refreshToken)loadSsoSession(String ssoSessionId)
동작 방식은 아래와 같습니다.
- 먼저 기존
ALIST_SSO쿠키 값(ssoSessionId)이 있으면 그대로 사용합니다. ssoSessionId가 없으면refreshToken으로 사용자 토큰 정보를 조회합니다.- 유효한 사용자가 확인되면
- 기존 최신 SSO 세션이 있으면 TTL을 연장해서 재사용하고
- 없으면 Redis에 새로운 SSO 세션을 다시 생성합니다.
- 이후
loginChecked,authorize,access는 복원된 SSO 세션 기준으로 정상 동작합니다.
즉, SSO 쿠키가 비어 있어도 refreshToken만 유효하면 공통 로그인 상태를 다시 살릴 수 있게 변경되었습니다.
4-2. /auth/access 응답 강화
AuthController.access() 변경 내용:
@CookieValue(name = "refreshToken", required = false)를 추가하여 refreshToken을 입력으로 받습니다.ssoService.loginChecked(ssoSessionId, refreshToken)을 사용해 SSO 세션을 복원 가능하게 했습니다.- 세션 복원 결과에
ssoSessionId가 있으면ALIST_SSO쿠키를 다시 발급합니다. - 응답 body에 아래 값을 포함합니다.
isAccessTokenuserIdxuserIduserRoleaccessToken
즉, /auth/access는 이제 토큰 쿠키 발급 + frontend용 JSON body accessToken 제공을 같이 수행합니다.
4-3. /auth/refresh 응답 강화
AuthController.refresh() 변경 내용:
- 기존처럼
accessToken,refreshToken쿠키는 재발급합니다. - 추가로 응답 body에 아래 값을 내려줍니다.
refreshed: trueaccessToken
이 변경으로 frontend는 refresh 성공 후 cookie에만 의존하지 않고, 응답 body의 accessToken으로 즉시 service-local 토큰을 다시 기록할 수 있습니다.
4-4. /sso/loginChecked 개선
SsoController.loginChecked() 변경 내용:
refreshTokencookie를 함께 입력으로 받습니다.ssoService.loginChecked(ssoSessionId, refreshToken)을 사용합니다.- access/refresh token 존재 여부를 기존처럼 함께 반환합니다.
- SSO 세션이 복원되면
ALIST_SSO쿠키를 다시 써줍니다.
즉, /sso/loginChecked는 더 이상 단순 조회가 아니라 필요 시 세션 복원까지 수행하는 확인 엔드포인트가 되었습니다.
4-5. /sso/authorize 개선
SsoController.authorize()와 SsoService.authorize() 변경 내용:
refreshTokencookie를 함께 전달받아 세션 복원에 사용합니다.- authorize 성공 시
SsoAuthorizeDto에ssoSessionId를 실어주고, - controller에서 해당 값을 기준으로
ALIST_SSO쿠키를 재발급합니다.
즉, 사용자가 이미 refreshToken을 가지고 있다면 SSO 쿠키가 비어 있어도 authorize 진입 시 다시 공통 로그인 상태를 회복할 수 있습니다.
4-6. refreshToken 조회용 Auth 계층 보강
AuthService와 DB 조회 쪽에는 아래 보강이 들어갔습니다.
findUserTokenByRefreshToken(String refreshToken)추가LoginTokenVo에userIdx,userId필드 추가LoginMapper.xml의selectUserTokenByUserTokenIdx가user_idx,user_id,user_role,refresh_token을 함께 조회
이 변경은 SSO 세션 복원 시, 단순 token 유효성 확인을 넘어서 어떤 사용자의 세션을 복구해야 하는지 식별하기 위해 필요합니다.
5. 변경 후 기대 동작
시나리오 A. ALIST_SSO 없음 + refreshToken 유효
POST /auth/access- SSO 세션 복원 성공
ALIST_SSO재발급accessToken/refreshToken재발급- body에
accessToken포함
시나리오 B. GET /sso/loginChecked
- 기존에는 로그인 false로 끝날 수 있었던 상황에서
- 이제 refreshToken이 유효하면 loggedIn true로 복원 가능
시나리오 C. GET /sso/authorize
- 기존에는
ALIST_SSO없으면/login으로 fallback - 이제 refreshToken으로 세션 복원 가능하면 정상 authorize 진행
시나리오 D. POST /auth/refresh
- cookie 재발급뿐 아니라 body에도
accessToken제공 - frontend가 바로 service-local accessToken을 다시 쓸 수 있음
6. frontend와의 계약 변화
이 브랜치는 frontend의 direct API 흐름과 맞물려 있습니다.
frontend는 현재 아래 계약을 기대합니다.
POST /auth/access응답 body에accessTokenPOST /auth/refresh응답 body에accessToken
따라서 이 브랜치 변경은 단순 backend 내부 개선이 아니라, frontend의 direct login / callback / refresh 흐름을 안정적으로 지원하는 계약 변경이기도 합니다.
7. 운영상 의미
이 변경을 적용하면 다음이 좋아집니다.
- SSO 쿠키 유실 상황에서 세션 복원력이 높아짐
- cross-domain authorize 진입 시 로그인 유지가 더 안정적임
- frontend가 refresh 후 토큰 재반영을 더 단순하게 처리할 수 있음
ALIST_SSO와refreshToken을 각각의 역할에 맞게 유지하면서도 사용자 체감 로그인 끊김을 줄일 수 있음
8. 검증 포인트
배포 또는 MR 검토 시 아래를 확인하는 것이 좋습니다.
-
POST /auth/accessALIST_SSO없이refreshToken만 있을 때 200 또는 정상 복원되는지- response body에
accessToken이 포함되는지
-
POST /auth/refresh- response body에
accessToken이 포함되는지
- response body에
-
GET /sso/loginCheckedrefreshToken만으로loggedIn=true가 가능한지
-
GET /sso/authorizeALIST_SSO가 없더라도 refreshToken 기반으로 redirect가 이어지는지
-
Redis 상태
alist:sso:userIdx:*alist:sso:session:*키가 복원/갱신되는지
9. 한 줄 요약
fix/sso-refresh-session-restore 브랜치는 refreshToken만 남아 있는 상황에서도 SSO 세션을 복원하고, /auth/access 및 /auth/refresh가 frontend가 바로 사용할 수 있는 accessToken을 응답 body로 반환하도록 보강한 변경입니다.