49 · xs-security.json Deep Dive

Full xs-security.json vocabulary: scopes, attributes, role-templates, oauth2-configuration, and $XSAPPNAME.

Episode 49 — xs-security.json Deep Dive

What you'll learn

Why this matters

xs-security.json is the security contract for your app. Every scope, role, and attribute you'll use in @requires and @restrict CDS annotations must be declared here first. Knowing the full vocabulary means you can express any authorization requirement without working around the framework.

Complete xs-security.json structure

{
  "xsappname":   "bookshop",
  "tenant-mode": "dedicated",

  "scopes": [
    {
      "name":         "$XSAPPNAME.Admin",
      "description":  "Full administrative access"
    },
    {
      "name":         "$XSAPPNAME.Buyer",
      "description":  "Purchase books"
    },
    {
      "name":         "$XSAPPNAME.ViewReports",
      "description":  "View sales reports",
      "granted-apps": ["$XSAPPNAME"]   // restricts who can grant this scope
    }
  ],

  "attributes": [
    {
      "name":        "region",
      "description": "Sales region assigned to the user",
      "valueType":   "string"
    },
    {
      "name":        "costCenter",
      "description": "User's cost center",
      "valueType":   "string"
    }
  ],

  "role-templates": [
    {
      "name":             "Admin",
      "description":      "Administrator",
      "scope-references": ["$XSAPPNAME.Admin"],
      "attribute-references": []
    },
    {
      "name":             "RegionalBuyer",
      "description":      "Buyer with region restriction",
      "scope-references": ["$XSAPPNAME.Buyer"],
      "attribute-references": [
        { "name": "region" }   // ← attribute available in this role
      ]
    }
  ],

  "oauth2-configuration": {
    "token-validity":     43200,
    "refresh-token-validity": 2592000,
    "redirect-uris": [
      "https://*.cfapps.eu10.hana.ondemand.com/**",
      "http://localhost:5000/**"
    ],
    "system-attributes": ["groups", "rolecollections"],
    "user-attributes":   ["region", "costCenter"]
  }
}

Scopes vs role templates vs role collections

xs-security.json defines:
  scope          → atomic permission (e.g., bookshop.Admin)
  role-template  → named group of scopes (e.g., Admin = [bookshop.Admin])

BTP Cockpit defines:
  role           → instance of a role template (admin can add attributes)
  role-collection → named group of roles (e.g., "Bookshop Admins" = [Admin role])

User assignment:
  BTP user → assigned to role-collection → gets the scopes → CAP reads from JWT

User attributes in JWT

After assigning a role with attributes to a user:

// Decoded JWT — attributes from xs-security.json
{
  "user_name": "alice",
  "scope":     ["bookshop.Buyer"],
  "xs.user.attributes": {
    "region":     ["EMEA", "NA"],    // user has both regions
    "costCenter": ["CC-1001"]
  }
}
// In CAP handler
req.user.attr.region      // ['EMEA', 'NA']
req.user.attr.costCenter  // ['CC-1001']

$XSAPPNAME placeholder — why it matters

// WRONG — hardcoded app name
{ "name": "bookshop.Admin" }

// CORRECT — $XSAPPNAME is substituted at runtime
{ "name": "$XSAPPNAME.Admin" }
// Becomes: "bookshop.Admin" in dedicated tenant
// Becomes: "bookshop!t<tenant-id>.Admin" in shared tenant mode

Always use $XSAPPNAME. Hardcoded names break multitenant deployments.

Multitenant vs dedicated

// Dedicated — one subaccount, one XSUAA instance (most apps start here)
{ "tenant-mode": "dedicated" }

// Shared — same XSUAA serves multiple subscriber tenants (SaaS)
{ "tenant-mode": "shared" }

Token validity tuning

"oauth2-configuration": {
  "token-validity":         3600,     // 1 hour (access token)
  "refresh-token-validity": 1209600,  // 14 days (refresh token)
  "autoapprove":            true,     // skip consent screen for trusted apps
  "allowedproviders":       ["sap.default"]   // restrict to SAP IdP
}

Hands-on exercise

  1. Add a region attribute to your XSUAA configuration
  2. Create a RegionalBuyer role template that includes the region attribute
  3. In BTP Cockpit, create a role instance and assign region=EMEA to your user
  4. Log in and decode your JWT — verify xs.user.attributes.region is present

Checkpoint ✓

Sign in for progress tracking & Q&A →