# 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)
[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` 등)가 필요해지더라도, 앱의 스코프 설정만 변경하면 자동으로 승인 로직에 반영됩니다.