# RP 자동 로그인 지원 가이드

이 문서는 Baron SSO의 userfront 연동 앱에서 RP를 클릭했을 때 별도 로그인 버튼 클릭 없이 OIDC 인증을 시작하려는 RP 등록자와 RP 개발자를 위한 기준입니다.

## 목적

자동 로그인은 userfront가 RP의 자체 로그인 시작 URL로 사용자를 보내고, RP가 그 진입점에서 OIDC Authorization Code + PKCE 흐름을 직접 시작하는 방식입니다.

Baron backend가 `/oauth2/auth?...` URL을 대신 만들어 넘기지 않는 이유는 RP가 직접 `state`, `nonce`, PKCE verifier/challenge, callback 검증 상태를 관리해야 하기 때문입니다. SPA나 모바일 웹앱은 이 상태가 RP 저장소에 있어야 callback을 안전하게 처리할 수 있습니다.

## 등록 메타데이터

RP는 Hydra client metadata에 다음 값을 저장합니다.

| 키 | 타입 | 설명 |
| --- | --- | --- |
| `auto_login_supported` | boolean | 자동 로그인 지원 여부입니다. `true`일 때만 userfront가 자동 로그인 URL을 진입 URL로 사용합니다. |
| `auto_login_url` | string | RP가 OIDC 로그인을 시작하는 URL입니다. `http` 또는 `https` URL이어야 합니다. |

devfront의 RP 일반 설정에서 다음 항목을 입력합니다.

1. `자동 로그인 지원`을 켭니다.
2. `자동 로그인 시작 URL`에 RP 로그인 시작 URL을 입력합니다.
3. Redirect URI 목록에는 RP callback URL을 등록합니다.
4. 저장 후 userfront 연동 앱 카드에서 “연동앱 클릭 시 별도 로그인 없이 로그인할 수 있습니다.” 안내가 보이는지 확인합니다.

### 설정 규칙

- `자동 로그인 시작 URL`은 반드시 `http://` 또는 `https://`로 시작하는 완전한 절대 URL이어야 합니다.
- Baron은 이 값을 브라우저 진입 URL로만 사용합니다. Baron이 `/oauth2/auth?...`를 대신 생성하지 않습니다.
- 따라서 이 URL은 RP 내부의 "로그인 시작 엔드포인트"여야 합니다.
- 루트(`/`)가 아니라 실제로 OIDC 시작을 트리거하는 경로를 넣어야 합니다.

허용 예시:

```text
http://localhost:3333/login
http://localhost:3333/login?auto=1
https://rp.example.com/login?auto=1&returnTo=%2Fdashboard
```

비권장 예시:

```text
http:localhost:3333/login
localhost:3333/login
/login?auto=1
```

예시:

```text
auto_login_supported: true
auto_login_url: https://org.example.com/login?auto=1
redirect_uri: https://org.example.com/auth/callback
```

### 로컬 RP 예시

로컬에서 `client_id=f5cdd938-a3ae-4e47-ab83-4c13e59949f5` RP가 `http://localhost:3333`에서 실행 중이라면, 메인 페이지가 `/login` 링크를 노출하고 `/login` 호출 시 Baron OIDC authorize endpoint로 `302`를 반환하는지 먼저 확인합니다.

이 경우 devfront 설정 탭의 권장 입력값은 다음과 같습니다.

```text
자동 로그인 지원: ON
자동 로그인 시작 URL: http://localhost:3333/login
Redirect URI: http://localhost:3333/callback
```

주의:

- `http://localhost:3333/`는 홈 URL일 뿐, 로그인 시작 URL이 아닐 수 있습니다.
- `http://localhost:3333/login?auto=1`도 저장은 가능하지만, RP가 `/login`만으로 이미 즉시 OIDC를 시작한다면 `?auto=1`은 필수가 아닙니다.
- 현재 확인된 로컬 데모 RP는 `/login`만 호출해도 Baron OIDC로 바로 리다이렉트합니다.

## RP 구현 요구사항

RP는 `auto_login_url`에서 다음 동작을 구현해야 합니다.

1. `auto=1` 쿼리를 읽습니다.
2. 이미 RP 세션이 있으면 기본 화면 또는 `returnTo` 경로로 이동합니다.
3. RP 세션이 없고 `auto=1`이면 로그인 버튼을 기다리지 않고 OIDC authorization 요청을 시작합니다.
4. OIDC 요청 전에 `state`, `nonce`, PKCE `code_verifier`, `code_challenge`를 생성합니다.
5. `state`, `nonce`, `code_verifier`, `returnTo`는 RP origin의 안전한 저장소에 보관합니다.
6. callback에서 `state`를 검증하고, token 교환 시 `code_verifier`를 사용합니다.
7. 인증 완료 후 저장된 `returnTo`가 있으면 해당 경로로 이동합니다.

권장 URL 형식:

```text
https://rp.example.com/login?auto=1
https://rp.example.com/login?auto=1&returnTo=%2Fdashboard
```

## Baron 내장 RP 기준

Baron 계열 RP는 다음 fallback을 사용합니다. env URL이 설정되어 있을 때만 자동 로그인 지원으로 간주합니다.

| Client ID | Env | 자동 로그인 URL |
| --- | --- | --- |
| `adminfront` | `ADMINFRONT_URL` | `${ADMINFRONT_URL}/login?auto=1` |
| `devfront` | `DEVFRONT_URL` | `${DEVFRONT_URL}/login?auto=1&returnTo=%2Fclients` |
| `orgfront` | `ORGFRONT_URL` | `${ORGFRONT_URL}/login` |

orgfront는 `/login` 진입부터 OIDC authorize 요청을 즉시 시작하며, 기본 callback 이후 이동 경로는 `/chart`입니다. 수동 로그인 화면 검증이 필요하면 `/login?auto=0`으로 자동 시작을 끌 수 있습니다.

## userfront 동작

userfront는 backend의 linked RP 응답을 기준으로 진입 URL을 선택합니다.

1. `status`가 active가 아니면 진입 URL을 만들지 않습니다.
2. `auto_login_supported=true`이면 `auto_login_url`을 우선 사용합니다.
3. `auto_login_url`이 없으면 `init_url`을 사용합니다.
4. 자동 로그인 미지원이면 `init_url`이 있어도 기존 `url`로 이동합니다.

이 기준 때문에 `auto_login_supported=false`인 RP는 accidental auto-login을 수행하지 않습니다.

## 시퀀스 다이어그램

### 1. 설정 저장 흐름

```mermaid
sequenceDiagram
    participant Admin as 운영자
    participant DevFront as DevFront 설정 화면
    participant Backend as Baron Backend
    participant Hydra as Hydra Client Metadata

    Admin->>DevFront: RP 설정 화면 진입
    Admin->>DevFront: 자동 로그인 지원 ON
    Admin->>DevFront: 자동 로그인 시작 URL 입력
    Admin->>DevFront: 저장
    DevFront->>Backend: RP 일반 설정 수정 요청
    Backend->>Backend: auto_login_url 검증
    Note over Backend: scheme=http/https<br/>host 존재 필요
    Backend->>Hydra: client metadata update
    Hydra-->>Backend: 저장 완료
    Backend-->>DevFront: 저장 성공
    DevFront-->>Admin: 저장 완료 표시
```

### 2. userfront에서 자동 로그인 시작

```mermaid
sequenceDiagram
    participant User as 사용자
    participant UserFront as UserFront
    participant Backend as Baron Backend
    participant RP as RP 로그인 시작 URL
    participant Baron as Baron OIDC/Hydra

    User->>UserFront: 연동 앱 카드 클릭
    UserFront->>Backend: linked RP 목록/상태 조회
    Backend-->>UserFront: auto_login_supported, auto_login_url 반환

    alt auto_login_supported = true
        UserFront->>RP: GET auto_login_url
        Note over RP: RP가 state, nonce,<br/>PKCE verifier/challenge 생성
        RP-->>UserFront: 302 Baron authorize endpoint
        UserFront->>Baron: GET /oidc/oauth2/auth
    else auto_login_supported = false
        UserFront->>UserFront: 일반 url 또는 init_url 사용
    end
```

### 3. 로컬 3333 RP 예시 흐름

```mermaid
sequenceDiagram
    participant User as 사용자 브라우저
    participant UserFront as UserFront
    participant RP as localhost:3333 RP
    participant Baron as Baron OIDC

    User->>UserFront: RP 카드 클릭
    UserFront->>RP: GET http://localhost:3333/login
    RP-->>User: 302 /oidc/oauth2/auth?...&client_id=f5cdd938-a3ae-4e47-ab83-4c13e59949f5
    User->>Baron: GET authorize endpoint
    Baron-->>User: 로그인/동의 또는 기존 세션 진행
    Baron-->>RP: callback redirect
    RP-->>User: RP 세션 생성 후 앱 화면 진입
```

## 로직 요약

1. DevFront는 `auto_login_supported`, `auto_login_url`을 RP metadata로 저장합니다.
2. Backend는 `auto_login_supported=true`일 때만 `auto_login_url`을 linked RP 응답에 포함시켜 userfront가 사용할 수 있게 합니다.
3. UserFront는 카드 클릭 시 이 URL로 직접 이동합니다.
4. RP는 그 진입점에서 OIDC 요청을 "직접" 생성해야 합니다.
5. Callback 검증에 필요한 `state`, `nonce`, PKCE 상태는 RP 저장소가 소유해야 합니다.
6. 그래서 Baron이 RP 대신 authorize URL을 만들어 주는 구조로 바꾸면 안 됩니다.

## 검증 체크리스트

RP 등록자는 다음을 확인해야 합니다.

1. devfront에서 `자동 로그인 지원`이 켜져 있습니다.
2. `자동 로그인 시작 URL`이 실제 RP 로그인 진입점입니다.
3. `auto_login_url`에 직접 접속하면 로그인 버튼 클릭 없이 Baron OIDC authorize 요청이 시작됩니다.
4. callback URL이 Redirect URI에 등록되어 있습니다.
5. callback 이후 RP가 `state`, `nonce`, PKCE 검증을 통과합니다.
6. userfront 연동 앱 카드에 자동 로그인 안내 문구가 표시됩니다.
7. userfront에서 RP 카드를 클릭하면 RP 로그인 화면에 머물지 않고 OIDC 흐름으로 진입합니다.

orgfront 기준 검증 명령:

```bash
npm run test -- tests/orgfront-auto-login.spec.ts --project=chromium
```

## 실패 시 확인할 항목

| 증상 | 확인 항목 |
| --- | --- |
| userfront에서 일반 URL로만 이동함 | RP metadata의 `auto_login_supported`가 `true`인지 확인합니다. |
| userfront 카드에 안내 문구가 없음 | backend `/api/v1/user/rp/linked` 응답에 `auto_login_supported=true`가 내려오는지 확인합니다. |
| RP 로그인 화면에 머무름 | RP가 `auto=1` 쿼리를 읽어 자동으로 `signinRedirect` 또는 동일한 OIDC 시작 함수를 호출하는지 확인합니다. |
| callback에서 state 오류 발생 | userfront나 backend가 만든 `/oauth2/auth?...` URL을 직접 쓰지 말고 RP 자체 로그인 시작 URL에서 OIDC 요청을 생성해야 합니다. |
| 등록 저장이 실패함 | `auto_login_supported=true`일 때 `auto_login_url`이 비어 있거나 `http/https` URL이 아닌지 확인합니다. |
| `http:localhost:3333/login` 같은 값이 브라우저에서는 열림 | 브라우저 보정에 기대지 말고 `http://localhost:3333/login`처럼 완전한 절대 URL로 저장합니다. |

## 구현 예시

React RP 예시입니다. 실제 프로젝트에서는 사용하는 OIDC client 라이브러리의 API에 맞춰 적용합니다.

```tsx
const returnTo = searchParams.get("returnTo") || "/";
const shouldAutoLogin = searchParams.get("auto") === "1";

useEffect(() => {
  if (auth.isAuthenticated) {
    navigate(returnTo, { replace: true });
    return;
  }
  if (!shouldAutoLogin || auth.isLoading || auth.activeNavigator) {
    return;
  }
  void auth.signinRedirect({
    state: { returnTo },
  });
}, [auth, navigate, returnTo, shouldAutoLogin]);
```

중요한 점은 `signinRedirect`가 RP에서 실행되어야 한다는 것입니다. 그래야 RP가 callback 검증에 필요한 상태를 보유할 수 있습니다.
