Using Okta Authentication with Azure Functions

Cloud Architect
4 min readJul 2, 2022

--

Update 10th April 2023 : I do not recommend this article anymore. Check out my configuration based article here: OpenID Connect with Okta and Azure Functions | by Cloud Architect | Apr, 2023 | Medium

I will leave this article as is since it may help with some scenarios where coding the authentication may be useful.

+++++++++++++++++++++++++++++++++++++++++++++++

It is fairly straightforward to get Azure Functions working with Okta authentication, however the blog post on the Okta site doesn’t quite work out of the box.

Details of the Okta Client Credential Flow are here: Implement authorization by grant type | Okta Developer

Please note this is a simple get started article. Advanced configuration that you will need for Production level security is not covered.

Step 1: Build & Deploy the Azure Function

The first thing we want to do is build a DotNet 6 HTTP triggered Function and remove all Azure authentication. This is because we want to delegate the authorization to Okta:

Step 2: Setup in Okta

Go to Applications and choose ‘Create App Integration’. Then choose the API Services’

Give the App a name, and in return Okta will give you your Client ID and Client Secret

Then goto Security and API and click on the default authorization server:

Finally add a claim called api_scope to this:

Step 3: Update your Trigger Code:

I adapted the Okta articles code somewhat. This function will return a JSON array on successful Okta authentication.

using System;using System.Collections.Generic;using System.Net.Http;using System.Threading.Tasks;using Microsoft.AspNetCore.Mvc;using Microsoft.Azure.WebJobs;using Microsoft.Azure.WebJobs.Extensions.Http;using Microsoft.AspNetCore.Http;using Microsoft.Extensions.Logging;using Newtonsoft.Json;namespace acme.search{public static class PersonSearch{[FunctionName("PersonSearch")]public static async Task<IActionResult> Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)] HttpRequest req,ILogger log){log.LogInformation("C# HTTP trigger function processed a request.");//Pull out the header values passed into the requestvar headers = req.Headers;if(!headers.TryGetValue("token", out var token)){log.LogInformation("BAD TOKEN");return new BadRequestResult();}if(!headers.TryGetValue("client_id", out var client_id)){log.LogInformation("BAD CLIENTID");return new BadRequestResult();}if(!headers.TryGetValue("client_secret", out var client_secret)){log.LogInformation("BAD CLIENT SECRET");return new BadRequestResult();}var accessToken = token.ToString();var clientId = client_id.ToString();var clientSecret = client_secret.ToString();//Call the Okta introspection API to validate the token.var baseUrl = "https://dev-12345678.okta.com/oauth2/default/v1/introspect";var content = new FormUrlEncodedContent(new[]{new KeyValuePair<string, string>("token", accessToken),new KeyValuePair<string, string>("token_type_hint", "access_token"),new KeyValuePair<string, string>("client_id", clientId),new KeyValuePair<string, string>("client_secret", clientSecret)});var _httpClient = new HttpClient();var response = await _httpClient.PostAsync(baseUrl, content);var result = await response.Content.ReadAsStringAsync();log.LogInformation("C# HTTP trigger function processed an external API call to Okta.");if(!response.IsSuccessStatusCode){log.LogInformation("Web Service Call Unsuccessful.");return new UnauthorizedResult();}// This is a not very profesional. Ideally we would parse for a positive result.bool isResultFalse = String.Equals(result, "{\"active\":false}", StringComparison.OrdinalIgnoreCase);if( isResultFalse ) {log.LogInformation("Okta Introspection indicates token is not active");return new UnauthorizedResult();}// Build the responsePersonSearchResult result1 = new PersonSearchResult();result1.id = "VBNN-09123445";result1.probability = 100;PersonSearchResult result2 = new PersonSearchResult();result2.id = "VBGG-091236742";result2.probability = 85;List<PersonSearchResult> personList = new List<PersonSearchResult>();personList.Add(result1);personList.Add(result2);String results = JsonConvert.SerializeObject(personList);return new OkObjectResult(results);}}}

Step 4: Try it out:

First, use Postman to call Okta for the authorization token. Make sure you have a header request with the content type defined below as well as setting the Params:

With the access token returned by Okta, you can now call the Function with the combination of client_id and token:

Note: The screenshot above includes the secret. You should not actually pass this.

--

--

No responses yet