Files
api2/docs/sso-refresh-session-restore.md
진기정 f389d652d6 [docs] SSO 세션 복원 브랜치 설명 문서 추가
- fix/sso-refresh-session-restore 브랜치의 변경 배경과 목적 정리
- refreshToken 기반 SSO 세션 복원과 토큰 응답 보강 내용을 문서화
- 검증 포인트와 frontend 계약 변화를 함께 정리
2026-04-09 13:00:56 +09:00

8.2 KiB

fix/sso-refresh-session-restore 설명 문서

1. 문서 목적

이 문서는 backend 프로젝트 apifix/sso-refresh-session-restore 브랜치에서 반영한 SSO 세션 복원 및 토큰 응답 보강 변경을 설명합니다.

핵심 목적은 다음 두 가지입니다.

  • ALIST_SSO 쿠키가 없더라도, 유효한 refreshToken이 있으면 SSO 세션을 복원할 수 있게 한다.
  • frontend direct API 흐름에서 필요한 accessToken 값을 /auth/access, /auth/refresh 응답 body로도 내려준다.

2. 배경 문제

기존 흐름에서는 SSO 관련 엔드포인트가 주로 ALIST_SSO 쿠키를 기준으로 로그인 상태를 판단했습니다.

이 구조에서는 다음 문제가 있었습니다.

  1. 브라우저에 refreshToken은 남아 있지만 ALIST_SSO 쿠키가 사라진 경우

    • /sso/loginChecked
    • /sso/authorize
    • /auth/access 에서 로그인 상태를 복원하지 못했습니다.
  2. frontend가 direct API 흐름으로 변경되면서

    • POST /auth/access
    • POST /auth/refresh 응답 body의 accessToken을 직접 사용하도록 바뀌었는데, backend 응답은 cookie만 세팅하고 body에는 토큰을 충분히 내려주지 않았습니다.

즉, refreshToken 기반 세션 복원frontend 계약(body accessToken) 이 동시에 필요했습니다.


3. 변경 대상 파일

이 브랜치의 핵심 변경 파일은 아래 7개입니다.

  • src/main/java/com/alist/api/modules/auth/AuthController.java
  • src/main/java/com/alist/api/modules/auth/SsoController.java
  • src/main/java/com/alist/api/modules/auth/dto/SsoAuthorizeDto.java
  • src/main/java/com/alist/api/modules/auth/service/AuthService.java
  • src/main/java/com/alist/api/modules/auth/service/SsoService.java
  • src/main/java/com/alist/api/modules/auth/vo/LoginTokenVo.java
  • src/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)

동작 방식은 아래와 같습니다.

  1. 먼저 기존 ALIST_SSO 쿠키 값(ssoSessionId)이 있으면 그대로 사용합니다.
  2. ssoSessionId가 없으면 refreshToken으로 사용자 토큰 정보를 조회합니다.
  3. 유효한 사용자가 확인되면
    • 기존 최신 SSO 세션이 있으면 TTL을 연장해서 재사용하고
    • 없으면 Redis에 새로운 SSO 세션을 다시 생성합니다.
  4. 이후 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에 아래 값을 포함합니다.
    • isAccessToken
    • userIdx
    • userId
    • userRole
    • accessToken

즉, /auth/access는 이제 토큰 쿠키 발급 + frontend용 JSON body accessToken 제공을 같이 수행합니다.


4-3. /auth/refresh 응답 강화

AuthController.refresh() 변경 내용:

  • 기존처럼 accessToken, refreshToken 쿠키는 재발급합니다.
  • 추가로 응답 body에 아래 값을 내려줍니다.
    • refreshed: true
    • accessToken

이 변경으로 frontend는 refresh 성공 후 cookie에만 의존하지 않고, 응답 body의 accessToken으로 즉시 service-local 토큰을 다시 기록할 수 있습니다.


4-4. /sso/loginChecked 개선

SsoController.loginChecked() 변경 내용:

  • refreshToken cookie를 함께 입력으로 받습니다.
  • ssoService.loginChecked(ssoSessionId, refreshToken)을 사용합니다.
  • access/refresh token 존재 여부를 기존처럼 함께 반환합니다.
  • SSO 세션이 복원되면 ALIST_SSO 쿠키를 다시 써줍니다.

즉, /sso/loginChecked는 더 이상 단순 조회가 아니라 필요 시 세션 복원까지 수행하는 확인 엔드포인트가 되었습니다.


4-5. /sso/authorize 개선

SsoController.authorize()SsoService.authorize() 변경 내용:

  • refreshToken cookie를 함께 전달받아 세션 복원에 사용합니다.
  • authorize 성공 시 SsoAuthorizeDtossoSessionId를 실어주고,
  • controller에서 해당 값을 기준으로 ALIST_SSO 쿠키를 재발급합니다.

즉, 사용자가 이미 refreshToken을 가지고 있다면 SSO 쿠키가 비어 있어도 authorize 진입 시 다시 공통 로그인 상태를 회복할 수 있습니다.


4-6. refreshToken 조회용 Auth 계층 보강

AuthService와 DB 조회 쪽에는 아래 보강이 들어갔습니다.

  • findUserTokenByRefreshToken(String refreshToken) 추가
  • LoginTokenVouserIdx, userId 필드 추가
  • LoginMapper.xmlselectUserTokenByUserTokenIdxuser_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에 accessToken
  • POST /auth/refresh 응답 body에 accessToken

따라서 이 브랜치 변경은 단순 backend 내부 개선이 아니라, frontend의 direct login / callback / refresh 흐름을 안정적으로 지원하는 계약 변경이기도 합니다.


7. 운영상 의미

이 변경을 적용하면 다음이 좋아집니다.

  • SSO 쿠키 유실 상황에서 세션 복원력이 높아짐
  • cross-domain authorize 진입 시 로그인 유지가 더 안정적임
  • frontend가 refresh 후 토큰 재반영을 더 단순하게 처리할 수 있음
  • ALIST_SSOrefreshToken을 각각의 역할에 맞게 유지하면서도 사용자 체감 로그인 끊김을 줄일 수 있음

8. 검증 포인트

배포 또는 MR 검토 시 아래를 확인하는 것이 좋습니다.

  1. POST /auth/access

    • ALIST_SSO 없이 refreshToken만 있을 때 200 또는 정상 복원되는지
    • response body에 accessToken이 포함되는지
  2. POST /auth/refresh

    • response body에 accessToken이 포함되는지
  3. GET /sso/loginChecked

    • refreshToken만으로 loggedIn=true가 가능한지
  4. GET /sso/authorize

    • ALIST_SSO가 없더라도 refreshToken 기반으로 redirect가 이어지는지
  5. Redis 상태

    • alist:sso:userIdx:*
    • alist:sso:session:* 키가 복원/갱신되는지

9. 한 줄 요약

fix/sso-refresh-session-restore 브랜치는 refreshToken만 남아 있는 상황에서도 SSO 세션을 복원하고, /auth/access/auth/refresh가 frontend가 바로 사용할 수 있는 accessToken을 응답 body로 반환하도록 보강한 변경입니다.