Add Baron SSO 로그인 화면 3가지 방식 절차 및 흐름.md
This commit is contained in:
428
Baron SSO 로그인 화면 3가지 방식 절차 및 흐름.md
Normal file
428
Baron SSO 로그인 화면 3가지 방식 절차 및 흐름.md
Normal file
@@ -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 등 별도 신뢰 채널을 마련해야 한다.
|
||||
|
||||
Reference in New Issue
Block a user