scope 정책 로직 문서 정리

This commit is contained in:
2026-04-13 18:10:50 +09:00
parent 50e3b2040e
commit ee2e186bd6

View File

@@ -0,0 +1,97 @@
# Headless 스코프(Scope) 및 자동 승인(Auto-Consent) 가이드
이 문서는 Headless 로그인 환경에서 애플리케이션이 사용자 정보를 가져오기 위해 사용하는 **스코프(Scope)**의 개념과, IdP의 화면 없이 권한을 획득하는 **자동 승인(Auto-Consent)** 로직을 설명합니다.
---
## 1. 요구 스코프 (Requested Scopes)
데모 앱은 OIDC 표준에 따라 다음 스코프를 IdP(Baron SSO)에 요청합니다.
| 스코프 | 필수 여부 | 역할 및 획득 데이터 |
| :-------- | :-------: | :------------------------------------------------------------------ |
| `openid` | **필수** | 해당 요청이 OIDC 인증임을 명시. `id_token` 발급을 위해 반드시 필요. |
| `profile` | 권장 | 사용자의 기본 프로필 정보(이름, 사번, 부서명 등) 접근 권한. |
| `email` | 권장 | 사용자의 이메일 주소 정보 접근 권한. |
데모 앱은 최초 인증 요청(`GET /oauth2/auth`) 시 `scope=openid profile` 형식으로 권한을 요구합니다.
---
## 2. 자동 승인(Auto-Consent) 흐름도
일반적인 OIDC 환경에서는 사용자에게 '정보 제공 동의' 화면이 노출되지만, Headless 환경에서는 **RP 서버가 이 과정을 백그라운드에서 자동으로 수행**합니다.
```mermaid
sequenceDiagram
autonumber
participant Browser as 사용자 브라우저
participant RP as 데모 앱 서버 (RP)
participant SSO as Baron SSO (IdP)
RP->>SSO: 1. 본인 인증 요청 (전화번호)
SSO-->>RP: 2. 인증 성공 및 리다이렉트 (redirectTo: /consent...)
Note over RP: [자동 승인 로직 시작]
RP->>RP: 3. 리다이렉트 경로 중 '/consent' 감지
RP->>SSO: 4. 동의 상세 정보 요청 (GET /api/v1/auth/consent)
SSO-->>RP: 5. 요청된 스코프 정보 반환 (openid, profile 등)
RP->>SSO: 6. 동의 승인 API 호출 (POST /api/v1/auth/consent/accept)<br/>[grant_scope 포함]
SSO-->>RP: 7. 최종 리다이렉트 주소 반환 (code=...)
Note over RP: [표준 OIDC 흐름 복귀]
RP->>SSO: 8. Token Exchange (Code -> id_token)
SSO-->>RP: 9. 사용자 정보가 담긴 id_token 발급
RP-->>Browser: 10. 세션 생성 및 로그인 완료 안내
```
---
## 3. 핵심 구현 코드 (server.js)
데모 앱의 `server.js``resolveRedirects` 함수는 SSO 서버로부터 오는 리다이렉트 주소를 추적하다가, 동의 화면(`consent_challenge`)이 나타나면 이를 가로채서 처리합니다.
```javascript
if (currentUrl.includes("/consent")) {
console.log(
" [자동 승인] 사용자의 정보 제공 동의 화면이 감지되어 시스템이 자동으로 승인 중입니다.",
);
// 1. URL에서 consent_challenge 추출
const consentUrl = new URL(currentUrl);
const consentChallenge = consentUrl.searchParams.get("consent_challenge");
// 2. SSO 서버에 현재 요청된 스코프가 무엇인지 확인
const detailsUrl = new URL("/api/v1/auth/consent", currentUrl);
detailsUrl.searchParams.set("consent_challenge", consentChallenge);
const detailsRes = await fetch(detailsUrl.toString(), {
headers: { Cookie: nextCookies },
});
const consentInfo = await detailsRes.json();
// 3. 확인된 스코프(openid, profile 등)를 모두 허용(accept)한다고 서버에 전송
const acceptUrl = new URL("/api/v1/auth/consent/accept", currentUrl);
const acceptRes = await fetch(acceptUrl.toString(), {
method: "POST",
headers: { "Content-Type": "application/json", Cookie: nextCookies },
body: JSON.stringify({
consent_challenge: consentChallenge,
grant_scope: consentInfo.requested_scope || ["openid", "profile"],
grant_access_token_audience:
consentInfo.requested_access_token_audience || [],
}),
});
const acceptPayload = await acceptRes.json();
// 4. 승인 후 받은 최종 목적지(code 포함)로 이동 계속
return resolveRedirects(acceptPayload.redirectTo, nextCookies, depth + 1);
}
```
---
## 4. 특징 및 장점
- **심리스한 UX**: 사용자는 "로그인 중..."이라는 메시지만 보게 되며, 복잡한 권한 동의 절차를 신경 쓸 필요가 없습니다.
- **강력한 보안**: 자동 승인 과정은 서버 대 서버(Back-channel) 통신으로 이루어지며, 브라우저에는 동의 관련 데이터가 전혀 노출되지 않습니다.
- **유연한 확장**: 나중에 새로운 사용자 정보(`email` 등)가 필요해지더라도, 앱의 스코프 설정만 변경하면 자동으로 승인 로직에 반영됩니다.