Web APIs have experienced an exponential increase in popularity and usage in the past few years. APIs exist at the intersection of business, products, and technologies and have transformed the way businesses interact with each other and the way they provide value to their customers. Web APIs allow businesses to access 3rd-party data, allow for cross-platform communication and seamless integration anywhere and anytime it's required, offering unmatched data processing efficiencies and cost savings.
Azure API Management
API Management Authorizations
Authorization scenarios
Today, we will talk about an unattended scenario with Azure Functions. With our Static Web App Scenario, users are able to post a GitHub issue to a repository. We now want to implement a timer triggered Azure Function that will GET the count of GitHub issues and POST about it in a Microsoft Teams channel. This will create a reminder notification in Teams about how many issues are still open:
Prerequisites
- A running Azure API Management service instance. Check out our Quickstart: Create a new Azure API Management service instance by using the Azure portal
- Managed system-assigned identity must be enabled for the API Management instance.
- Visual Studio 2022 (Make sure you select the Azure development workload during installation) or Visual Studio Code
STEP 1 - Configure Authorizations in Azure API Management
For our scenario, we need two API Management Authorizations, one for the GitHub API and one for the Microsoft Graph API.
For the GitHub authorization, you can follow this tutorial to configure your authorization. Make sure you use the following configurations:
Settings
|
Value
|
Provider name
|
githubissue01
|
Identity provider
|
Select GitHub
|
Grant type
|
Select Authorization code
|
Client id
|
Create a new GitHub OAuth app or use existing one from Blog Post
|
Client secret
|
Paste the value from the GitHub OAuth app
|
Scope
|
repo
|
Authorization name
|
githubissue01
|
For the Microsoft Graph API authorization, you can follow this tutorial to configure your authorization. Make sure you use the following configurations:
Settings
|
Value
|
Provider name
|
channel-aad
|
Identity provider
|
Select Azure Active Directory
|
Grant type
|
Select Authorization code
|
Client id
|
Paste the value you copied earlier from the app registration - follow tutorial for setting this up
|
Client secret
|
Paste the value you copied earlier from the app registration
|
Resource URL
|
|
Scopes
|
Note: Leave this input empty since your scopes are defined in the app registration
|
Authorization name
|
channel-aad
|
STEP 2 - Add your GitHub API and configure a policy
Setting
|
Value
|
Display name
|
githubissue
|
Name
|
githubissue
|
Web service URL
|
|
API URL suffix
|
githubissue
|
Setting
|
Value
|
Display name
|
getissues
|
URL for GET
|
/repos/{github-alias}/{reponame}/issues
|
<policies>
<inbound>
<base />
<get-authorization-context provider-id="githubissue01" authorization-id="githubissue01" context-variable-name="auth-context" identity-type="managed" ignore-error="false" />
<set-header name="Authorization" exists-action="override">
<value>@("Bearer " + ((Authorization)context.Variables.GetValueOrDefault("auth-context"))?.AccessToken)</value>
</set-header>
<set-header name="User-Agent" exists-action="override">
<value>API Management</value>
</set-header>
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
</policies>
STEP 3 - Add your Microsoft Graph API and configure a policy
Setting
|
Value
|
Display name
|
TeamsChannelMessage
|
Name
|
TeamsChannelMessage
|
Web service URL
|
|
API URL suffix
|
TeamsChannelMessage
|
Setting
|
Value
|
Display name
|
postchannelmessage
|
URL for POST
|
/v1.0/teams/{team-id}/channels/{channel-id}/messages
|
Once you added the API, we can make use of the provider in the Inbound Processing Policy and apply the previously created Authorization. Add the following snippet to the inbound JWT policy:
<policies>
<inbound>
<base />
<get-authorization-context provider-id="channel-aad" authorization-id="channel-aad" context-variable-name="auth-context" identity-type="managed" ignore-error="false" />
<set-header name="authorization" exists-action="override">
<value>@("Bearer " + ((Authorization)context.Variables.GetValueOrDefault("auth-context"))?.AccessToken)</value>
</set-header>
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
</policies>
NOTE: For more information, check out the get-authorization-context policy references to learn more about how to use the policy.
STEP 4 - Test the APIs
- Select your API and the operation you added previously
- Go to the Test tab.
- Select Send.
STEP 5 - Building your timer triggered Azure Function
Next, we will build our timer triggered function in Azure Functions. For this, you can follow the Quickstart: Create your first C# function in Azure using Visual Studio and use the AuthorizationsDemoAzureFunction GitHub repo. We used the following configurations in Visual Studio:
Setting
|
Value
|
Project name
|
FunctionAppAPIMAuthTest
|
Solution name
|
FunctionAppAPIMAuthTest
|
Make sure to use Time trigger as the initial trigger for your Azure function.
In local.settings.json file, we will add the following code:
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "UseDevelopmentStorage=true",
"FUNCTIONS_WORKER_RUNTIME": "dotnet",
"CUSTOM_URL": "YOUR_CUSTOM_URL",
"SUBSCRIPTION_KEY": "YOUR_SUBCRIPTION_KEY",
"TEAMS_URL": "YOUR_TEAMS_URL"
}
}
In our FunctionAppAPIMAuthTest.cs file, we will add the following code:
using System;
using System.Net.Http;
using System.Net.Http.Formatting;
using System.Threading.Tasks;
using Microsoft.Azure.WebJobs;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json.Linq;
namespace FunctionAppAPIMAuthTest
{
public class Function1
{
private static HttpClient httpClient = new HttpClient();
[FunctionName("Function1")]
public async Task Run([TimerTrigger("*/1 * * * *")] TimerInfo myTimer, ILogger log)
{
log.LogInformation($"Timer trigger function started at: {DateTime.Now}");
//Define header
var subscriptionKey = System.Environment.GetEnvironmentVariable("SUBSCRIPTION_KEY", EnvironmentVariableTarget.Process);
httpClient.DefaultRequestHeaders.Accept.Clear();
httpClient.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", subscriptionKey);
//Define GET URL for GET issue count
var baseurl = System.Environment.GetEnvironmentVariable("CUSTOM_URL", EnvironmentVariableTarget.Process);
var addurl = "?state=open";
var _baseurl = baseurl + addurl;
log.LogInformation($"URL: {_baseurl}");
//GET call
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, _baseurl);
var response = await httpClient.SendAsync(request);
JArray arr = JArray.Parse(await response.Content.ReadAsStringAsync());
//Error handling
log.LogInformation($"You currently have {arr.Count} issues open.");
if (!response.IsSuccessStatusCode)
{
throw new Exception($"Call unsuccessful: {response.IsSuccessStatusCode}");
};
//Define POST URL to POST TeamsBody to Teams
var teamsurl = System.Environment.GetEnvironmentVariable("TEAMS_URL", EnvironmentVariableTarget.Process);
log.LogInformation($"URL: {teamsurl}");
// Create TeamsBody
var TeamsBody = new
{
body = new
{
content = $"You currently have {arr.Count} issues open."
}
};
log.LogInformation($"Body: {TeamsBody.body.content}");
//Define POST header
httpClient.DefaultRequestHeaders.Accept.Clear();
httpClient.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", subscriptionKey);
//POST call with TeamsBody content
HttpRequestMessage requestteams = new HttpRequestMessage(HttpMethod.Post, teamsurl);
requestteams.Content = new ObjectContent<object>(TeamsBody, new JsonMediaTypeFormatter());
var responseteams = await httpClient.SendAsync(requestteams);
log.LogInformation($"Response: {responseteams.IsSuccessStatusCode}");
//Error handeling
if (!responseteams.IsSuccessStatusCode)
{
throw new Exception($"Call unsuccessful: {responseteams.IsSuccessStatusCode}");
};
}
}
}
Note: Function1 referring to your function class file.
STEP 5 - Test Azure Function locally
Further Resources