[QnA] XSUAA Scope가 Role Collection에 안 묶이는 이유 — 완전 해결 가이드
![[QnA] XSUAA Scope가 Role Collection에 안 묶이는 이유 — 완전 해결 가이드](https://btpstacks.com/uploads/9d29549f-dfd7-4276-a6c5-0059b56c3233.png)
📖 개요 및 학습 목표
SAP BTP에서 애플리케이션 보안을 설정할 때 가장 흔히 마주치는 문제: "xs-security.json에 scope를 정의했는데 왜 Role Collection에 안 보이지?" 이 글에서는 XSUAA(Authorization and Trust Management Service)의 Scope → Role Template → Role Collection 3단계 구조를 명확히 이해하고, 실제로 발생하는 401/403 에러를 체계적으로 해결하는 방법을 다룹니다.
이 글을 읽으면 다음을 할 수 있습니다:
- ✅ Scope, Role Template, Role Collection의 관계를 명확히 이해하고 설명
- ✅ xs-security.json을 올바르게 작성하고 XSUAA 인스턴스에 반영
- ✅ 401/403 에러 발생 시 5가지 체크리스트로 원인을 빠르게 파악
- ✅ CAP 프로젝트에서 @requires 어노테이션으로 역할 기반 접근 제어 구현
- ✅ 멀티테넌트 환경에서의 신뢰 구성 문제 해결
대상 독자: BTP Cloud Foundry에 앱을 배포한 경험이 있고, 인증/인가 설정에서 막힌 중급 개발자
📚 선수 지식
- SAP BTP Cloud Foundry 환경에서 앱 배포 경험 (cf push)
- OAuth 2.0 기본 개념 — Access Token, Grant Type
- JSON 파일 편집 및 CF CLI 기본 명령어
- CAP(Cloud Application Programming) 기초 (선택사항이나 코드 예제에 포함)
🔧 환경 / 버전 / 준비물
- SAP BTP: Cloud Foundry Runtime (Trial 계정 가능)
- XSUAA Service: application 플랜 (단일 앱) 또는 broker 플랜 (재사용 서비스)
- CF CLI: v8 이상 (
cf version으로 확인) - CAP: @sap/cds 8.x (2024년 이후 릴리스, 선택)
- 도구: BTP Cockpit 접근 권한, VS Code 또는 터미널
권장: BTP Trial에서 먼저 테스트한 후 프로덕션에 적용하세요.

💡 핵심 개념
XSUAA의 권한 구조를 도서관 출입 시스템에 비유하면 이해가 쉽습니다:
- Scope = 개별 권한 카드 — "열람실 출입", "대출 가능", "서고 접근" 같은 최소 단위의 권한입니다.
xs-security.json에서 정의하며, 앱 코드에서 직접 체크하는 대상입니다. 예:$XSAPPNAME.Read,$XSAPPNAME.Admin - Role Template = 권한 묶음 카드 — 여러 Scope를 하나로 묶은 것입니다. "일반 이용자" 카드에는 "열람실 출입 + 대출 가능"이 포함됩니다. 역시
xs-security.json에서 정의합니다. - Role Collection = 직원 배지 — BTP Cockpit에서 생성하고, 사용자에게 직접 할당하는 것입니다. Role Template을 Role Collection에 추가하고, Role Collection을 사용자에게 할당합니다.
# XSUAA 권한 흐름 구조
xs-security.json (개발자가 정의)
└─ scopes: ["Read", "Write", "Admin"] ← 최소 단위 권한
└─ role-templates: ← Scope 묶음
├─ "Viewer" → [Read]
└─ "Manager" → [Read, Write, Admin]
BTP Cockpit (관리자가 설정)
└─ Role Collections: ← 사용자에게 할당
├─ "AppViewers" → Viewer Role Template
└─ "AppManagers" → Manager Role Template
└─ 사용자 할당: user@company.com → "AppManagers"
흔한 오개념:
- ❌ "Scope를 정의하면 자동으로 Role Collection이 생긴다" → ⭕ Scope → Role Template는 xs-security.json에서 정의하지만, Role Collection은 BTP Cockpit에서 별도로 생성하고 Role Template을 추가해야 합니다. 이 단계를 빠뜨리면 scope가 있어도 사용자에게 권한이 전달되지 않습니다.
- ❌ "application 플랜과 broker 플랜은 같다" → ⭕ application 플랜은 단일 앱용, broker 플랜은 재사용 가능한 서비스용입니다. 잘못된 플랜을 선택하면 scope 매핑이 작동하지 않을 수 있습니다.
💻 실전 코드 — 3단계
1단계: xs-security.json 기본 설정
{
"xsappname": "my-bookshop-app",
"tenant-mode": "dedicated",
"scopes": [
{
"name": "$XSAPPNAME.Read",
"description": "Read books"
},
{
"name": "$XSAPPNAME.Write",
"description": "Create and update books"
},
{
"name": "$XSAPPNAME.Admin",
"description": "Full admin access"
}
],
"role-templates": [
{
"name": "Viewer",
"description": "Read-only access",
"scope-references": ["$XSAPPNAME.Read"]
},
{
"name": "Manager",
"description": "Read and write access",
"scope-references": ["$XSAPPNAME.Read", "$XSAPPNAME.Write"]
},
{
"name": "Administrator",
"description": "Full access including admin",
"scope-references": ["$XSAPPNAME.Read", "$XSAPPNAME.Write", "$XSAPPNAME.Admin"]
}
],
"role-collections": [
{
"name": "BookshopViewers",
"description": "Bookshop read-only users",
"role-template-references": [
{ "role-template-name": "Viewer", "service-instance-name": "my-bookshop-xsuaa" }
]
},
{
"name": "BookshopManagers",
"description": "Bookshop managers",
"role-template-references": [
{ "role-template-name": "Manager", "service-instance-name": "my-bookshop-xsuaa" }
]
}
]
}
실행: cf create-service xsuaa application my-bookshop-xsuaa -c xs-security.json
결과: BTP Cockpit → Security → Role Collections에서 "BookshopViewers"와 "BookshopManagers"가 생성되었는지 확인합니다.
2단계: CAP 프로젝트에서 역할 기반 접근 제어
// srv/cat-service.cds — @requires로 역할 기반 접근 제어
service CatalogService {
@requires: 'authenticated-user'
entity Books as projection on bookshop.Books;
@requires: 'Manager'
action submitOrder(book: Books:ID, quantity: Integer) returns { stock: Integer };
@requires: 'Administrator'
action deleteAllBooks();
}
// srv/cat-service.js — 핸들러에서 사용자 권한 확인
module.exports = class CatalogService extends cds.ApplicationService {
async init() {
this.before('submitOrder', (req) => {
// req.user.is('Manager')로 역할 확인 가능
if (!req.user.is('Manager')) {
req.reject(403, 'Manager 역할이 필요합니다');
}
console.log(`주문 요청: user=${req.user.id}, roles=${JSON.stringify(req.user.roles)}`);
});
this.on('submitOrder', async (req) => {
// 비즈니스 로직...
const { book, quantity } = req.data;
const db = await cds.connect.to('db');
const { Books } = db.entities;
const result = await db.run(
UPDATE(Books).set({ stock: { '-=': quantity } }).where({ ID: book })
);
return { stock: result };
});
await super.init();
}
};
3단계: CLI로 Role Collection 검증 및 사용자 할당
-- CF CLI로 XSUAA 인스턴스 확인
$ cf services | grep xsuaa
my-bookshop-xsuaa xsuaa application create succeeded
-- Service Key 생성하여 XSUAA 설정 확인
$ cf create-service-key my-bookshop-xsuaa my-key
$ cf service-key my-bookshop-xsuaa my-key
-- 출력에서 clientid, clientsecret, url 확인
-- 토큰 발급 테스트 (Client Credentials)
$ curl -X POST "{xsuaa-url}/oauth/token" -H "Content-Type: application/x-www-form-urlencoded" -d "grant_type=client_credentials&client_id={clientid}&client_secret={clientsecret}"
-- 응답의 scope 필드에서 할당된 scope 목록 확인
-- Role Collection에 사용자 할당 (BTP Cockpit 또는 CLI)
$ cf curl "/sap/rest/authorization/v2/rolecollections/BookshopManagers/users" -X PUT -d '{"username":"user@company.com","origin":"sap.default"}'
⚠️ 흔한 실수 / 트러블슈팅
Q1: xs-security.json을 수정했는데 변경사항이 반영 안 돼요
- 증상: 새 scope를 추가했는데 Role Template에 나타나지 않음
- 원인: XSUAA 서비스 인스턴스를 업데이트하지 않음
- 해결:
cf update-service my-bookshop-xsuaa -c xs-security.json실행. 단순히 파일만 수정하면 반영되지 않으며, 반드시cf update-service명령으로 인스턴스를 갱신해야 합니다.
Q2: 403 Forbidden — "Insufficient scope"
- 증상: 로그인은 되지만 API 호출 시 403 반환
- 원인 체크리스트: 1) Role Collection에 Role Template이 추가되었는지 확인 2) Role Collection에 사용자가 할당되었는지 확인 3) xs-security.json의 xsappname과 실제 서비스 인스턴스 이름이 일치하는지 확인 4) $XSAPPNAME 접두사가 scope-references에 올바르게 사용되었는지 확인 5) 토큰을 재발급 받았는지 확인 (캐시된 토큰에는 새 scope가 없음)
- 해결: 위 5가지를 순서대로 점검하세요. 대부분 2번(사용자 미할당) 또는 5번(캐시 토큰) 문제입니다.
Q3: 멀티테넌트 환경에서 "token audience invalid"
- 증상: subscriber 테넌트에서 토큰 검증 실패
- 원인: xs-security.json에서
tenant-mode가 "shared"로 설정되어야 하는데 "dedicated"로 되어있거나,allowedproviders가 누락됨 - 해결:
"tenant-mode": "shared"로 변경하고, subscriber 서브어카운트가 provider의 XSUAA를 신뢰하도록 Trust Configuration을 설정하세요.
Q4: Role Collection이 BTP Cockpit에 안 보여요
- 증상: xs-security.json에 role-collections를 정의했는데 Cockpit에 없음
- 원인:
role-collections섹션은 서비스 인스턴스 생성 시에만 적용됩니다. 이미 존재하는 인스턴스에cf update-service하면 role-collections는 무시될 수 있습니다. - 해결: Cockpit에서 수동으로 Role Collection을 생성하고 Role Template을 추가하세요. 또는 인스턴스를 삭제 후 재생성합니다 (주의: 기존 바인딩이 끊어짐).
🚀 다음 단계 / 관련 주제
- IAS(Identity Authentication Service) 연동 — XSUAA 대신 또는 함께 IAS를 사용하는 하이브리드 인증 설정
- Attribute-Based Access Control — Scope 외에 사용자 속성(조직, 지역 등)으로 세밀한 권한 제어
- Principal Propagation — On-Premise 시스템으로 사용자 토큰을 전달하는 SSO 구성
- CAP @restrict 심화 — CDS 레벨에서 행 단위 권한 제어 (where 절 기반)
- App Router 설정 — 프론트엔드 라우팅 + XSUAA 토큰 관리 패턴

📚 참고 자료
- SAP Help: What is SAP Authorization and Trust Management Service — XSUAA 공식 문서
- SAP Help: Security Administration — 인증 및 인가 관리 가이드
- SAP Help: xs-security.json 유지보수 — Application Security Descriptor 상세 스키마
- SAP Tutorial: Secure a Basic Node.js App with XSUAA — 단계별 보안 설정 실습
- SAP Cloud SDK: XSUAA Service Guide — OAuth 흐름별 사용법
- Mindful Chase: XSUAA 인증 트러블슈팅 가이드 — 에러 유형별 해결법
- GitHub: SAP CAP Samples — XSUAA 인가 설정 포함 샘플 프로젝트
📌 본 게시물은 AI(Claude)가 공개된 자료를 기반으로 자동 생성한 콘텐츠입니다. 기술 내용의 정확성은 SAP 공식 문서 와 교차 확인하시기 바랍니다.
™ SAP, S/4HANA, ABAP, Fiori, SAP BTP 등은 SAP SE 또는 그 계열사의 등록 상표입니다. 본 사이트는 SAP SE 와 공식적인 관련이 없는 비공식 학습 자료 입니다.
📧 저작권 침해 / 오류 / 콘텐츠 신고: btpstacks.com 의 "문의" 메뉴를 이용해주세요.