Post

Implementing Advance Scope Check (before Token Generation) for Client Credential Grant in IBM API Connect v10

Implementing Advance Scope Check (before Token Generation) for Client Credential Grant in IBM API Connect v10

Hello Tech Enthusiasts 👋,

This article talks about implementing ‘Advance Scope Check’ in IBM API Connect v10. If you’re new to my technical blog, I’d recommend to checkout my last article link, where I’ve covered basics on OAuth and implementing Client Credential (Application) grant type in IBM API Connect.

Overview

For any organization, Security is on top priority. To begin with, let’s understand the importance of scopes in the OAuth framework.

In the authentication and authorization flow of OAuth, authentication is managed through credential verification, while authorization determines access to resources. For example, User-1 might have full access (read/write/update/delete) to a resource or application, whereas User-2 might only have read access to the same resource. This variation in access levels for a particular resource or application is referred to as the scope of access.

Scope Standard

There is no standardized naming convention for scopes. However, as a best practice I recommend using the format <application/resource>:<_access-level_>, while super-user or applications can have _application_ scope omitting the access level, to indicate unrestricted access.

Example:

  • Accessing bank account (Account API) : account:read , account:write, account:update, account:delete
  • Accessing credit information (Credit) : credit:read, credit:write

Alternatively, you can use underscores (_) or hyphens (-) instead of colons (:) such as account-read , or account_read.

Why Scope Check is important ?

I’d like to reference the Zero Trust concept here, which operates on the principle of NEVER TRUST, ALWAYS VERIFY.

By default, when application request token, the Native OAuth Provider checks if the application is subscribed to the API which has OAuth security enforcement. The API could have multiple paths/operations typically aligned with CRUD (Create/Read/Update/Delete) model as per API standards and best Practices. Since these are distinct operations, it is often necessary to enforce access restrictions for specific applications or users.

n a native OAuth provider, it is challenging to determine whether an application subscribed to an API plan is authorized for a specific operation. One alternative is to create multiple plans for each operation, but this approach introduces significant complexity—both operationally and conceptually. A better solution is to implement this with the correct approach, namely Advance Scope Check.

How to implement Simple Advance Scope Check ?

High Level Steps of implementation:

Implementation Steps

Key Considerations for Implementation

To implement Advance Scope Check, we’d need additional service that would :

  • The advance scope check service should map the input application & it’s supplied scope through a property file and returns the allowed scope in response http header x-selected-scope.
  • In case unable to identify, the service should reject the transaction and return non-200 response.
  • The Native OAuth Provider looks for x-selected-scope and override allowed scopes.

Step 1: Create Scope Check Service

The scope service can be implemented and hosted at any application / server. I’m creating and hosting it on DataPower itself (in separate non-apim domain). The service type I’ve implemented is a XML-Firewall service with loopback backend type.

  • Create XML Firewall with loopback type.
  • Configure local-ip as 127.0.0.1 so that service isn’t accessible from outside.
  • Add policy with following implementation:
    • Match action to match all incoming request.
    • Convert Query param to convert the input GET request to XML
    • Add transformation XSLT action which should function in following steps:
      • Extract input app_name and token_scope.
      • Match it with attribute app_name and token_scopefrom the XML property file (Sample file below 👇)
      • Set x-selected-scope header with mapped value.
      • If no value match, log error message No Application Scope Match
    • Add result action
1
2
3
4
5
6
7
8
9
10
11
<!-- Sample XML Property file -->
<AdvanceScopeCheck>
    <!-- Application-1 scope -->
    <Scopes app_name="application-1" token_scope="scope1">
    scope1:read scope1:write scope1:update scope1:delete
    </Scopes>
    <!-- Application-2 scope -->
    <Scopes app_name="application-2" token_scope="scope1">
    scope1:read
    </Scopes>
</AdvanceScopeCheck>

The application-1 and application-2 are the client app that we’d be creating later in Add Subscription.

Step 2: Add Scope Service URL and OAuth Scope in Native OAuth Provider

  • Go to Resources > OAuth Provider
  • Select the Native OAuth Provider
  • Select Scope section from design tab and check Advanced scope check before Token Generation
  • Add Endpoint URL as http:127.0.0.1:<port>/ and the click save.

Sample Scopes in Native OAuth Provider API

Advance Scope Check Sample in Native OAuth Provider

(Optional) The default error generates non intuitive response, so additionally, In the Assemble part, I updated the gateway script ‘oauth-auto-generated-advanced-scope-application’ for non-200 response as :

1
2
3
             // Error non 200 response
             context.set('oauth.custom_error.message', 'Invalid Scope');
             context.set('oauth.custom_error.description', 'Please provide the valid scope.');

Step 3: Create/Update OAuth Secure API

In my API, I created 4 operations for single path and modified the security:scope specifically. Here is the sample yaml file

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
paths:
  /test-oauth-secure:
    get:
      responses:
        '200':
          description: success
          schema:
            type: string
      security:
        - oauth-client-cred:
            - scope1:read
    post:
      responses:
        '200':
          description: success
          schema:
            type: string
      security:
        - oauth-client-cred:
            - scope1:write
    delete:
      responses:
        '200':
          description: success
          schema:
            type: string
      security:
        - oauth-client-cred:
            - scope1:delete
    put:
      responses:
        '200':
          description: success
          schema:
            type: string
      security:
        - oauth-client-cred:
            - scope1:update
securityDefinitions:
  oauth-client-cred:
    type: oauth2
    x-ibm-oauth-provider: oauth-client-credential-grant
    flow: application
    tokenUrl: https://$(catalog.url)/oauth-client-credential-grant/oauth2/token
    scopes:
      scope1: Access to all paths of application
      scope1:read: Read Access
      scope1:write: Write Access
      scope1:delete: Delete Access
      scope1:update: Update Access
security:
  - oauth-client-cred: []

Step 4: Add subscription

As specified above advance-scope-check-property.xml, create 2 applications and subscribe both to the OAuth-Secure-Client-Cred-API

Sample Application Subscription

Step 5: Testing

Below sequence design 👇 depicts the advance-scope flow which we’re going to implement as part of this article:

Advance Scope Check Sequence Diagram

  • I’m using postman scripts to get token and use the token in my next operation.
  • The following screenshot covers all the explanation. Add your comments in the posts if you’d like to additional details or reach out to me on my linkedIn.

5.1: Success / Happy-Path

5.1.1: Application-1 Testing

Application-1 : Get OAuth Token

Application-1 : Validate Read operation

Application-1: Validate Write(Post) Operation

5.1.2: Application-2 Testing

Application-2 : Get OAuth Token

Application-2 : Validate Read operation

5.2: Failure / Unhappy-path

5.2.1: No Scope as part of OAuth token request

Error thrown when no scope in token request

5.2.2: Scope not part of listed scopes

Error when Invalid Scope part of token request

5.2.3 Application-2 calling POST(write) Operation

The following screenshot depicts the behavior where application-2 trying to access POST (write) operation. The call get fails because Application-2 token scope doesn’t have access to scope:write.

Application-2: Calling Write Operation (Error)

Please do let me know your thoughts and any question in comments.

— Keep Learning 😊

— Aditya Singh

If this article helped you in someway and want to support me, you can …

This post is licensed under CC BY 4.0 by the author.