scope 정책 로직 문서 정리
This commit is contained in:
97
docs/headless-consent-and-scope.md
Normal file
97
docs/headless-consent-and-scope.md
Normal 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` 등)가 필요해지더라도, 앱의 스코프 설정만 변경하면 자동으로 승인 로직에 반영됩니다.
|
||||
Reference in New Issue
Block a user