OAuth Proxy for Azure API Management
On this page
The OAuth Proxy is an extension to your API gateway that you need when your single page applications (SPAs) call OAuth-secured APIs using the Token Handler pattern. The SPA sends an encrypted proxy cookie that transports an access token. The OAuth Proxy plugin decrypts the cookie to extract the access token.
When the OAuth Proxy work completes, Azure API Management routes the request to the target API, which uses the access token to implement its OAuth security.
Download the OAuth Proxy
You get the OAuth Proxy by downloading the latest ZIP file version from the Curity Developer Portal, with a filename of the following form. This zip file contains a Java 17 Azure function, an Azure API Management policy fragment and a README file with detailed instructions.
curity-token-handler-proxy-azure-<version>.zip
Prepare Decryption
You need an asymmetric keypair as part of your overall token handler deployment. To create one, follow the instructions in the Configure Cryptographic Keys
section of the Create a Token Handler tutorial. This results in a PKCS#8 file with an encrypted private key, and also a private key password.
Deploy the OAuth Proxy
You must deploy the OAuth Proxy to a gateway that runs in your SPA's backend for frontend domain. If a deployment uses the following URLs, the OAuth Proxy executes in a gateway at https://bff.product.example
:
- SPA Web Origin:
https://www.product.example
- Backend for Frontend Base URL:
https://bff.product.example
- Target API Base URL:
https://api.example.com
To deploy the OAuth Proxy, first define settings in the configure.bicepparam
file. You must configure the cookie decryption key for the OAuth Proxy, using the content of the PKCS#8 file, and the PKCS#8 file's password. An example configuration is shown here:
using './lib/configure.bicep'param apiManagementServiceName = 'myServiceName'param functionAppName = 'myFunctionApp'param restrictFunctionAppToApiManagementIp = trueparam cookieKey = loadTextContent('key.pem')param cookieKeyPassword = 'myS3cret'
If the OAuth Agent uses a different prefix for cookie names than the default value th-
, you should also configure a cookiePrefix
that matches the value from the OAuth Agent. You can find further details on parameters in the lib/configure.bicep
file. Also, locate the policy fragment file at lib/policy-fragment.xml
.
Next, apply the configuration to a resource group for services in the gateway domain. You can run the following command using the Azure CLI:
az loginaz deployment group create --resource-group <name-of-resource-group> \--template-file lib/configure.bicep \--parameters configure.bicepparam \--mode incremental
Finally, upload the Azure function using the following command:
cd bin/funcfunc azure functionapp publish <functionAppName>
Configure API Routes
You must configure the OAuth Proxy for all API routes that the SPA calls. Also, add a route such as /oauthuserinfo
if the SPA calls the authorization server's OpenID Connect userinfo endpoint.
In Azure API Management you configure API routes using policies. You must enable CORS to instruct the browser to allow requests with cookies from the SPA's web origin, and deny access to untrusted origins. Enable settings such as these, so that your SPA can send cross-origin JSON requests:
<policies><inbound><cors allow-credentials="true"><allowed-origins><origin>https://example.com</origin></allowed-origins><allowed-methods preflight-result-max-age="86400"><method>*</method></allowed-methods><allowed-headers><header>*</header></allowed-headers><expose-headers><header>*</header></expose-headers></cors></inbound></policies>
You must then configure the route to use the OAuth Proxy, so that the main cookie processing logic is applied when Azure API Management receives requests from your SPA:
<policies><inbound><cors>...</cors><include-fragment fragment-id="CURITY-TOKEN-HANDLER"/></inbound>...</policies>
OAuth Proxy Output
At runtime, the OAuth Proxy processes cookies in incoming requests from SPAs and returns a result. On success, the policy fragment from the download applies the result to the HTTP request, setting the access token in the HTTP authorization header. You can then route the access token to the target API, which uses it for authorization.
<set-header name="Authorization" exists-action="override"><value>@($"Bearer {context.Variables["thProxyAccessToken"]}")</value></set-header>
If the OAuth Proxy experiences an invalid cookie error, it returns a 400 response to the gateway, or throws an exception in the event of an unexpected error. The policy fragment transforms error results and returns responses with an HTTP 401 status code for invalid cookie errors. If required, you can customize the gateway error responses.
<choose><when condition="@(((IResponse)context.Variables["thProxyCookieResponse"]).StatusCode == 400)"><return-response><set-status code="401" reason="Unauthorized" /></return-response></when><when condition="@(((IResponse)context.Variables["thProxyCookieResponse"]).StatusCode != 200)"><return-response><set-status code="500" reason="Internal error" /></return-response></when></choose>
Conclusion
The OAuth Proxy is part of your API gateway. It enables your SPAs to use the correct browser security and also make direct calls to API URLs. The OAuth Proxy plugin deals with the cookie complexity so that you do not need to implement it in your API code.
Join our Newsletter
Get the latest on identity management, API Security and authentication straight to your inbox.
Start Free Trial
Try the Curity Identity Server for Free. Get up and running in 10 minutes.
Start Free Trial