# TDC114PLUS / tdc114plus-auth / Baron SSO Redirect Flow

작성일: 2026-07-15

## 결론

현재 우리가 진행 중인 방식에서는 TDC114PLUS 앱 RP의 아래 callback은 로그인 완료에 필수 아님이다.

```text
https://114.hmac.kr/auth/callback
```

현재 필요한 것은 `tdc114plus-auth` 중계서버 RP에 등록한 redirect URI다.

```text
https://114-auth.hmac.kr/api/v1/auth/oidc/callback
```

개발 로컬에서는 아래 URI를 사용한다.

```text
http://172.16.8.198:5001/api/v1/auth/oidc/callback
http://127.0.0.1:5001/api/v1/auth/oidc/callback
```

다만 앱 소스에는 아직 예전/보조 구조인 아래 callback이 남아 있다.

```text
https://114.hmac.kr/auth/callback
```

이 값은 Hosted Login + PKCE 방식으로 앱이 Baron SSO에 직접 붙던 구조의 흔적이다.

## 역할 구분

### TDC114PLUS 앱

- 전화번호 입력 화면 제공
- `tdc114plus-auth`에 링크 발송 요청
- `pendingRef`를 받아 저장
- 계속 poll
- poll 성공 시 받은 앱 세션 token 저장
- 직원검색 화면 진입

### tdc114plus-auth

- 앱 대신 Baron SSO headless API 호출
- `client_assertion` 생성
- `login_challenge` 확보
- Baron SSO `link/init`, `link/poll` 호출
- poll 성공 후 `redirectTo` 추적
- consent 필요 시 자동 consent 처리
- authorization code 수신
- token exchange
- 앱용 session token 발급
- 직원/조직 API 중계

### Baron SSO

- 사용자/전화번호 검증
- SMS 링크 발송
- 사용자가 링크 클릭하면 승인 처리
- OIDC authorization code 발급
- token endpoint 제공

## 현재 실제 로그인 흐름

### 1. 앱 실행

```text
TDC114PLUS 앱
```

### 2. 사용자가 전화번호 입력 후 로그인 링크 보내기

로컬 개발 기준:

```http
POST http://127.0.0.1:5001/api/v1/auth/link/init
```

실서버/도메인 기준:

```http
POST https://114-auth.hmac.kr/api/v1/auth/link/init
```

요청 예:

```json
{
  "loginId": "01091365338"
}
```

### 3. tdc114plus-auth가 Baron SSO OIDC authorization 시작

```http
GET https://sso.hmac.kr/oidc/oauth2/auth
```

주요 값:

```text
client_id=tdc114plus-auth RP client_id
redirect_uri=https://114-auth.hmac.kr/api/v1/auth/oidc/callback
response_type=code
scope=openid profile email tenants
state=...
```

### 4. Baron SSO가 login_challenge 발급

```http
302 Location: https://sso.hmac.kr/login?login_challenge=...
```

### 5. tdc114plus-auth가 Baron SSO headless link init 호출

```http
POST https://sso.hmac.kr/api/v1/auth/headless/link/init
```

요청 주요 값:

```json
{
  "client_id": "tdc114plus-auth RP client_id",
  "client_assertion": "tdc114plus-auth가 개인키로 서명한 JWT",
  "loginId": "01091365338",
  "login_challenge": "..."
}
```

### 6. Baron SSO 응답

```json
{
  "status": "pending",
  "pendingRef": "...",
  "interval": 2
}
```

### 7. tdc114plus-auth가 앱에 pendingRef 반환

```json
{
  "status": "pending",
  "pendingRef": "...",
  "pollInterval": 2
}
```

### 8. 앱이 poll 시작

```http
POST http://127.0.0.1:5001/api/v1/auth/link/poll
```

요청:

```json
{
  "pendingRef": "..."
}
```

### 9. tdc114plus-auth가 Baron SSO poll 호출

```http
POST https://sso.hmac.kr/api/v1/auth/headless/link/poll
```

요청 주요 값:

```json
{
  "client_id": "tdc114plus-auth RP client_id",
  "client_assertion": "tdc114plus-auth가 개인키로 서명한 JWT",
  "pendingRef": "..."
}
```

## 운영 점검 기준 추가

2026-07-20 기준 실제 점검에서 아래 사실을 확인했다.

- 앱에서 `link/init` 요청이 로컬 `tdc114plus-auth:5001`에 정상 도달할 수 있다.
- `pendingRef` 생성과 `link/poll` 반복도 서버 로그에서 확인할 수 있다.
- 실기기 `adb reverse tcp:5001 tcp:5001`까지 정상이어도, 실제 사용자 휴대폰에 문자 링크가 도착하지 않을 수 있다.

이 경우의 판단 기준은 아래와 같다.

1. `link/init` 로그가 찍히고 `pendingRef`가 생성되면 앱 -> auth broker 구간은 우선 정상이다.
2. 이후 `link/poll`이 계속 pending인데 사용자 휴대폰에 문자가 오지 않으면, 우선 Baron SSO 문자 발송 또는 SMS 연계 구간을 의심해야 한다.
3. 즉 `pendingRef 생성 성공`은 `문자 실제 발송 성공`과 같은 뜻이 아니다.

### 10. 사용자가 SMS 링크 클릭

```http
GET https://sso.hmac.kr/ko/verify-cc/...
```

또는 내부적으로:

```http
POST https://sso.hmac.kr/api/v1/auth/magic-link/verify
```

### 11. Baron SSO는 브라우저에 승인 완료 화면 표시

```text
https://sso.hmac.kr/ko/verify-complete
```

여기서 앱으로 자동 이동하지 않는다. 현재 Baron SSO 정책상 정상이다.

### 12. 앱의 poll이 성공 감지

Baron SSO에서 `tdc114plus-auth`로 내려오는 값:

```json
{
  "status": "ok",
  "redirectTo": "https://sso.hmac.kr/oidc/oauth2/auth?..."
}
```

### 13. tdc114plus-auth가 redirectTo 추적

```http
GET https://sso.hmac.kr/oidc/oauth2/auth?...
```

### 14. consent가 필요하면 consent 처리

```http
GET https://sso.hmac.kr/api/v1/auth/consent?consent_challenge=...
```

이후:

```http
POST https://sso.hmac.kr/api/v1/auth/consent/accept
```

### 15. Baron SSO가 최종 callback으로 code 전달

```http
GET https://114-auth.hmac.kr/api/v1/auth/oidc/callback?code=...&state=...
```

여기가 현재 필요한 redirect URI다.

### 16. tdc114plus-auth가 token exchange

```http
POST https://sso.hmac.kr/oidc/oauth2/token
```

주요 값:

```text
grant_type=authorization_code
code=...
redirect_uri=https://114-auth.hmac.kr/api/v1/auth/oidc/callback
client_id=tdc114plus-auth RP client_id
client_assertion=...
```

### 17. Baron SSO token 응답

```json
{
  "access_token": "...",
  "id_token": "...",
  "token_type": "Bearer",
  "expires_in": 3600
}
```

### 18. tdc114plus-auth가 앱용 세션 발급

앱 poll 응답:

```json
{
  "status": "ok",
  "accessToken": "tdc114plus-auth 앱용 세션 JWT",
  "user": {
    "id": "...",
    "name": "...",
    "email": "..."
  }
}
```

### 19. 앱이 직원검색/조직정보 호출

로컬 개발 기준:

```http
GET http://127.0.0.1:5001/api/v1/integrations/org-context
Authorization: Bearer 앱용 세션 JWT
```

실서버 기준:

```http
GET https://114-auth.hmac.kr/api/v1/integrations/org-context
Authorization: Bearer 앱용 세션 JWT
```

## 그럼 https://114.hmac.kr/auth/callback은 무엇인가

아래 구조에서 필요했던 URI다.

```text
앱이 Baron SSO에 직접 OIDC 로그인 요청
-> Baron SSO 로그인
-> Baron SSO가 앱 App Link로 code 전달
-> 앱이 직접 token exchange
```

그때 필요한 redirect URI가 아래 값이었다.

```text
https://114.hmac.kr/auth/callback
```

하지만 지금 구조는 바뀌었다.

```text
앱이 직접 Baron SSO OIDC callback을 받지 않음
앱은 tdc114plus-auth에만 요청함
OIDC callback은 tdc114plus-auth가 받음
```

그래서 현재 필수 callback은 아래 값이다.

```text
https://114-auth.hmac.kr/api/v1/auth/oidc/callback
```

## 정리 표

| 항목 | 현재 필요 여부 | 용도 |
| --- | --- | --- |
| `https://114.hmac.kr/auth/callback` | 필수 아님 | 예전 앱 직접 OIDC/PKCE App Link callback |
| `https://114-auth.hmac.kr/api/v1/auth/oidc/callback` | 필요 | `tdc114plus-auth`가 Baron SSO authorization code 받는 callback |
| `https://114-auth.hmac.kr/.well-known/jwks.json` | 필요 | Baron SSO가 `tdc114plus-auth` client_assertion 서명 검증 |
| `https://114-auth.hmac.kr/api/v1/auth/link/init` | 필요 | 앱이 중계서버에 링크 발송 요청 |
| `https://114-auth.hmac.kr/api/v1/auth/link/poll` | 필요 | 앱이 승인 상태 확인 |

## 현재 판단

Baron SSO 쪽에 TDC114PLUS 앱 RP를 계속 유지할 필요는 현재 흐름 기준으로 낮다.

정식 구조를 단순화하려면 `tdc114plus-auth` RP 하나만 남기는 방향이 맞다.

2026-07-15 작업으로 앱 코드 안의 `/auth/callback` 직접 수신 흔적은 제거했다.

제거한 항목:

- AndroidManifest의 `https://114.hmac.kr/auth/callback` App Link intent-filter
- Flutter GoRouter의 `/auth/callback` route
- 앱 직접 OIDC/PKCE callback 화면
- 앱 직접 OIDC/PKCE token exchange 코드
- startup의 Windows App Link 테스트 서버 강제 확인

남겨둘 수 있는 항목:

- 이 문서 안의 `https://114.hmac.kr/auth/callback` 언급은 과거 구조 설명과 혼선 방지를 위한 기록이다.
