Business Use Case
OrganizationABC is an API provider who has published an API which is having two operations such as sales order creation & purchase order creation. Another two different organizations (CompanyA & CompanyB) will be consuming this API where CompanyA is responsible for posting sales order to backend application whereas CompanyB is responsible for post purchase order to the backend application. So, CompanyA shouldn’t have access to the resource /PurchaseOrderCreation and similarly, CompanyB shouldn’t have access to /SalesOrderCreation. In this blog, we will be discussing one of the custom approaches to achieve this feature in SAP API Management.
Technical Approach
Prerequisites
- Create an API Proxy with multiple resources. (Example: /SalesOrderCreation, /PurchaseOrderCreation)
- Publish a product for the above API Proxy to Developer Portal.
- Create two different applications using the above product in Developer Portal.
Steps to be followed
1. Add a custom attribute (Attribute Name: Scope) in each of application which is subscribed to this API in Developer portal.
Here, I have created an application named APP_CompanyA and maintained the Scope attribute with the value as “Demo_API-POST-/SalesOrderCreation”.
Here, I have defined the Scope in a custom attribute with the combination of <API Proxy Name>-<Method>-<Resource Name to which it should have access>
Demo_API: API Proxy name
POST: Method
This application should have access to /SalesOrderCreation only. Hence the Scope value has been defined as “Demo_API-POST-/SalesOrderCreation”.

Similarly, I have created another application for CompanyB and defined the Scope as a custom attribute:

2. Add “Access Entity” policy at the PreFlow(Incoming Request) of ProxyEndpoint to retrieve the profile data for applications during API proxy message processing. Add the below content inside the policy:
<!-- this policy can be used to retrieve all details of an entity(application, API Product, company, company developer, consumer key and developer) -->
<AccessEntity async="true" continueOnError="false" enabled="true" xmlns='http://www.sap.com/apimgmt'>
<!-- the name of the type of entity to be retrieved -->
<EntityType value="app"/>
<!-- The value that identifies the specific entity whose profile should be retrieved. The ref attribute identifies the variable that provides the source of the identifier.
The type identifies the EntityType populated by the referenced variable -->
<EntityIdentifier ref="client_id" type="consumerkey"/>
<!-- used when EntityIdentifier is not gaurenteed unique -->
</AccessEntity>
- Add Extract Variable policy at PreFlow(Incoming Request) of ProxyEndpoint to retrieve the value of Scope defined as a custom attribute into a variable. You can add the below content to the policy:
<!-- Extract content from the request or response messages, including headers, URI paths, JSON/XML payloads, form parameters, and query parameters -->
<ExtractVariables async="true" continueOnError="false" enabled="true" xmlns='http://www.sap.com/apimgmt'>
<!-- the source variable which should be parsed -->
<Source>AccessEntity.ExtractAtributes</Source>
<!-- Specifies the XML-formatted message from which the value of the variable will be extracted -->
<XMLPayload>
<!-- Specifies variable to which the extracted value will be assigned -->
<Variable name="scope" type="string">
<!-- Specifies the XPath defined for the variable -->
<XPath>/App/Attributes/Attribute[2]/Value</XPath>
</Variable>
</XMLPayload>
</ExtractVariables>
- Add a JavaScript policy at the PreFlow(Incoming Request) of ProxyEndpoint to frame a combination of <API proxy name>-<API method>- <Resource Name> during API proxy message processing runtime and check if that includes into the variable which we have set in the previous policy. Based on this check, we will be setting another variable named “GrantAccess” which contains the value as true/false. JavaScript is as below:
var GrantAccess = ""
var scope = context.getVariable('scope')
var proxypathsuffix = context.getVariable('proxy.pathsuffix')
var proxyverb = context.getVariable('request.verb')
var proxyname = context.getVariable('apiproxy.name')
var APIDetails = proxyname + "-" + proxyverb + "-" + proxypathsuffix
var GrantAccess = scope.includes(APIDetails)
context.setVariable('GrantAccess', GrantAccess);
- Add Raise Fault policy at PreFlow(Incoming Request) of ProxyEndpoint to raise a custom response message in case the “GrantAccess” variable value is false. Policy content would be as below:
Condition String: GrantAccess = ‘false’
<RaiseFault async="true" continueOnError="false" enabled="true" xmlns="http://www.sap.com/apimgmt">
<!-- Defines the response message returned to the requesting client -->
<FaultResponse>
<Set>
<Payload contentType="application/json" variablePrefix="@" variableSuffix="#">
{
"successful": false,
"status": 500,
"error": "Restricted resource access",
"Response": "You don't have access to the API resource which you are trying to access. Please contact the system administrator to define the scope."
}
</Payload>
<StatusCode>500</StatusCode>
<ReasonPhrase>Undefined Scope</ReasonPhrase>
</Set>
</FaultResponse>
<IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
</RaiseFault>
Testing
Scenario – 1
Using the Client ID & Client Secret of CompanyB and trying to access “/SalesOrderCreation” API resource.
Expected Outcome: This should throw an exception as CompanyB is responsible only for purchase order creation.

Scenario – 2
Using the Client ID & Client Secret of CompanyA and trying to access “/PurchaseOrderCreation” API resource.
Expected Outcome: This should throw an exception as CompanyA is responsible only for sales order creation.
