# Auth and Token Lifecycle - Related REQ: `REQ-004` ## 목표 정적 토큰과 DB 발급 토큰을 병행하는 현재 인증 모델의 동작 기준을 명확히 한다. ## 권한 모델 | Permission | 허용 범위 | | --- | --- | | `read` | 조회 계열 API | | `trade-write` | 조회 + 포트폴리오 변경 API | | `admin` | 전체 API + 사용자/봇 관리 | 소유권 결합 정책: - `admin`이 아닌 주체는 포트폴리오 접근 시 리소스 소유주(`owner_user_id`) 일치 조건을 추가로 만족해야 한다. - `admin`은 소유권 제약 없이 전체 포트폴리오를 접근할 수 있다. ## 인증 방식 - 보호된 API는 `Authorization: Bearer ` 헤더를 사용한다. - 인증 소스는 정적 토큰과 DB 저장 토큰을 병행한다. 권한 계층: - `admin`은 전체 엔드포인트 접근 가능 - `trade-write`는 `trade-write`와 `read` 범위 접근 가능 - `read`는 조회 엔드포인트만 접근 가능 ## 인증 소스 - 환경변수 기반 정적 토큰: `PORTFOLIOHUB_*_TOKENS` - DB 저장 토큰: 로그인 세션/클라이언트 토큰/봇 토큰 봇 토큰 사용자 컨텍스트 정책: - 봇 principal은 `owner_user_id`를 가진다. - 봇 토큰 인증 시 실효 사용자 식별자는 `bot_principals.owner_user_id`로 해석한다. - 따라서 소유권이 필요한 포트폴리오 API에서 봇 토큰은 소유 사용자 경계 내에서만 동작한다. ## 봇 관리 API 정책 - Admin 경로: - `POST /auth/bots` - `GET /auth/bots` - `GET /auth/bots/{bot_id}` - `DELETE /auth/bots/{bot_id}` - `POST/GET/DELETE /auth/bots/{bot_id}/tokens*` - Self-service 경로(사용자 본인 전용): - `POST /auth/me/bots` - `GET /auth/me/bots` - `POST/GET/DELETE /auth/me/bots/{bot_id}/tokens*` 제약: - self-service 경로는 DB 사용자 컨텍스트가 있는 사용자 토큰에서만 허용한다. - self-service 경로는 요청자의 소유 봇(`owner_user_id == auth_context.user_id`)에만 허용한다. - 봇 권한은 `read` 또는 `trade-write`만 허용한다. ## 토큰 라이프사이클 1. 사용자 로그인(`POST /auth/login`) 또는 토큰 발급 API 호출 2. 토큰 해시 저장 및 prefix 관리 3. 요청 처리 시 해시 비교와 만료/폐기 상태 검증 4. `DELETE /auth/tokens/{token_id}` 또는 봇 비활성화로 토큰 폐기 CLI 봇 토큰 라이프사이클: 1. `bot token issue ` 실행 시 `--ttl-days`/`--no-expiry` 정책을 먼저 검증한다. 2. 정책 검증 후 서비스 계층에서 권한과 만기 정책을 재검증한다. 3. 발급 성공 시 응답은 마스킹된 토큰만 재출력 가능하며, 원문 토큰은 1회 출력 경로로 제한한다. 4. `bot token revoke ` 실행 시 확인 프롬프트(`--force`로 생략 가능)를 거쳐 폐기한다. 만기 정책: - 기본 TTL은 365일이다. - `--ttl-days`와 `--no-expiry` 동시 사용은 거부한다. - 비관리자 컨텍스트에서는 `--no-expiry`를 거부한다. 감사 로그 정책: - `issue/revoke`는 `auth.bot_token` 이벤트를 감사 로그로 남긴다. - 감사 로그에는 마스킹된 `token_id/token_ref`만 기록한다. - issue 경로에서 감사 로그 기록이 실패하면 발급 토큰을 즉시 폐기하고 실패 처리한다. - revoke 경로에서 감사 로그 기록이 실패해도 폐기는 유지하고 명령은 실패로 반환한다. ## 실패 응답 기준 - bearer 헤더 누락 또는 형식 오류: `401` - 알 수 없는 토큰: `401` - 권한 부족: `403` ## 부트스트랩 사용자 규칙 - `PORTFOLIOHUB_BOOTSTRAP_USERNAME`과 `PORTFOLIOHUB_BOOTSTRAP_PASSWORD`가 설정되고 users 테이블이 비어 있으면 초기 admin을 1회 생성한다. - 이미 사용자가 존재하면 추가 생성하지 않는다. ## Validation Notes - 만료된 토큰은 항상 인증 실패로 처리해야 한다. - 비활성 봇(`is_active=false`)의 토큰은 거부되어야 한다. - 권한 계층 승격 우회가 없는지 API/CLI 양쪽에서 검증한다. ## Open Implementation Points - 정적 토큰과 DB 토큰의 우선순위/병합 정책을 명문화할지 결정한다. - 감사 로그(audit trail)에 토큰 발급/폐기 이벤트를 표준 포맷으로 남길지 확정한다.