215 lines
6.8 KiB
Markdown
215 lines
6.8 KiB
Markdown
# 세션 연장 Confirm 적용 가이드
|
|
|
|
## 1) 목적과 원칙
|
|
|
|
JWT 만료 **5분 전**에 `"로그인을 연장하시겠습니까?"` confirm을 띄우고, 선택에 따라 세션을 연장하는 UX를 서비스 앱에 적용하기 위한 가이드입니다.
|
|
|
|
이 문서는 [서비스별 인증 처리 리팩토링 가이드](./auth-service-refactoring-guide.md)의 **후속 단계**입니다.
|
|
|
|
핵심 원칙:
|
|
|
|
- confirm UX는 `@common/components` **Header**의 `useSessionExtendConfirm`이 담당한다.
|
|
- confirm **확인** → `authService.silentRefresh()`
|
|
- confirm **취소** → `authService.declineSessionExtend()`
|
|
- 앱은 `ConfirmProvider` 계층과 `authService` 주입을 맞춘다.
|
|
|
|
**적용 완료**: `cs`, `as`, `st`
|
|
|
|
---
|
|
|
|
## 2) 선행 조건
|
|
|
|
[리팩토링 가이드 체크리스트](./auth-service-refactoring-guide.md#5-적용-체크리스트)를 통과한 서비스만 진행한다.
|
|
|
|
| 항목 | 리팩토링 가이드 |
|
|
| --- | --- |
|
|
| `authService` (`silentRefresh`, `declineSessionExtend`) | [4-4](./auth-service-refactoring-guide.md#44-인증-서비스) |
|
|
| `BaseLayout`에 `authService` 주입 | [4-7](./auth-service-refactoring-guide.md#47-레이아웃provider-연결) |
|
|
|
|
---
|
|
|
|
## 3) 목표 아키텍처
|
|
|
|
### 3-1. 레이어 책임
|
|
|
|
| 레이어 | 위치 | 역할 |
|
|
| --- | --- | --- |
|
|
| JWT 시간 계산 | `@common/auth` `jwt-utils.ts` | `getRemainingMs`, confirm 버퍼 상수 |
|
|
| 토큰·정리 | `@common/auth` `token-manager.ts` | `setToken`, `clearRefreshTimer`, `clearAuthToken` |
|
|
| API 오케스트레이션 | `entities/auth/api/auth-service.ts` | `silentRefresh`, `declineSessionExtend` |
|
|
| confirm UX | `@common/components` Header | 카운트다운 + 5분 전 confirm |
|
|
| 앱 진입점 | `entities/auth/lib/auth-wrapper.tsx` | auth 체크, `auth:logout` |
|
|
| 레이아웃 | layout / BaseLayout wrapper | `authService` → Header |
|
|
| UI 쉘 | `app/providers/app-provider.tsx` | `ConfirmProvider`, `ConfirmDialog` |
|
|
|
|
### 3-2. 런타임 흐름
|
|
|
|
```mermaid
|
|
sequenceDiagram
|
|
participant Login as authService.login
|
|
participant Header as Header
|
|
participant User as 사용자
|
|
participant API as authService.silentRefresh
|
|
|
|
Login->>Login: setToken
|
|
Header->>Header: confirm 예약(exp - 5분)
|
|
Note over Header: 만료 5분 전
|
|
Header->>User: 로그인을 연장하시겠습니까?
|
|
alt 확인
|
|
User->>API: silentRefresh()
|
|
API->>API: setToken
|
|
Header->>Header: confirm 타이머 재설정
|
|
else 취소
|
|
Header->>Header: declineSessionExtend()
|
|
end
|
|
```
|
|
|
|
| 시점 | 동작 | 담당 |
|
|
| --- | --- | --- |
|
|
| 로그인 / silentRefresh 성공 | 토큰 저장 | `authService` |
|
|
| 만료 5분 전 | confirm 표시 | Header → `useSessionExtendConfirm` |
|
|
| confirm **확인** | `silentRefresh` + confirm 타이머 재설정 | Header → `authService.silentRefresh` |
|
|
| confirm **취소** | `declineSessionExtend` | Header → `authService.declineSessionExtend` |
|
|
| 토큰 완전 만료 | logout | Header |
|
|
|
|
---
|
|
|
|
## 4) 공통 계약
|
|
|
|
### 4-1. 시간 버퍼 (`getRemainingMs`)
|
|
|
|
파일: `packages/common/auth/jwt-utils.ts`
|
|
|
|
```ts
|
|
export const SESSION_EXTEND_CONFIRM_BUFFER_MS = 5 * 60_000; // confirm: 만료 5분 전
|
|
|
|
getRemainingMs(token, SESSION_EXTEND_CONFIRM_BUFFER_MS); // → confirm 타이머 delay
|
|
getRemainingMs(token, 0) > 0; // → 토큰 미만료 여부
|
|
```
|
|
|
|
### 4-2. Header ↔ AuthService
|
|
|
|
공통 Header가 아래처럼 연결한다.
|
|
|
|
```ts
|
|
useSessionExtendConfirm({
|
|
enabled:
|
|
mounted &&
|
|
isLoggedIn &&
|
|
!viewOnly &&
|
|
!!authService &&
|
|
!isAtLoginRedirectUrl(getAuthLoginRedirectUrl()),
|
|
getAccessToken: () => getCookie(appConfig.CLAIM_NAME ?? ""),
|
|
silentRefresh: authService?.silentRefresh ?? (async () => {}),
|
|
declineSessionExtend: authService?.declineSessionExtend ?? (() => {}),
|
|
});
|
|
```
|
|
|
|
### 4-3. Provider 계층
|
|
|
|
```
|
|
ConfirmProvider
|
|
└─ AuthWrapper
|
|
└─ … → BaseLayout → Header
|
|
└─ ConfirmDialog
|
|
```
|
|
|
|
---
|
|
|
|
## 5) 적용 순서
|
|
|
|
### 5-1. AppProvider — ConfirmProvider 마운트
|
|
|
|
파일: `app/providers/app-provider.tsx`
|
|
|
|
```tsx
|
|
<ConfirmProvider>
|
|
<AuthWrapper>
|
|
{children}
|
|
<ConfirmDialog />
|
|
</AuthWrapper>
|
|
</ConfirmProvider>
|
|
```
|
|
|
|
참고: `apps/cs/src/app/providers/app-provider.tsx`
|
|
|
|
### 5-2. BaseLayout — authService 전달
|
|
|
|
```tsx
|
|
import { authService } from "@/entities/auth";
|
|
|
|
<BaseLayout authService={authService} /* ... */>
|
|
{children}
|
|
</BaseLayout>
|
|
```
|
|
|
|
### 5-3. authService — declineSessionExtend
|
|
|
|
리팩토링 [4-4](./auth-service-refactoring-guide.md#44-인증-서비스)에서 이미 구현했다면 확인만 한다.
|
|
|
|
```ts
|
|
export const authService: AuthService = {
|
|
login,
|
|
silentRefresh,
|
|
declineSessionExtend: clearRefreshTimer,
|
|
logout,
|
|
};
|
|
```
|
|
|
|
---
|
|
|
|
## 6) 엣지 케이스
|
|
|
|
| 상황 | 동작 |
|
|
| --- | --- |
|
|
| 토큰 유효 시간 < 5분 | 진입 즉시 confirm |
|
|
| confirm **취소** | `declineSessionExtend()` + 동일 JWT에 재표시 안 함 |
|
|
| confirm **확인** | `silentRefresh()` → 새 토큰 기준 confirm 타이머 재설정 |
|
|
| `silentRefresh` 실패 | `auth:logout` → AuthWrapper 리다이렉트 |
|
|
| 로그아웃 | `clearAuthToken`, 훅 cleanup |
|
|
| 페이지 새로고침 | Header가 confirm 타이머 재예약 |
|
|
|
|
---
|
|
|
|
## 7) 적용 체크리스트
|
|
|
|
- [ ] `ConfirmProvider` > `AuthWrapper` > `BaseLayout` > `Header` 계층
|
|
- [ ] `ConfirmDialog`가 `ConfirmProvider` 하위에 마운트됨
|
|
- [ ] `BaseLayout`에 `authService` 전달
|
|
- [ ] `authService.declineSessionExtend` 구현
|
|
- [ ] 만료 5분 전 confirm 노출
|
|
- [ ] 확인 클릭 시 `SILENT_REFRESH` 호출
|
|
- [ ] 취소 후 세션이 연장되지 않음
|
|
|
|
---
|
|
|
|
## 8) 검증 방법
|
|
|
|
1. 로그인 후 JWT `exp`가 5분 이내가 되도록 대기하거나 테스트 토큰 사용
|
|
2. confirm 문구 `"로그인을 연장하시겠습니까?"` 표시 확인
|
|
3. **확인** → Network에서 `SILENT_REFRESH` PUT, 쿠키 갱신, confirm 재예약
|
|
4. **취소** → 만료 시 로그아웃/리다이렉트
|
|
5. 새로고침 후 confirm 타이머 복구
|
|
|
|
---
|
|
|
|
## 9) 참고 구현
|
|
|
|
| 앱 | auth-service | BaseLayout / layout | AppProvider |
|
|
| --- | --- | --- | --- |
|
|
| as (기준) | `apps/as/src/entities/auth/api/auth-service.ts` | `apps/as/src/app/layouts/base-layout.tsx` | (동등 Provider) |
|
|
| cs | `apps/cs/src/entities/auth/api/auth-service.ts` | `apps/cs/app/(main)/(with-base-layout)/layout.tsx` | `apps/cs/src/app/providers/app-provider.tsx` |
|
|
| st | `apps/st/src/entities/auth/api/auth-service.ts` | `apps/st/app/(main)/(with-base-layout)/layout.tsx` | (동등 Provider) |
|
|
|
|
공통:
|
|
|
|
- `packages/common/components/src/ui/header/index.tsx`
|
|
- `packages/common/components/src/lib/use-session-extend-confirm.ts`
|
|
|
|
---
|
|
|
|
## 10) 관련 문서
|
|
|
|
- [서비스별 인증 처리 리팩토링 가이드](./auth-service-refactoring-guide.md)
|
|
- `packages/common/auth/README.md`
|