This article is part of a series about OAuth 2.0 Authorization on OCI API Gateway:
- Complete Guide: How to configure OAuth 2.0 with JWT & IDCS on OCI API Gateway
- Limit access to your APIs with OCI API Gateway using OAuth 2.0 Scopes
- Protect OIC REST APIs with OCI API Gateway and OAuth2 – 1/2
We will talk about limiting access to your APIs using OAuth2 scopes. When we deploy multiple endpoints within an OCI API Gateway deployment, we may want to limit access to certain endpoints (routes) or the amount of access to a specific endpoint (subject to back-end capabilities) and we can achieve this by using OAuth 2.0 scopes.
Check this article if you’re interested in a complete guide on how to configure OAuth 2.0 Authorization on OCI API Gateway and then you can come back to this one for access limits with OAuth2.0 scopes.
What is an OAuth2 scope?
Let’s start by looking at what exactly is an OAuth2 scope. I recommend having a look at the IETF OAuth 2.0 specification definition as well.
OAuth2.0 is a mechanism that allows you to set the amount of access granted to an access token.
Probably, the clearest example would be when an access token is issued to a client with READ access or READ and WRITE access. So, if a client would call an endpoint that requires WRITE access with a token issued with the READ access, the request will fail.
All this can be implemented using scopes – this being said – OAuth does not define any particular values for scopes, so you can implement any scope or combination of scopes you wish.
Use Case Definition
This article will focus on how to use OAuth scopes to limit access on certain routes from your OCI API Gateway deployment and not on how to use scopes for the backend APIs interpretation, since that is highly dependent on the service’s internal architecture and needs. Oracle IDCS will be used as identity provider for OAuth2 token generation and validation.
I’m going to use an example from one of my customers who chose to use OCI API Gateway to unify their back-end endpoints into a single point of entry and to have the authorization made on the Gateway layer rather than on the back-end.
These endpoints are consumed by multiple external clients who each had their own OAuth2 Client Application for token generation but also by some of their internal applications who each, of course, had their own OAuth2 Client Application.
All looks good and secure, but the problem was that both internal and external apps could access all API endpoints deployed in this OCI API Gateway deployment. They wanted to have a clear split of access on the APIs. Some of the APIs are for both internal and external usage, but some are for internal or external usage only.
Now, how can we solve this?
There were many options discussed, including splitting into multiple gateways (like having a separate private Gateway for internal apps) or multiple deployments each with its own OAuth Resource Server, but the best approach for this customer was to use OAuth2 scopes:
- In IDCS (the identity provider used), we can define all scope values in our shared OAauth2 Resource Server
- Each OAuth2 Client App from IDCS will only be assigned with the necessary scope
- so the external client apps will only have an “external scope” and the internal client apps will only have an “internal scope” for the token generation
- In the Gateway configuration, we can define scope values per route (so for each API endpoint) and in this way – limit access on the internal endpoints only for the OAuth2 Client Apps destined for internal usage
- so the external APIs will be attributed with external scope values while the internal APIs will be attributed with the internal scope value while all APIs destined for both internal and external usage will be attributed with both scopes
Here is a high-level overview of the solution:
Let’s see now how all this was implemented!
Firstly, we need to have OAuth2 already configured for our OCI API Gateway:
- The OAuth2 Authorization Policy on the API Gateway Deployment
- An OAuth2 Resource Server in IDCS
- One or more OAuth2 Client Application in IDCS
If you don’t already have these configured, please follow my complete guide here before going forward with this article.
Define your scopes
Before doing any other configuration, you should define the scopes you need. For this use-case, it was pretty simple – we needed to draw a line between internal and external endpoints so we had two scopes:
You can use whatever scopes you want/need for your use case – there are no pre-defined values.
Add all scopes in the IDCS OAuth2 Resource Server
Let’s start by adding our scopes in the OAuth2.0 Resource Server in IDCS:
From the IDCS Console – You can connect to IDCS via OCI from the Identity & Security Menu -> Federation -> OracleIdentityCloudService and now click on the Oracle Identity Cloud Service Console link:
From the IDCS dashboard – go to Applications and search for your Resource Server Application
I will edit the one that we created in the last article – which is oauth-resource-server
Please follow the Complete OAuth2 Implementation Guide if you feel lost at this stage
Go to the Configuration tab and under Resources click on Add Scopes and add our scope values
We can leave the previosly created super-scope there as well
We should now be able to use these scopes in our Client Applications.
Create two IDCS OAuth2 Client Applications and add scope
In the last article, we’ve created a Client Application named my-client-app which was using the /super-scope.
We’ll leave that as is, and we’ll create two new Client Applications:
- one using the /internal-scope for the internal apps named my-internal-app
- and the other using the /external-scope for our external apps named my-external-app
From the IDCS dashboard – go to Applications and click on Add and select Confidential Application
We will repeate these steps for each application. So one App for internal purposes and one for external.
Give the Client Application a Name and click on Next
This is an example for the internal app. The same will apply for the external app as well
Configure this application as a client and check Client Credentials and JWT Assertion
Add the scopes defined in our Resource Server app
We will add /internal-scope for the interal app and /external-scope for the external app
Select the Resource Server application created before
Select the scope and click Add
So in our use case, the /internal-scope will be added for our internal app and /external-scope for our external app
Click on Next and skip the rest of the screens
A Client ID and Client Secret for this client application will be generated for you at the end of the process.
Do not forget to ACTIVATE the application
Now repeat the same steps for the external app and this time, of course, add only the /external-scope.
You can also write down at this stage the Client ID and Client Secret for both of your applications. You can get them from your application dashboard over to the Configuration tab:
Update the Authorization Policy in the OCI API Gateway Deployment
Now that the identity provider (IDCS in this case) part is done, let’s configure the OCI API Gateway.
We will first define all scopes in our general Authorization Policy and then, we will attribute the right scope values for our routes.
Go to your OCI API Gateway deployment, and Click on Edit next to the Authentication Policy
Remember to check this Complete Guide if you need help configuring the Authentication Policy
Click on Show Advanced Options and add all scope values in the Claims section
Add scope values to the routes
Now that we have defined all of our scope values in the Authentication Policy, we will go on each route deployed, and add the right scope(s) for each one.
I will be using Stock Response in my examples.
1. Route 1
I am defining Route 1 as both internal & external usage API.
In your route configuration, click on Show Route Request Policies and them on Edit next to Authorization
Here we are able to edit Authorization details for this particular route
Chose Any as Authorization Type and then add the allowed scopes and Apply
For my example, I will add both /internal-scope and /external-scope as I want to give both client apps access to this API
2. Route 2
This route will be only for external purposes, so only the /external-scope will be added:
3. Route 3
This route will be only for internal purposes, so only the /internal-scope will be added:
Testing our solution
Let’s test our solution to see that everything works as expected:
- Internal Client App (my-internal-client)
- Generate an OAuth2 token using the Client ID and the Client Secret of our Internal Client App created in IDCS and use it to call all 3 endpoints deployed in OCI API Gateway
- Of course, the Internal Client App can only generate tokens using the /internal-scope
- We will be able to call all APIs successfully, except for route 2 which has only /external-scope defined
- External Client App (my-external-client)
- Generate a new OAuth2 token this time using the Client ID and Client Secret of the External Client App created in IDCS and use it to call all 3 endpoints
- This time the tokens will be generated only using the /external-scope
- All API calls will work, except for route 3 which has only /internal-scope defined
Here’s an example of how to test via Postman:
In this example, I call route 1 (which is for both internal and external usage) using the Internal Client App (my-internal-app) credentials (Client ID & Client Secret) and /internal-scope to generate the OAuth2 token.
You can test for all routes with both Internal and External applications to see the results.
Here are some guidelines for the token generation with Postman:
- Configure OAuth 2.0 Authorization as follows:
- Give a token name – it can be anything
- Select Grant Type as Client Credentials
- Use IDCS URL for Access Token URL as follows: https://<your-idcs-hostname>/oauth2/v1/token
- This is IDCS’s URL for OAuth 2.0 token generation
- Use the Client ID from the client application created earlier
- Use the Client Secret from the same client application created earlier
- You can find those again by going in the client application, over in the Configuration tab, and General Information
- Use the Scope from the client application – should be the format <primary-audience>/<scope-name>
- You can find the scope in the client application, over in the Configuration tab as well, but in the Client Configuration section
- Generate New Access Token
- Use the token and Send a new request