Basic Authentication For Azure Functions (Open API) .Net 6

Introduction

In this article, we are going to learn how to set up the basic authentication for Azure Function APIs using Open API in Net 6.0. Its newly launched framework was officially released in November 2021 with LTS (Long Term Support). Here I've shared the link to install the SDK for .Net 6.0, and along with this you will need Visual Studio 2022 IDE to work with it.

Step 1

Create an Azure Function project in Visual Studio and make sure to go with the same process as shown in the image below.

Step 2

Add the name of the project in the next step and choose the path of the location to save this project.

Step 3

In this step, under the functions worker, we can see the latest .Net 6 (LTS) in the dropdown which we installed earlier. Under the function choose the HTTP Trigger with Open API, because we have to enable the basic authentication with Open API and don't need to do any other modifications on top of it. After this, a skeletal function project will be created where we can go with our authentication setup. 

Step 4 - Understanding the Open API specification

Assuming we notice the underlying format produced code, we will find new traits beginning with OpenApi once again our Function. These attributes over the Method control what gets created as a feature of the OpenAPI Document Specification. Below is the reference for the attributes.

  • OpenApiOperation - This guides to "Operation Object" from the OpenAPI Specification.
  • OpenApiResponseWithBody - This guides to "Response Object" from the OpenAPI Specification.
  • OpenApiParameter - This relates to "Parameter Object" from the OpenAPI Specification.
  • OpenApiSecurity - This relates to the "Security Scheme Object" from the OpenAPI Specification.

Infrequently, we will make works that would pass boundaries in the Query line of the Function Url.

[OpenApiOperation(operationId: "Run", tags: new[] { "http" }, Summary = "Basic authentication token flow via header", Description = "This shows the basic authentication token flow via header", Visibility = OpenApiVisibilityType.Important)]
[OpenApiSecurity("basic_auth", SecuritySchemeType.Http, Scheme = OpenApiSecuritySchemeType.Basic)]
[OpenApiParameter(name: "name", In = ParameterLocation.Query, Required = true, Type = typeof(string), Description = "The **Name** parameter")]
[OpenApiResponseWithBody(statusCode: HttpStatusCode.OK, contentType: "text/plain", bodyType: typeof(string), Description = "The OK response")]

Step 5 - Basic Auth Setup

These authentication steps are not part of the initial setup; we need to change the open API security property values of the attributes. Here the type defines the HTTP as it is treated as the Trigger APIs, and the scheme is Basic for Authentication.

  • TypeSecuritySchemeType.Http
  • SchemeOpenApiSecuritySchemeType.Basic
[OpenApiSecurity("basic_auth", SecuritySchemeType.Http, Scheme = OpenApiSecuritySchemeType.Basic)]

Step 6 - ValidateToken Method

In this method, we extracted the request header from the function API and validated the user credentials to pass. Here I've shared the steps that we followed to validate the token:

Note: I have used static username and password 

username: "Jay"

password: "12345"

  • Checking the header
  • Extracting the credentials & removing the "Basic" substring
  • Decode the base64 string
  • Split the username: password
  • Extracting the individual username and password
  • Validating the credentials.
private bool ValidateToken(string header) {
    //Checking the header
    if (!string.IsNullOrEmpty(header) && header.StartsWith("Basic")) {
        //Extracting credentials
        // Removing "Basic " Substring
        string encodedUsernamePassword = header.Substring("Basic ".Length).Trim();
        //Decoding Base64
        Encoding encoding = Encoding.GetEncoding("iso-8859-1");
        string usernamePassword = encoding.GetString(Convert.FromBase64String(encodedUsernamePassword));
        //Splitting Username:Password
        int seperatorIndex = usernamePassword.IndexOf(':');
        // Extracting the individual username and password
        var username = usernamePassword.Substring(0, seperatorIndex);
        var password = usernamePassword.Substring(seperatorIndex + 1);
        //Validating the credentials 
        if (username is "Jay" && password is "12345") return true;
        else return false;
    } else {
        return false;
    }
}

Step 7

Line 10 - extract the header from the HTTP request

Line 11 - pass the header parameter to validatetoken method for further validation and based on a response add a valid response as okobjectresult or make it the unauthorized response.

[FunctionName("Function1")]
[OpenApiOperation(operationId: "Run", tags: new [] {
    "http"
}, Summary = "Basic authentication token flow via header", Description = "This shows the basic authentication token flow via header", Visibility = OpenApiVisibilityType.Important)]
[OpenApiSecurity("basic_auth", SecuritySchemeType.Http, Scheme = OpenApiSecuritySchemeType.Basic)]
[OpenApiParameter(name: "name", In = ParameterLocation.Query, Required = true, Type = typeof(string), Description = "The **Name** parameter")]
[OpenApiResponseWithBody(statusCode: HttpStatusCode.OK, contentType: "text/plain", bodyType: typeof(string), Description = "The OK response")]
public async Task < IActionResult > Run(
    [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req) {
    //Getting the Header - extracting from the request
    var headers = req.Headers["Authorization"];
    if (ValidateToken(headers)) {
        _logger.LogInformation("C# HTTP trigger function processed a request.");
        string name = req.Query["name"];
        string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
        dynamic data = JsonConvert.DeserializeObject(requestBody);
        name = name ?? data?.name;
        string responseMessage = string.IsNullOrEmpty(name) ? "This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response." : $ "Hello, {name}. This HTTP triggered function executed successfully.";
        return new OkObjectResult(responseMessage);
    } else {
        return new UnauthorizedResult();
    }
}

Final Code

using System;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Attributes;
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Enums;
using Microsoft.Extensions.Logging;
using Microsoft.OpenApi.Models;
using Newtonsoft.Json;
namespace BasicAuth_AzureFunction_API {
    public class Function1 {
        private readonly ILogger < Function1 > _logger;
        public Function1(ILogger < Function1 > log) {
                _logger = log;
            }
            [FunctionName("Function1")]
            [OpenApiOperation(operationId: "Run", tags: new [] {
                "http"
            }, Summary = "Basic authentication token flow via header", Description = "This shows the basic authentication token flow via header", Visibility = OpenApiVisibilityType.Important)]
            [OpenApiSecurity("basic_auth", SecuritySchemeType.Http, Scheme = OpenApiSecuritySchemeType.Basic)]
            [OpenApiParameter(name: "name", In = ParameterLocation.Query, Required = true, Type = typeof(string), Description = "The **Name** parameter")]
            [OpenApiResponseWithBody(statusCode: HttpStatusCode.OK, contentType: "text/plain", bodyType: typeof(string), Description = "The OK response")]
        public async Task < IActionResult > Run(
            [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req) {
            //Getting the Header - extracting from the request
            var headers = req.Headers["Authorization"];
            if (ValidateToken(headers)) {
                _logger.LogInformation("C# HTTP trigger function processed a request.");
                string name = req.Query["name"];
                string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
                dynamic data = JsonConvert.DeserializeObject(requestBody);
                name = name ?? data?.name;
                string responseMessage = string.IsNullOrEmpty(name) ? "This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response." : $ "Hello, {name}. This HTTP triggered function executed successfully.";
                return new OkObjectResult(responseMessage);
            } else {
                return new UnauthorizedResult();
            }
        }
        private bool ValidateToken(string header) {
            //Checking the header
            if (!string.IsNullOrEmpty(header) && header.StartsWith("Basic")) {
                //Extracting credentials
                // Removing "Basic " Substring
                string encodedUsernamePassword = header.Substring("Basic ".Length).Trim();
                //Decoding Base64
                Encoding encoding = Encoding.GetEncoding("iso-8859-1");
                string usernamePassword = encoding.GetString(Convert.FromBase64String(encodedUsernamePassword));
                //Splitting Username:Password
                int seperatorIndex = usernamePassword.IndexOf(':');
                // Extracting the individual username and password
                var username = usernamePassword.Substring(0, seperatorIndex);
                var password = usernamePassword.Substring(seperatorIndex + 1);
                //Validating the credentials 
                if (username is "Jay" && password is "12345") return true;
                else return false;
            } else {
                return false;
            }
        }
    }
}

Step 8

Run the app to see the terminal open like below.

Step 9

Copy the above URL and open it in the browser to see the Swagger UI like below.

To authenticate your endpoint, you should enter the Username and Password, added to the Authorization header.

The result screen shows the request header of Authorization with the base64 encoded value.

In this article, we learned how can set up basic authentication for Azure function HTTP trigger API via Swagger and Run and test it with Postman. If you want to clone the project, click here.

I hope this article helps you. Keep learning!