From 927881f5ef5f1ced967f3b0ed0985ef0e1b2a4be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=AC=B8=ED=98=95=EC=84=9D?= Date: Mon, 22 Jun 2026 14:15:24 +0900 Subject: [PATCH] =?UTF-8?q?Add=20Baron=20SSO=20=EB=A1=9C=EA=B7=B8=EC=9D=B8?= =?UTF-8?q?=20=ED=99=94=EB=A9=B4=203=EA=B0=80=EC=A7=80=20=EB=B0=A9?= =?UTF-8?q?=EC=8B=9D=20=EC=A0=88=EC=B0=A8=20=EB=B0=8F=20=ED=9D=90=EB=A6=84?= =?UTF-8?q?.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...SSO 로그인 화면 3가지 방식 절차 및 흐름.md | 428 ++++++++++++++++++ 1 file changed, 428 insertions(+) create mode 100644 Baron SSO 로그인 화면 3가지 방식 절차 및 흐름.md diff --git a/Baron SSO 로그인 화면 3가지 방식 절차 및 흐름.md b/Baron SSO 로그인 화면 3가지 방식 절차 및 흐름.md new file mode 100644 index 0000000..f32f766 --- /dev/null +++ b/Baron SSO 로그인 화면 3가지 방식 절차 및 흐름.md @@ -0,0 +1,428 @@ +# Baron SSO 로그인 화면 3가지 방식 절차 및 흐름 정리 + +작성일: 2026-06-22 + +## 1. 목적 + +Baron SSO 로그인 페이지에는 사용자가 선택할 수 있는 로그인 탭이 3개 있다. + +- 비밀번호 +- 로그인 링크 +- QR 코드 + +본 문서는 각 탭이 어떤 상황에서 쓰이고, 사용자가 어떤 절차를 거치며, 내부 시스템에서는 어떤 데이터와 인증 상태가 이동하는지 설명한다. + +## 2. 로그인 화면 기준 요약 + +| 탭 | 사용자 입력/행동 | 대표 Backend API | 인증 성격 | 적합한 상황 | +| --- | --- | --- | --- | --- | +| 비밀번호 | 이메일 또는 휴대폰 번호 + 비밀번호 입력 | `POST /api/v1/auth/password/login` | Kratos password 기반 직접 인증 | 가장 기본적인 로그인, 최초 로그인, 비밀번호를 알고 있는 경우 | +| 로그인 링크 | 이메일 또는 휴대폰 번호 입력 후 수신한 링크/코드 승인 | `POST /api/v1/auth/enchanted-link/init` -> `poll`, `POST /api/v1/auth/magic-link/verify`, `POST /api/v1/auth/login/code/verify` | Baron pendingRef 기반 원격 승인 | 비밀번호 입력을 줄이고 싶거나, 다른 기기/채널로 본인 확인하려는 경우 | +| QR 코드 | 로그인 화면에 QR 표시, 이미 로그인된 기기에서 스캔/승인 | `POST /api/v1/auth/qr/init` -> `poll` -> `approve` | 교차 기기 승인 | PC에서 로그인하려는데 모바일 또는 다른 브라우저에 이미 로그인되어 있는 경우 | + +핵심 차이는 다음과 같다. + +- 비밀번호: 현재 로그인 화면에서 사용자가 직접 비밀번호를 증명한다. +- 로그인 링크: 현재 로그인 화면은 대기하고, 이메일/SMS/링크를 받은 쪽에서 승인을 수행한다. +- QR 코드: 현재 로그인 화면은 QR을 띄우고, 이미 로그인된 승인 기기가 해당 QR을 승인한다. + +## 3. 공통 운영 경로 + +운영 환경에서는 사용자의 요청이 Backend, Kratos, Hydra로 직접 들어가지 않는다. 일반적으로 앞단의 L7 또는 Traefik, Baron Gateway Nginx, Oathkeeper를 거쳐 내부 서비스로 라우팅된다. + +```mermaid +flowchart LR + User[사용자 브라우저] + RP[RP/업무시스템] + L7[Traefik 또는 외부 L7] + GW[Baron Gateway Nginx] + UF[UserFront 로그인 화면] + BE[Baron Backend] + OK[Oathkeeper] + KR[Ory Kratos] + HY[Ory Hydra] + Redis[Redis] + + User -->|업무시스템 접속| RP + RP -->|OIDC 인증 요청 /oidc/oauth2/auth| L7 + User -->|Baron SSO 화면/API 요청| L7 + L7 --> GW + GW -->|/| UF + GW -->|/api/v1/*| BE + GW -->|/auth/*| OK + GW -->|/oidc/*| OK + OK --> KR + OK --> HY + BE --> Redis + BE --> KR + BE --> HY +``` + +운영 관점에서는 다음 경로를 구분해서 설명하면 이해하기 쉽다. + +| 구분 | 경로 | 의미 | +| --- | --- | --- | +| 화면 진입 | `사용자 -> L7 -> Nginx -> UserFront` | 로그인 페이지를 보여주는 경로 | +| Baron API | `UserFront -> L7 -> Nginx -> Backend` | 로그인 버튼 클릭, 링크 발송, QR 생성, 폴링 요청 | +| Ory Public | `브라우저 또는 Nginx -> Oathkeeper -> Kratos/Hydra` | Ory public API 또는 OIDC public endpoint | +| 내부 백채널 | `Backend -> Kratos/Hydra/Redis` | 세션 발급, OIDC accept, 대기 상태 저장 | + +## 4. 비밀번호 로그인 + +### 4.1 사용자가 보는 절차 + +1. 사용자가 `비밀번호` 탭을 선택한다. +2. `이메일 또는 휴대폰 번호`를 입력한다. +3. `비밀번호`를 입력한다. +4. 로그인 버튼을 누른다. +5. 인증 성공 시 Baron SSO 세션이 만들어지고, OIDC 로그인 중이면 원래 RP 시스템으로 돌아간다. +6. 실패 시 비밀번호 오류, 미등록 사용자, 비활성 사용자 등의 메시지가 표시된다. + +### 4.2 주요 상황 + +| 상황 | 처리 | +| --- | --- | +| 사용자가 이메일 입력 | 입력값을 그대로 loginId로 사용 | +| 사용자가 휴대폰 번호 입력 | `010-1234-5678` 같은 값을 정리하여 `+821012345678` 형태로 정규화 | +| 일반 UserFront 로그인 | `sessionJwt`를 받아 UserFront 세션으로 사용 | +| RP OIDC 로그인 중 | `login_challenge`를 함께 보내고, 성공 후 Hydra `AcceptLoginRequest`를 거쳐 `redirectTo`로 이동 | + +### 4.3 데이터 예시 + +요청 예시: + +```json +{ + "loginId": "user@example.com", + "password": "********", + "login_challenge": "optional-hydra-login-challenge" +} +``` + +응답 예시: + +```json +{ + "status": "ok", + "provider": "kratos", + "sessionJwt": "eyJ...", + "token": "eyJ...", + "redirectTo": "https://sso.example.com/oidc/oauth2/auth?..." +} +``` + +`redirectTo`는 OIDC 로그인 흐름일 때 중요하다. RP 시스템에서 Baron SSO로 보낸 로그인 요청을 Hydra가 이어받고, Backend가 로그인 성공을 Hydra에 알려주면, Hydra가 최종 이동할 URL을 돌려준다. + +### 4.4 흐름도 + +```mermaid +sequenceDiagram + autonumber + actor User as 사용자 + participant RP as RP/업무시스템 + participant L7 as L7/Traefik + participant GW as Baron Gateway Nginx + participant UF as UserFront + participant BE as Baron Backend + participant KR as Ory Kratos + participant HY as Ory Hydra + + User->>RP: 업무시스템 접속 + RP->>L7: /oidc/oauth2/auth?client_id=... + L7->>GW: OIDC 요청 전달 + GW->>HY: /oidc/* -> Hydra + HY-->>UF: login_challenge 포함 로그인 화면 이동 + User->>UF: 이메일/휴대폰 + 비밀번호 입력 + UF->>L7: POST /api/v1/auth/password/login + L7->>GW: API 요청 전달 + GW->>BE: /api/v1/auth/password/login + BE->>KR: Kratos password 인증 + KR-->>BE: session_token, cookie + alt login_challenge 있음 + BE->>HY: AcceptLoginRequest(login_challenge, subject) + HY-->>BE: redirectTo + BE-->>UF: sessionJwt + redirectTo + UF->>RP: OIDC callback 이동 + else 일반 로그인 + BE-->>UF: sessionJwt + end +``` + +## 5. 로그인 링크 + +### 5.1 사용자가 보는 절차 + +1. 사용자가 `로그인 링크` 탭을 선택한다. +2. 이메일 또는 휴대폰 번호를 입력한다. +3. `로그인 링크 전송`을 누른다. +4. 현재 브라우저는 로그인 대기 상태가 된다. +5. 사용자는 이메일/SMS로 받은 링크를 클릭하거나, 전달받은 코드를 입력한다. +6. 승인 또는 코드 검증이 성공하면 원래 대기 중이던 브라우저가 로그인 완료된다. + +### 5.2 주요 상황 + +| 상황 | 처리 | +| --- | --- | +| 이메일 입력 | 이메일로 로그인 링크 또는 코드 전달 | +| 휴대폰 번호 입력 | SMS로 로그인 링크 또는 코드 전달 | +| 요청 브라우저 | `pendingRef`를 들고 `poll`을 반복 호출 | +| 승인 브라우저/기기 | 링크 클릭 또는 코드 검증으로 `pendingRef` 승인 | +| verifyOnly 승인 | 승인 기기에는 세션을 만들지 않고, 원래 요청 브라우저만 로그인 완료 | + +로그인 링크 방식의 핵심은 `pendingRef`이다. `pendingRef`는 "로그인을 기다리는 요청"을 식별하는 임시 키다. 현재 브라우저는 이 키로 계속 상태를 확인하고, 링크를 클릭한 쪽이 해당 키를 승인하면 현재 브라우저가 세션을 받는다. + +### 5.3 데이터 예시 + +초기 요청: + +```json +{ + "loginId": "user@example.com", + "uri": "https://sso.example.com", + "codeOnly": false +} +``` + +초기 응답: + +```json +{ + "linkId": "Sent", + "pendingRef": "AbC123", + "mode": "code", + "provider": "kratos", + "expiresIn": 300, + "interval": 2, + "resendAfter": 30 +} +``` + +Redis 대기 상태 예시: + +```json +{ + "key": "enchanted_session:AbC123", + "value": { + "status": "pending", + "loginId": "user@example.com" + }, + "ttl": "5m" +} +``` + +폴링 중 대기 응답: + +```json +{ + "error": "authorization_pending", + "code": "authorization_pending", + "interval": 2 +} +``` + +승인 후 성공 응답: + +```json +{ + "status": "ok", + "sessionJwt": "eyJ..." +} +``` + +### 5.4 흐름도 + +```mermaid +sequenceDiagram + autonumber + actor User as 사용자 + participant UF as 요청 브라우저(UserFront) + participant L7 as L7/Traefik + participant GW as Baron Gateway Nginx + participant BE as Baron Backend + participant Redis as Redis + participant KR as Ory Kratos/Courier + participant Channel as Email/SMS + participant Approver as 링크 승인 기기 + + User->>UF: 로그인 링크 탭에서 이메일/휴대폰 입력 + UF->>L7: POST /api/v1/auth/enchanted-link/init + L7->>GW: API 요청 전달 + GW->>BE: init 요청 + BE->>BE: 사용자 존재 여부 확인, 전화번호 정규화 + BE->>KR: 링크/코드 로그인 시작 + BE->>Redis: pendingRef 상태 저장(status=pending) + KR-->>Channel: 로그인 링크 또는 코드 발송 + BE-->>UF: pendingRef, expiresIn, interval + + loop 요청 브라우저 대기 + UF->>BE: POST /api/v1/auth/enchanted-link/poll(pendingRef) + BE->>Redis: pendingRef 상태 조회 + BE-->>UF: authorization_pending 또는 slow_down + end + + User->>Approver: 수신한 링크 클릭 또는 코드 입력 + Approver->>BE: POST /api/v1/auth/magic-link/verify 또는 /login/code/verify + BE->>Redis: pendingRef 승인 처리(status=approved/success) + UF->>BE: poll 재시도 + BE-->>UF: sessionJwt +``` + +### 5.5 보안상 설명 포인트 + +로그인 링크는 비밀번호를 입력하지 않아 편리하지만, 링크를 받은 사람이 곧 승인자가 된다. 따라서 운영 설명 시 다음 통제가 필요하다. + +- 링크 만료 시간은 짧게 유지한다. +- 재전송 제한과 폴링 속도 제한을 둔다. +- 승인 화면에는 요청 기기, IP, 브라우저, 요청 시각을 표시한다. +- "내가 요청한 로그인이 아님" 버튼을 제공한다. +- 요청자와 승인자를 감사 로그에 분리 기록한다. + +## 6. QR 코드 로그인 + +### 6.1 사용자가 보는 절차 + +1. 사용자가 `QR 코드` 탭을 선택한다. +2. 로그인 화면에 QR 코드가 표시된다. +3. 사용자는 이미 로그인되어 있는 기기에서 QR을 스캔한다. +4. 승인 기기에서 로그인 요청 정보를 확인하고 승인한다. +5. 원래 QR을 띄운 브라우저가 로그인 완료된다. + +### 6.2 주요 상황 + +| 상황 | 처리 | +| --- | --- | +| PC에서 새 로그인 필요 | PC 화면에 QR 표시 | +| 사용자가 모바일/다른 브라우저에 이미 로그인되어 있음 | 해당 기기로 QR 스캔 후 승인 | +| 승인 기기에 세션 없음 | 승인 불가, 먼저 승인 기기에서 로그인 필요 | +| QR 만료 | `expired_token` 처리 후 새 QR 발급 필요 | +| 폴링 과다 | `slow_down`으로 폴링 간격 증가 | + +QR 방식은 "이미 로그인된 기기"를 신뢰 근거로 쓴다. 즉 QR을 스캔하는 기기가 Baron SSO 세션을 가지고 있어야 하며, 그 세션의 사용자가 QR을 띄운 브라우저에 대한 로그인을 승인하는 구조다. + +### 6.3 데이터 예시 + +QR 초기화 응답: + +```json +{ + "qrCode": "https://sso.example.com/ql/QR_REF_64_CHARS", + "pendingRef": "PENDING_REF", + "expiresIn": 300, + "interval": 2 +} +``` + +Redis 저장 예시: + +```json +[ + { + "key": "enchanted_session:PENDING_REF", + "value": { + "status": "pending" + }, + "ttl": "5m" + }, + { + "key": "qr_ref:QR_REF_64_CHARS", + "value": "PENDING_REF", + "ttl": "5m" + } +] +``` + +승인 요청 예시: + +```json +{ + "pendingRef": "PENDING_REF" +} +``` + +승인 요청은 쿠키 세션 또는 토큰 세션을 통해 승인 사용자를 확인한다. 승인 후에는 QR을 띄운 브라우저 쪽 `pendingRef`가 성공 상태로 바뀐다. + +### 6.4 흐름도 + +```mermaid +sequenceDiagram + autonumber + actor User as 사용자 + participant PC as 요청 PC(UserFront) + participant L7 as L7/Traefik + participant GW as Baron Gateway Nginx + participant BE as Baron Backend + participant Redis as Redis + participant Mobile as 이미 로그인된 승인 기기 + participant KR as Ory Kratos + + User->>PC: QR 코드 탭 선택 + PC->>L7: POST /api/v1/auth/qr/init + L7->>GW: API 요청 전달 + GW->>BE: QR init + BE->>Redis: pendingRef/status=pending 저장 + BE->>Redis: qrRef -> pendingRef 매핑 저장 + BE-->>PC: qrCode URL, pendingRef, expiresIn + PC->>PC: QR 코드 표시 + + loop 요청 PC 대기 + PC->>BE: POST /api/v1/auth/qr/poll(pendingRef) + BE->>Redis: pendingRef 상태 조회 + BE-->>PC: authorization_pending 또는 slow_down + end + + User->>Mobile: QR 스캔 + Mobile->>BE: POST /api/v1/auth/qr/approve(pendingRef 또는 qrRef) + BE->>KR: 승인 기기 세션 확인(whoami/session) + BE->>KR: QR 대상 사용자의 코드 로그인/세션 발급 처리 + BE->>Redis: pendingRef/status=success, jwt 저장 + BE-->>Mobile: QR Login Approved + PC->>BE: poll 재시도 + BE-->>PC: sessionJwt +``` + +### 6.5 QR 방식의 핵심 통제 + +QR 로그인은 편리하지만, 공격자가 자기 PC에 QR을 띄우고 사용자에게 스캔을 유도할 수 있다. 따라서 승인 화면에는 반드시 다음 정보가 필요하다. + +| 승인 화면 표시 정보 | 이유 | +| --- | --- | +| 요청 기기 종류 | 내 PC인지 확인 | +| 요청 브라우저 | 평소 사용하는 브라우저인지 확인 | +| 요청 IP/대략 위치 | 낯선 위치 요청인지 확인 | +| 요청 시각 | 방금 내가 요청한 것인지 확인 | +| RP 시스템 이름 | 어떤 업무시스템 로그인을 승인하는지 확인 | + +또한 승인 버튼과 별도로 `내가 요청한 로그인이 아님` 버튼을 제공해야 한다. 이 버튼은 해당 `pendingRef`를 차단하고, 필요 시 세션/refresh grant revoke로 이어져야 한다. + +## 7. 세 방식 비교 + +| 비교 항목 | 비밀번호 | 로그인 링크 | QR 코드 | +| --- | --- | --- | --- | +| 현재 화면에서 인증 완료 가능 | 가능 | 불가능, 외부 링크/코드 필요 | 불가능, 승인 기기 필요 | +| 비밀번호 필요 | 필요 | 불필요 | 불필요 | +| 기존 로그인 기기 필요 | 불필요 | 필수는 아님 | 사실상 필요 | +| 이메일/SMS 채널 필요 | 불필요 | 필요 | 불필요 | +| 교차 기기 승인 | 아님 | 가능 | 핵심 기능 | +| 주요 임시 키 | 없음 | `pendingRef`, magic token, login code | `pendingRef`, `qrRef` | +| 주요 위험 | 비밀번호 탈취, 무차별 대입 | 링크 탈취, 오발송, 피싱 승인 | QR 피싱, 잘못된 승인 | +| 운영 통제 | 비밀번호 정책, 실패 횟수 제한 | TTL, 재전송 제한, 승인 정보 표시 | TTL, 승인 정보 표시, 기존 세션 검증 | + +## 8. 팀 설명용 쉬운 표현 + +비밀번호 로그인은 "본인이 지금 이 화면에서 비밀번호를 직접 증명하는 방식"이다. + +로그인 링크는 "지금 화면은 대기표를 뽑고, 이메일이나 문자로 받은 링크를 눌러 그 대기표를 승인하는 방식"이다. + +QR 코드는 "새 PC 화면에 임시 출입증을 띄우고, 이미 로그인된 내 기기로 그 출입증을 스캔해서 승인하는 방식"이다. + +세 방식 모두 최종 목적은 같다. Baron Backend가 사용자를 확인하고, Kratos 세션을 얻은 뒤, RP 로그인이면 Hydra OIDC 흐름을 완료하여 사용자를 원래 업무시스템으로 돌려보낸다. 다만 "사용자 본인임을 확인하는 수단"이 각각 다르다. + +## 9. 운영/보안 권고 + +1. 비밀번호 방식은 기본 로그인 수단으로 유지하되, 실패 횟수 제한과 감사 로그를 반드시 유지한다. +2. 로그인 링크 방식은 만료 시간, 재전송 제한, 링크 재사용 방지를 강하게 적용한다. +3. QR 방식은 승인 화면에 요청 정보를 충분히 보여주고, 사용자가 명확히 승인하도록 한다. +4. 링크/QR 방식 모두 `요청자 기기`와 `승인자 기기`를 감사 로그에 분리 저장한다. +5. `내가 요청한 로그인이 아님`을 누르면 해당 pending 요청을 즉시 차단하고, 이미 발급된 세션 또는 refresh grant가 있으면 단계적으로 revoke한다. +6. 내부 사용자는 Naver Works 같은 조직 채널 알림과 연동할 수 있지만, 외부 사용자는 이메일/패스키/TOTP 등 별도 신뢰 채널을 마련해야 한다. +