Scope 레퍼런스
Scope는 공백 구분 문자열입니다 (profile email phone, 콤마 ❌).
표준 Scope
| scope | userinfo 반환 필드 | 비고 |
|---|---|---|
profile:basic | sub, preferred_name, full_name | 기본 신원. profile alias 허용, 등록·요청은 profile:basic 권장 |
email | sub, email, email_verified | |
phone | sub, phone_number | 별도 동의 |
address | sub, address, postal_code | 별도 동의 |
identity:level | sub, identity_verified_level (0/1/2/3) | 실명인증 레벨. 신규 앱은 명시 요청 필요 (legacy 앱은 profile에 자동 포함) |
openid | id_token 발급 + sub | OIDC 1.0 활성화 |
identity_verified_level 값: 0 unverified · 1 email_verified · 2 phone_verified · 3 sp_verified. logi는 실명/주민번호 미보유, 정수 플래그만 제공.
커스텀 Scope
네임스페이스 필수 형식 <namespace>:<key> (콜론 1개):
krx_listing:reviewer_role
blog:post.writeUser#custom_claims jsonb {namespace: {key: value}} 로 저장, scope 요청 시 id_token/userinfo 에 병합.
앱 등록 시 allowed_scopes
{
"oauth_application": {
"redirect_uris": ["https://app.example.com/cb"],
"allowed_scopes": ["profile", "email"]
}
}Scope 설정
logi apps edit <id> --add-scope phoneapp = OauthApplication.kept.find_by(name: "your_app")
app.set_scopes!(["openid", "profile", "email", "phone"])Scope drift 처리
기본 정책은 block 입니다 — 요청 scope 중 allowed_scopes 에 없는 것이 하나라도 있으면 요청 전체가 invalid_scope 로 거절됩니다 (callback-safe redirect). 운영자가 앱 단위로 log_only(미등록 scope silent drop 후 등록된 subset 으로 진행) 또는 alert(log_only + 관리자 알림) 로 완화할 수 있습니다.
| 케이스 | 기본 (block) | log_only / alert |
|---|---|---|
| 모든 요청 scope 등록됨 | ✅ 진행 | ✅ 진행 |
| 일부 미등록 | ❌ invalid_scope | ⚠️ 미등록 drop, 등록된 것으로 진행 |
| 모두 미등록 | ❌ invalid_scope | ❌ invalid_scope |
required: true scope 가 effective 에서 누락 | ❌ invalid_scope | ❌ invalid_scope |
정책과 무관하게 drift 는 항상 기록됩니다 (로그 + drift record + webhook_url 설정 시 최초 1회 webhook) — block 으로 거절된 경우에도 운영자가 원인을 추적할 수 있습니다.
감지 방법
1. 서버 로그 (client_id 로 grep):
[oauth] scope_drift app_id=4 client_id=logi_xxx policy=block dropped=phone,address kept=profile,email2. Webhook scope.drift_detected (HMAC-SHA256 서명, (app_id, scope_name) 페어당 1회):
{
"event_type": "scope.drift_detected",
"application_id": 4,
"payload": {
"scope_name": "phone",
"client_id": "logi_xxx",
"first_seen_at": "2026-04-29T01:30:00Z",
"allowed_scopes": ["openid", "profile:basic", "email"]
}
}3. 토큰 응답 헤더 X-Logi-Scope-Drift — 최근 7일 내 기록된 drift 이력을 정상 token 응답에 echo. 기본 block 정책에서는 drift 가 포함된 요청 자체가 invalid_scope 로 거절되므로, 이 헤더는 이후의 정상 token 응답(드리프트 없는 요청)에 이력으로 나타납니다:
HTTP/1.1 200 OK
X-Logi-Scope-Drift: address,phoneif drift = res["X-Logi-Scope-Drift"]
Rails.logger.warn("[logi] scope drift: #{drift}")
end4. Escalation webhook scope.drift_unresolved — 초기 알림 7일 후에도 drift 진행 중이면 1회 발사.
5. 개발자 대시보드 — Apps 카드에 "Scope drift" 핀, 상세에 drift 테이블.
required 마킹
app.oauth_application_scopes.create!(oauth_scope: email_scope, required: true)필수 scope 거부 시 → access_denied.
재인가 UX
사용자가 profile email 동의 이후:
| 요청 scope | 동작 |
|---|---|
동일하거나 축소 (profile) | UI 스킵, 즉시 code 발급 |
확장 (profile email phone) | "NEW" 배지 + 추가 동의 |
| Consent revoke 후 | Consent 화면 재노출 |
요청 방법
GET /oauth/authorize?...&scope=profile+email+openid&...공백 구분, URL encoding 시 %20 또는 +. 응답 scope 필드는 실제 부여된 scope 를 echo (사용자가 일부만 동의 가능).