Preserve Authorization Header in WSO2 API Manager

Greetings Everyone!!! 👋

In this medium, I will be walking-through a solution to preserve and send the Authorization Header to the Backend service at the (per) API level.

APIs that are published through the WSO2 API Manager is protected by either OAuth2, Basic, or API Key tokens. As out-of-the-box, the API Manager server removes the incoming Authorization Header during the token validation process, so that the Backend services will never know the actual Access Token used to invoke the API in the API Manager.

The API Manager has a global configuration to enable and disable the removal of the Authorization Header. The configuration can be found under the api-manager.xml of the API Manager server.

<RemoveOAuthHeadersFromOutMessage>true</RemoveOAuthHeadersFromOutMessage>

And the respective TOML configuration will be as following

[apim.oauth_config]
enable_outbound_auth_header = false

But, let’s say, we have a requirement, where we only need to pass the Authorization Header presented for a specific API and not for others. In such scenarios, as out-of-the-box, there is no direct solution to achieve this requirement. So, let’s see how we can achieve this requirement with minimal customizations.

To make it easy, I have already developed a custom handler to extract and preserve the Authorization header in the message context. Given below is the custom handler implementation to preserve the Authorization header in the message context and then to pass it to the Backend service with the help of a mediation sequence.

Let’s get more understanding on how they work…

✋ How does it work?

The custom handler is implemented to engage and extract the Authorization header during an API invocation through the WSO2 API Manager Gateway. The handler extracts the Authorization header from the Transport Headers and saves it to the Message Context with a custom Key-Value pair.

Then, a global-in-mediation-sequence is added to the Gateway node, to check whether the custom Key-Value pair exists in the context. If exists, the value is retrieved from the context and set back as an Authorization header, and sent to the Backend service.

You can find a sample global-in mediation sequence under the example directory of the above-shared repository [Global Sequence]. 👌

✋ Configure API Manager

Let’s go through how to configure the WSO2 API Manager to engage this handler and perform the trick.

First, clone the shared repository, and build the project using the following command

The repository contains the source and dependencies supported to WSO2 API Manager v3.1.0

mvn clean package

Once, the build is done successfully, copy the built JAR artifact from the <project>/target directory and place it inside <apim>/repository/components/lib directory.

Next, we have to configure the velocity_template.xml of the API Manager to engage the handler when the API is published to the Gateway nodes. To do so, we need to alter the existing <apim>/repository/resources/api_templates/velocity_template.xml with the following segment.

...
<handlers xmlns="http://ws.apache.org/ns/synapse">
#foreach($handler in $handlers)
#if($handler.className == 'org.wso2.carbon.apimgt.gateway.handlers.security.APIAuthenticationHandler')
#if($apiObj.additionalProperties.get('PreserveAuthHeader') == true)
<handler class="com.sample.handlers.PreserveAuthHeaderHandler">
#if($handler.hasProperties())
#set ($tempMap = $handler.getProperties() )
#foreach($property in $tempMap.entrySet())
#if($property.key == 'AuthorizationHeader')
<property name="$!property.key" value="$!property.value" />
#end
#end
#end
</handler>
#end
#end
...

The above-segment introduces a condition to check whether an API Custom Property has been introduced with the name of PreserveAuthHeader. If yes, then the custom handler will be engaged and listed under the handlers section along with the default shipped handlers.

Next, we have to add a global-in mediation sequence to read the custom key-value pair property from the context and to set the Authorization header back. Given below is a sample global-in mediation sequence and you can find the exact sequence inside the example directory of the shared repository.

<sequence xmlns="http://ws.apache.org/ns/synapse" name="WSO2AM--Ext--In">
<!-- a custom log to print the header content -->
<log level="custom">
<property name="Extracted Auth Header"
expression="get-property('PRESERVE_AUTH_HEADER_HANDLER_TOKEN')" />
</log>
<!-- setting back the Auth header if property exists-->
<filter
xpath="get-property('PRESERVE_AUTH_HEADER_HANDLER_TOKEN')">
<property name="Authorization" scope="transport" expression="get-property('PRESERVE_AUTH_HEADER_HANDLER_TOKEN')" />
</filter>
</sequence>

Once the configurations are done, start the API Manager server and perform the following

  • Log-in to the Publisher portal
  • Create a new API or edit an existing API that needs to pass the Authorization header to the Backend
  • Navigate to the Properties menu of the respective API and add the following custom property
    PreserveAuthHeader : true
  • And save the API

With the above-made configurations, now we will be able to see that our custom handler getting engaged with the respective API.

We can verify this by navigating to the <apim>/repository/deployment/server/syanpse-configs/default/api directory and opening up the respective API Synapse artifact. There, under the handlers section, our custom PreserveAuthHandler will be engaged prior to the default APIAuthenticationHandler.

And we are DONE!!! 🎉 🎊 🎉

We have now successfully configured the API Manager server to preserve and send the Authorization header to the Backend service (per) API level.

Happy Stacking!!! 😎

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Athiththan Kathirgamasegaran

Athiththan Kathirgamasegaran

@athiththan11 | GH:athiththan11 | Site Reliability Engineer@WSO2