type, status, related_pages, last_updated, source
| type |
status |
related_pages |
last_updated |
source |
| concept |
stable |
|
2026-07-17 |
docs/raw/verification/2026-07-17_verify_auth_reverify.md |
인증 / RBAC
세션 인증 (backend.md 6.3)
- 방식: Secure HttpOnly 세션 쿠키 (
session_id, JWT 아님), SameSite=Lax
- 저장소:
sessions 테이블 → db_schema/users_auth
- 유효시간: 활동 기준 4시간 또는 절대 12시간 중 먼저 도달하는 쪽
- DB 풀:
autocommit=True (세션 즉시 조회 가능하도록)
- 프론트: 모든 API 요청에
credentials: "include" (frontend.md 5.1)
OTP / 비밀번호 및 디바이스 신뢰
- OTP 6자리, 5분 유효, 해시 저장(bcrypt/PBKDF2), 재시도 최대 3회(2s/4s/8s 백오프)
- 비밀번호 최소 8자, bcrypt(라운드≥12) 또는 PBKDF2, 평문 저장 절대 금지
- 5회 연속 실패 시 계정 임시 잠금 및 ADMIN_EMAIL로 보안 경고 메일 발송
- 디바이스 신뢰 (2026-07-17 도입):
- 기기 신뢰를 기존 User-Agent 해시에서 **HttpOnly 디바이스 토큰 쿠키 (
device_token)**로 전환하여 브라우저 업데이트 시 반복적인 OTP 요구를 해결.
- 로그인 또는 가입 인증 성공 시 무작위 32바이트 토큰을 발급하여 브라우저 쿠키에 저장(만료 90일)하고, SHA256 해시값은 DB
trusted_devices 테이블에 저장.
- 기기 신뢰 만료 정책:
last_used_at이 EMAIL_REVERIFY_DAYS(90일) 이내인 기기 토큰만 유효 처리하며, 로그인 시 last_used_at을 자동으로 갱신.
사용자 상태 생명주기
| 상태 |
접근 가능 범위 |
| NO_COMPANY |
로그인 가능, B01만 (B02~B11 차단) |
| PENDING |
로그인 가능, B01만 (승인 대기) |
| ACTIVE |
전체 (B01 + B02~B11) |
역할 (users.role)
| 역할 |
전체회사조회 |
역할변경 |
팀원관리 |
가입승인 |
프로젝트조회 범위 |
| SYSTEM_ADMIN |
✅ |
✅ |
✅ |
✅ |
전체 |
| ADMIN |
✗ |
✗ |
✅(자기회사) |
✅(자기회사) |
회사별 |
| USER |
✗ |
✗ |
✗ |
✗ |
회사별 |
is_master 플래그: TRUE=회사 생성자/ADMIN(팀원 승인권), FALSE=일반 팀원
권한 검증 헬퍼 (B01_Dashboard)
| 항목 |
위치 |
역할 |
_can_edit_project() |
B01_Dashboard_Router.py:79 |
역할·회사 기준 프로젝트 수정 권한 |
_can_manage_automation() |
B01_Dashboard_Router.py:87 |
USER 차단과 프로젝트 범위 검사 |
_can_edit_user() |
B01_Dashboard_Router.py:93 |
사용자 수정 범위 검사 |
count_company_admins() |
B01_Dashboard_Repository.py:584 |
마지막 ADMIN 삭제·강등 방지 |
canEditProject() 외 5개 |
B01_Dashboard_UI_Helper.ts:3 |
프론트 표시 제어; 백엔드 권한을 대체하지 않음 |
원칙: 백엔드가 모든 수정/삭제/역할변경 API에서 반드시 재검증 (프론트 UI는 표시 제어만, 신뢰 금지). 위반 시 403 {"status":"error","message":"Access denied"}.
인증 갱신 및 만료 일원화
- 기존의 중복된
auth_expires_at 컬럼 및 로직을 제거하고, 만료 개념을 EMAIL_REVERIFY_DAYS(90일)로 일원화하였습니다.
- 로그인/가입 인증 이후 90일이 지나면 OTP 재인증을 요구하며, 대시보드 표시 시에도
last_email_verified_at + 90일을 계산하여 적용합니다.
라우팅 가드 (frontend.md 5.2)
B02~B11 진입 시 fetchDashboardMe() → company_id+status 확인 → NO_COMPANY/PENDING이면 B01로 강제 리다이렉트.
사용처 (역참조)