BARON-SSO 로그인 API 요청경로 수정
All checks were successful
ITAM Code Check / build-and-config-check (push) Successful in 12s
ITAM Docker Build Check / docker-build-check (push) Successful in 23s

This commit is contained in:
2026-07-01 17:47:20 +09:00
parent 2512082402
commit fd0bd126d1
4 changed files with 550 additions and 30 deletions

View File

@@ -0,0 +1,127 @@
# Headless Login Demo (OIDC Integration)
이 프로젝트는 **baron-sso (OIDC IdP)**와 연동하여 백채널(Back-channel)을 통한 **Headless 인증**을 구현한 데모 애플리케이션입니다.
## 주요 특징
- **Headless 인증**: IdP가 제공하는 UI를 거치지 않고, RP(데모 앱)가 사용자 자격 증명을 직접 받아 백채널로 인증을 수행합니다.
- **동적 UI 전환**: 입력값(숫자 vs 문자)을 실시간으로 분석하여 '전화번호 SSO 인증' 또는 '사번 로그인' 모드로 자동 전환됩니다.
- **Trusted RP 구현**:
- **OIDC Discovery**: `sso-test.hmac.kr`의 메타데이터를 동적으로 로드합니다.
- **JWKS Endpoint**: 서버 시작 시 생성된 RSA 공개키를 `/.well-known/jwks.json`을 통해 서빙하여 IdP와의 신뢰 관계를 형성합니다.
- **세션 유지**: 인증 완료 후 `express-session`을 통해 로그인 상태를 유지하고 사용자 정보를 관리합니다.
- **PM-fork 스타일 디자인**: 기존 프로젝트의 디자인 토큰(그라데이션, 라운드 처리 등)을 Vanilla CSS로 재현했습니다.
## 기술 스택
- **Backend**: Node.js, Express, express-session
- **OIDC**: openid-client (v5.x), jose
- **Frontend**: Vanilla JS, Modern CSS (Flexbox, CSS Variables)
## 시작하기
### 1. 환경 설정
프로젝트 루트에 `.env` 파일을 생성하고 아래와 같이 설정합니다.
```env
PORT=3000
CLIENT_ID=15cfb85c-f75f-4b51-a13d-d04f87d39739
ISSUER=https://sso-test.hmac.kr/oidc
REDIRECT_URI=http://localhost:3000/callback
JWKS_URI=http://localhost:3000/.well-known/jwks.json
# 필요 시 전화번호용 headless link endpoint를 별도로 덮어쓸 수 있음
PHONE_HEADLESS_LINK_INIT_ENDPOINT=
PHONE_HEADLESS_LINK_POLL_ENDPOINT=
BARON_API_BASE_URL=
BARON_BACKCHANNEL_JWKS_URL=
```
### 2. 의존성 설치
```bash
npm install
```
### 3. 서버 실행
```bash
npm start
```
## 프로젝트 구조
```text
├── server.js # Express 서버 및 OIDC 로직 (Discovery, JWKS, API)
├── public/ # 프론트엔드 정적 파일
│ ├── index.html # 로그인 화면
│ ├── home.html # 인증 후 메인 화면
│ ├── app.js # 입력값 분석 및 API 통신 로직
│ └── styles.css # PM-fork 스타일 시트
├── keys.json # (자동생성) 서비스용 RSA 키 쌍
└── .env # 환경 변수 설정
```
## 핵심 구현 로직
### 1. 입력값 분류 (Classify Input)
사용자가 입력한 값이 숫자만 포함되어 있으면 전화번호(`phone`) 모드로, 문자가 포함되어 있으면 사번(`employee`) 모드로 인식합니다.
- **Phone**: 전화번호를 SSO headless 인증 흐름에 전달합니다.
- **Employee**: 비밀번호 입력란 노출 및 OIDC Password Grant 요청 실행.
### 2. SSO Headless 인증 (Real Communication)
데모 앱은 사용자로부터 받은 식별자와 자격 증명을 SSO 서버의 headless 인증 엔드포인트로 직접 전달합니다.
- SSO 서버가 해당 방식을 허용하도록 설정되어 있어야 하며, 화이트리스트에 등록된 `REDIRECT_URI`와 일치해야 합니다.
- 기존 자동 전화번호 로그인은 `POST /api/v1/auth/headless/link/init`로 링크를 발송한 뒤 `POST /api/v1/auth/headless/link/poll`로 승인 완료를 기다리는 흐름입니다.
- 새 전화번호 로그인 탭은 `POST /api/v1/auth/headless/phone-login`으로 직접 전송합니다.
- 필요하면 `PHONE_HEADLESS_LINK_INIT_ENDPOINT`, `PHONE_HEADLESS_LINK_POLL_ENDPOINT`, `PHONE_HEADLESS_LOGIN_ENDPOINT`로 오버라이드할 수 있습니다.
### 3. Tenant 접근 제한 처리
Headless RP도 일반 로그인과 동일하게 RP metadata의 `tenant_access_restricted`, `allowed_tenants` 설정 영향을 받습니다.
- headless password login 자체는 성공해도, 후속 consent 단계에서 tenant 제한이 걸릴 수 있습니다.
- 이 경우 Baron SSO는 `403 tenant_not_allowed`를 반환합니다.
- 데모 앱은 이 응답을 소비해 `userfront`의 locale 포함 에러 화면으로 이동시킵니다.
- 기본 경로: `/ko/error?error=tenant_not_allowed&error_description=...&details=...`
- locale 경로를 바꾸고 싶으면 `.env``ERROR_LOCALE_PATH`를 추가해 덮어쓸 수 있습니다.
### 4. Back-Channel Logout
이 데모는 Baron SSO가 발행한 `logout_token`을 받아 RP 세션을 즉시 파기할 수 있습니다.
- `POST /backchannel-logout` 엔드포인트가 필요합니다.
- Baron이 서명한 `logout_token``BARON_BACKCHANNEL_JWKS_URL`의 공개키로 검증합니다.
- 로그인 성공 시 `id_token``sid` 또는 `sub`를 기준으로 RP 세션이 메모리에 바인딩됩니다.
- Baron에서 back-channel logout이 발생하면 해당 `sid` 또는 `sub`에 연결된 세션이 삭제됩니다.
- 기본 JWKS 주소는 `BARON_API_BASE_URL` 기준으로 `<BARON_API_BASE_URL>/api/v1/auth/backchannel/jwks.json` 입니다.
예시:
```env
ERROR_LOCALE_PATH=/ko/error
```
### 4. 테스트 체크리스트
다른 사용자가 headless login 작업을 검증할 때는 아래 순서로 확인하는 것이 가장 빠릅니다.
1. tenant 제한 없이 로그인해 headless 기본 흐름이 성공하는지 먼저 확인합니다.
2. RP에 `tenant_access_restricted=true`, `allowed_tenants=[...]`를 설정합니다.
3. 허용된 tenant 계정으로 로그인해 정상 성공 여부를 확인합니다.
4. 허용되지 않은 tenant 계정으로 로그인해 `userfront` 에러 화면으로 이동하는지 확인합니다.
5. 실패 시 `docker logs --tail 100 headless-login-demo`, `docker logs --tail 100 baron_backend`를 같이 확인합니다.
### 5. 장애 분석 포인트
- `Invalid URL`이 보이면 대부분 consent `403`을 RP가 처리하지 못한 경우입니다.
- `audience mismatch`가 보이면 `client_assertion``aud` 또는 Baron SSO의 expected audience 구성이 어긋난 상태입니다.
- `tenant_not_allowed`가 backend 로그에 보이면 Baron SSO의 tenant 제한은 정상 동작 중이며, 이후 처리 위치는 RP 쪽입니다.
## 라이선스
이 프로젝트는 내부 테스트 및 데모 목적으로 제작되었습니다.