Files
headless-login-demo/docs/headless-consent-and-scope.md
2026-04-13 18:10:50 +09:00

4.6 KiB

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 형식으로 권한을 요구합니다.


일반적인 OIDC 환경에서는 사용자에게 '정보 제공 동의' 화면이 노출되지만, Headless 환경에서는 RP 서버가 이 과정을 백그라운드에서 자동으로 수행합니다.

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.jsresolveRedirects 함수는 SSO 서버로부터 오는 리다이렉트 주소를 추적하다가, 동의 화면(consent_challenge)이 나타나면 이를 가로채서 처리합니다.

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