Efficient OAuth Authorisation Management in Azure API Management
Justin Yoo
Posted on June 8, 2022
While developing an application, the majority of the time, you use API calls to send and receive messages. Therefore, you should follow an authentication and authorisation process to use the API unless it's the public API. Those authentication/authorisation process uses either 1) an auth key or 2) an access token through an OAuth process.
Using the auth key approach, you can store it in a safe place like the Azure Key Vault service and fetch the key. It's a relatively simple process. However, if you need to use the OAuth process, it gets complicated with the following authorisation process. Here's the conceptual OAuth process.
Request an authorisation code
Receive the authorisation code
Request an access token by providing the authorisation code
Receive the access token and a refresh token
Call API request by providing the access token
Receive the API response
Request a new access token by providing the refresh token once the existing access token expires
Receive the new access token and a new refresh token
Call API request by providing the new access token
Receive the API response
If you want to know more about the OAuth auth process, please refer to this doc.
Therefore, developers should implement those processes as a part of the application development. You might be lucky if the service you want to use offers an SDK. If not, you should do it all by yourself, which is very cumbersome. What if someone does all the tedious steps for you? Let's say, within the secure place, someone does all the auth process on your behalf and simply returns the access token. If this happens, your application development velocity will increase significantly. Azure API Management (APIM) has recently released a preview feature called "Authorisations" that does the OAuth process on your behalf. Throughout this post, I'm going to discuss this feature using a Blazor Web Assembly (WASM) app hosted on Azure Static Web Apps (SWA).
You can download the sample app code from this GitHub repository:
There are two apps in the repository – one based on Blazor WASM and the other based on React. I'm going to use the Blazor WASM sample here. If you're interested in the React app sample, please visit my colleague, Aaron Powell's blog post.
Blazor Web Assembly App
Please refer to the Blazor Tutorial document for the Blazor WASM in general. Instead, I'm going to take a look at a component taking care of the OAuth authorisation and access token. This component takes the user inputs, stores them as a .csv file format and uploads it to DropBox. The Razor code below is nothing special but contains a form for user inputs. When a user completes the form and clicks the "Submit" button, the OnFormSubmittedAsync event is triggered (line #3).
The following @code { ... } block is the C# code interacting with the Razor component. For brevity, I've left two methods. The first method is the event handler, OnFormSubmittedAsync triggered by the "Submit" button. Then, inside the event handler, it calls the SaveToDropboxAsync method, which takes care of all the things, including access token fetch and DropBox save.
In the SaveToDropboxAsync method, it firstly gets the environment variable of APIM_Endpoint (line #4). Blazor WASM stores all the environment variables in the appsettings.json file, which I will discuss later. By calling the APIM endpoint from appsettings.json, the app gets the access token to DropBox (line #7), and the DropBox client instance uploads the data.
privateasyncTaskSaveToDropboxAsync(){// Gets the APIM endpoint from appsettings.jsonvarrequestUrl=Configuration.GetValue<string>("APIM_Endpoint");// Gets the auth token from APIMvartoken=awaitHttp.GetStringAsync(requestUrl).ConfigureAwait(false);// Builds contents.varpath=$"/submissions/{DateTimeOffset.UtcNow.ToString("yyyyMMddHHmmss")}.csv";varcontents=$"{userInfo.FirstName},{userInfo.LastName},{userInfo.Email},{userInfo.Phone}";varbytes=UTF8Encoding.UTF8.GetBytes(contents);// Uploads the contents.varresult=default(FileMetadata);using(vardropbox=newDropboxClient(token))using(varstream=newMemoryStream(bytes)){result=awaitdropbox.Files.UploadAsync(path,WriteMode.Overwrite.Instance,body:stream).ConfigureAwait(false);}...}}
Let's take a look at the appsettings.json file that contains the APIM_Endpoint environment variable. The value is the APIM endpoint to get the DropBox access token.
Then, open your web browser and enter the URL of https://localhost:5001, and you will see the page like:
Fill out the form and click the "Submit" button, and the app will save the form details to DropBox. Then, if you open the Developer Tools of your web browser, you can see how the Blazor WASM app calls the APIM endpoint.
And the API call returns the access token to DropBox.
With this access token, you can create and store a file. Here's the result:
There are no codes for OAuth authorisation to DropBox, as you can recall. Instead, it starts from the API call that directly gets the access token. So how can the code remove all the preflight codes before getting the access token? This is the new APIM authorisation feature being referred to in this post. In short, the APIM instance internally performs all the OAuth related processes on behalf of the Blazor WASM app and simply returns the access token.
Azure API Management Instance
Let's dig into the new APIM feature. You can click the button below to provision all the resources onto Azure at once.
Alternatively, you can run the bicep files declared below. Let's take a further look at the bicep files. First, declare the APIM instance. You might notice that it enables the Managed Identity feature (line #13-15), which I'll discuss later in this post. For convenience, name the APIM instance of token-store-demo-apim and set the location to West Central US. The resource group for this provision is set to rg-token-store-demo.
The next step is the CORS policy because Azure SWA directly calls the APIM endpoint. Within the inbound node, add the cors node, add the allowed-origins node under it, and add the origin node with its value of *. Make sure that it's just for the demo purpose. You should add the specific URL for better security if it goes live.
After declaring the APIM instance, define an API and its operation. The API's serviceUrl is set to the base URL of the DropBox API, and the operation endpoint is set to /token that returns the access token. Therefore, the entire APIM endpoint might look like https://token-store-demo-apim.azure-api.net/dropbox-demo/token.
The following XML document of the operation policy explains the core idea of this APIM's new feature. Add the get-authorization-context node under inbound. It has the following attributes.
provider-id: dropbox-demo
authorization-id: auth
context-variable-name: auth-context
identity-type: managed
As you can see, the APIM instance has enabled the Managed Identity feature corresponding to identity-type. Both provider-id and authorisation-id will be used later. The context-variable-name attribute is set to auth-context. It's used in the return-response node that holds the access token value. Overall, this operation policy takes care of getting access token on behalf of the SWA app.
You've got the APIM instance defined. Now, you need the SWA app instance for the Blazor WASM app.
Azure Static Web Apps Instance
To host the Blazor WASM app, you need to provision an Azure SWA instance. Here's the bicep code for it. First, give the app name token-store-demo-blazor-swa and the location of Central US under the resource group of rg-token-store-demo.
Blazor WASM App Deployment to Azure Static Web Apps Instance
You've got the new ASWA instance. It's time to deploy the Blazor WASM app, which is located in the src/frontend/blazor directory. The first step should be adding the appsettings.json file that contains the APIM endpoint for the access token. The following commands are how to get the APIM's endpoint URL.
# Get APIM gateway URLrg_name=rg-token-store-demoapim_name=token-store-demo-apimgateway_url=$(azapimshow-g$rg_name-n$apim_name--query"gatewayUrl"-otsv)# Get APIM subscription keysubscription_id=$(azaccountshow--query"id"-otsv)apim_secret_uri=/subscriptions/$subscription_id/resourceGroups/$rg_name/providers/Microsoft.ApiManagement/service/$apim_name/subscriptions/master/listSecretsapi_version=2021-08-01subscription_key=$(azrest--methodpost--uri$apim_secret_uri\?api-version=$api_version|jq'.primaryKey'-r)# Build APIM endpointapim_endpoint=$gateway_url/dropbox-demo/token\?subscription-key=$subscription_key
The APIM's endpoint URL is finally landed in the apim_endpoint variable. Therefore, rename the appsettings.sample.json file under the src/frontend/blazor/wwwroot directory to appsettings.json and update the endpoint.
{"APIM_Endpoint":"<apim_endpoint>"}
Build and create the artifact of the Blazor WASM app.
Although everything has gone perfectly so far, you can see the error below after submitting the form:
It's because you haven't made consent to the DropBox app yet. The final step will be consent.
DropBox App Consent
Create a DropBox app by following this document, and you will get both App key and App secret.
You need both values for the consent within the APIM instance. Click the "Authorisations (preview)" at the blade.
There are no authorisation apps yet. Therefore, click the "Create" button.
You can recall how you set up the get-authorisation-context node for the operation policy. It's time to use them.
Enter dropbox-demo to the "Provider name" field.
Select DropBox from the "Identity provider" field.
Enter DropBox's app key value to the "Client id" field.
Enter DropBox's app secreet value to the "Client secret" field.
Enter files.metadata.write files.content.write files.content.read to the "Scopes" field.
Enther auth to the "Authorization name" field.
Click the "Create" button and get the redirection URL.
Add the redirection URL to the DropBox app.
Back to the APIM instance and log in to the DropBox app. Then, proceed the pop-up window by clicking the "Continue" and "Allow" and "Allow access" buttons consecutively.
Then, you will see the success message.
The DropBox app has now been authorised. But the APIM instance has not yet been authorised to access the DropBox app. Since the APIM instance has the Managed Identity feature enabled, let's use it. Choose "Managed identity" and click the "Add members" button.
Find the APIM instance and add it.
Now, both APIM and DropBox can communicate with each other.
Can you see the DropBox app authorised?
Let's test the endpoint whether it actually works or not. Follow the menu "APIs" ➡️ "dropbox-demo" ➡️ "gettoken" and click the "Send" button.
Then you will see the access token successfully issued.
Let's get back to the ASWA app and fill out the form. There is no error this time.
And the uploaded file appears on DropBox!
So far, we've discussed the new OAuth authorisation feature of Azure API Management. Ultimately, we need the access token through the OAuth process. APIM performs this process. Therefore, we can save a huge amount of time by not implementing this feature within our app. Since it's currently in preview, some features may be ready, but they will be continuously improved.
If you want to know more about this APIM OAuth authorisation management feature, please visit the document below: