How to secure APIs with Okta in API Manager


In our previous post, we learnt how to add Okta as a Client Provider for our Mule apps. With that configuration we can now use an Access Token enforcement policy in API manager for our apps, which will require and validate access tokens issued by Okta. Now it’s time to prove it.

In this post, we will create a test app, we will deploy it and will secure it with our new OpenID access token enforcement policy. We will go through all the steps required to get our mule app secured by Okta.


Create API spec

Let’s start by creating the API spec for the mule app we’ll use for testing. Although we could do a quick test without the API spec, in this example we’re using it. The API spec will be very simple but this is how we would do it in real life. In our real projects all APIs will have an API spec.
For that, go to the our Anypoint platform and create a new project in Design Center for a RAML or OAS API specification. In my case I’ll use RAML. 
Here’s the RAML for our test app:

#%RAML 1.0
title: hello-okta

/hello:
get:
responses:
200:
body:
application/json:
example:
"message": "Hello from Okta"

Notice we’re just using a /hello endpoint with a get operation. That’s it, we don’t need anything more complex. Publish the API spec to Exchange


Create a Mule Project for the test app

Go to Anypoint Studio and create a new Mule Project. Use the API spec created in the previous step with the Download RAML from Design Center option. This way we’ll the interface of our API with the API kit router and the flow to our test endpoint scaffolded in the project.

 

Next, create a new XML configuration file for the implementation and prepare the implementation of the flow in our test app:


Run the project in Anypoint Studio and verify the /hello endpoint works.

Create the API instance in API Manager

Before we deploy our application we will set up the Autodiscovery ID on the app. For that, first we’ll create the API instance. Go to API Manage, click on Add API and select the option Add new API:


Next, select the options:
  • Mule Gateway for the runtime
  • Basic endpoint for Proxy type
  • Mule 4 for the runtime version

Next, choose the option Select API from Exchange and select the app we published to exchange in the first step (this corresponds to the API spec). Click Next.



After that, accept the default options in the next steps (Downstream and Upstream) and click on Save in the last step.
Now we should see the API instance ID in the API summary of our API. Take note of that ID, we’ll need it for our mule implementation




Head back to Anypoint Studio and create a new configuration file Global.xml (best practice). In that file, go to the Global Elements tab and create a new element API Autodiscovery. Paste here the API instance ID:


(Note: In a real project we should not hardcode this ID, we should put it in properties file. This is just for simplicity in our example).
With that our app is ready to be deployed. Go to the Anypoint control plane, Runtime manager and deploy the app. In here, in order for the app to connect to the API instance in API manager and download the policies we need to provide the Environment credentials as runtime properties. For that, in the deployment settings go to the Properties tab and add these two properties:

anypoint.platform.client_id=<YOUR CLIENT ID>
anypoint.platform.client_secret=<YOUR CLIENT SECRET>

The client id and secret of our environment we can take them from API manager home page. Click on the Environment button and it will show you the client credentials of your environment:



Deploy the app. Once it is downloaded we should see the API instance in API manager in Active status:



Apply the Open ID policy

From the API page of our app go to Policies and click Add policy. From the list of policies, select the OpenId Connect Access Token Enforcement and click Next

In the configuration of the policy add read as the scope for our test and click Apply



Update the API spec

When we use this policy we need to reflect the changes in the API spec. For that, click on the contextual menu of the policy and select the API specification snippet

That will display the different snippets to be added depending on the type and version we used for our API Spec. In our case, select the RAML 1.0 and copy the snippet. With those lines, re-open our API spec project in Design Center and them. 

You will have to replace the values for authorizationUri, accessTokenUri and authorizationGrants with the values of our Okta Authorization Server (see Metadata URI on our previous post). Our new API spec should look like this:

#%RAML 1.0
title: hello-okta

securitySchemes:
oauth_2_0:
description: |
This API supports OAuth 2.0 for authenticating all API requests.
type: OAuth 2.0
describedBy:
queryParameters:
access_token:
description: |
Used to send a valid OAuth 2 access token.
type: string
responses:
400:
description: Invalid token.
401:
description: |
Unauthorized or Connection error when connecting to the authorization server.
403:
description: |
Forbidden, invalid client application credentials.
500:
description: |
Bad response from authorization server, or WSDL SOAP Fault error.
settings:
authorizationUri: https://dev-35190461.okta.com/oauth2/default/v1/authorize
accessTokenUri: https://dev-35190461.okta.com/oauth2/default/v1/token
authorizationGrants:
- client_credentials

/hello:
get:
securedBy: [oauth_2_0]
responses:
200:
body:
application/json:
example:
"message": "Hello from Okta"

Publish the API spec to Exchange with a new version.


Lastly, we need to update API manager. Get back to settings page of our API in API manager and from the Actions dropdown on the right side click on Change API Specification



You’ll notice that now there a new version available, more recent than the current one. Select the Latest and click Change



Add Read Scope to the Okta Authorization Server

Head back to our Okta management console and go to Security > API and click on the default Authorization Server (or the one you’re using for mule). 
Next, in the Scopes tab click on Add Scope. Name the new scope read, provide a description and hit Create.




Test the Dynamic Client Registration

Our mule app is finally configured to enforce token access. We can check that out by sending a GET request to the /hello endpoint of our app and we’ll see that now it returns a 400 error - Access token was not provided. 
Now let’s see how we could get access to our app. 
The first thing we need to do is to register a new Client Application in Exchange. Go to Exchange and open the page of the API spec of our test app. Click on Request access at the top. 
In the Request Access pop up select the API instance, and then in application click on Create a new application.



In here we will provide a Name and description of our new Client Application (I’ve called it Postman because I’ll be doing the tests from there). Make sure you select the Client Credentials Grant in the list of OAuth 2.0 Grant types, as this is the OAuth 2.0 flow we will use.

Click Create and, if our configuration is correct, it will create a new Application in Okta with its client_id and client_secret. Head back to Okta and go to Applications > Applications. We should see that there’s a new Application. And if we click on it we’ll see the client id and client secret for this app. These are the client credentials we’ll need to get the Access Token from Okta.



Get the Access Token

Time for testing. To verify that our requests to our hello app require a valid token from Okta we need to first simulate the Client Credentials flow and get a valid token. For that, we’ll use Postman.
In Postman create a POST request to the token endpoint of our Okta Authorization server and add in the body the following key/value pairs using the x-www-forms-urlencoded format:
  • grant_type = client_credentials
  • scope = read

Hit Send and we should get an access_token in the response. That’s the token we need to make requests to our hello app.
Lastly, create a new request in POSTMAN. This time it would be the previous GET request to our /hello endpoint but now we need to add the access token. For that, add a new Authorization Header with the value Bearer [ACCESS_TOKEN]



If everything went well we should get a successful response from our app.
Previous Post Next Post