The problem(s) with Azure Functions
Tags: azure, serverless, dotnet, programming
Published: 2022-08-16 19:43:00

I’m a curious person. Trying out new things makes me happy. I strongly believe in learning by doing. That’s the only way for me to make progress and learn new programming languages, technologies or frameworks. One might say I love to overengineer things ;). I've been working on [cl3rk.io](https://cl3rk.io) for a while and spend most of the time researching technologies and trying out new stuff. A few weeks ago I decided to take the project a bit more serious and am now working with warp speed on getting the first version out there.


Before that, I spend a ton of time testing [Azure Functions](https://azure.microsoft.com/en-us/services/functions/) and stumbled over a few ~~rocks~~ mountains 🗻.



![Azure Functions Mountain I stumbled over](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s7tmrelrheq1z6px9m4x.jpg)


I wrote already a couple of Azure Functions in the past to interact with Telegram bots for example and was always happy with them. So I immediately started my first PoC with C#. Here is why I ended up moving away from Azure Functions:

## 1. Authentication and Authorization

Functions can be triggered in multiple ways: HTTP, Queue, Db, Blob Storage Change and many more. More on this can be found [here](https://docs.microsoft.com/en-us/azure/azure-functions/functions-bindings-http-webhook). This was one of the major reasons why I thought Azure Functions are great. I mostly needed the HTTP and Queue trigger. With HTTP functions comes also the requirement for Authentication and Authorization. I'm using [Auth0](https://auth0.com) as an authentication provider. The implementation is usually straightforward. The frontend obtains an access token and the API validates the token and authenticates the request. OpenID connect is well documented and somewhat easy to use in asp.net core for example. Not with Azure Functions I googled for days, opened an [issue](https://github.com/Azure/azure-functions-host/issues/8536) and tried everything I could think of and came to the conclusion: Microsoft doesn’t provide you with proper SDKs to handle authentication adequately.

### Expected:

I add the `[Authorize]` attribute on an Azure Function and configure the validation in the startup method for example. This is the well-known way to use OpenIDConnect in asp.net core apps. The user context is then injected via `HttpRequest` and accessible when the code needs it:

```csharp
[Authorize]
[FunctionName("CreatePersonalTask")]
public static IActionResult Run(
    [HttpTrigger(AuthorizationLevel.Anonymous, "post")]
    HttpRequest req,
    [CosmosDB(
        "personal_tasks",
        "personal_tasks",
        Connection = "CosmosDBConnection")]
    out PersonalTask personalTask,
    ILogger log)
{
    log.LogInformation("Create Personal Task");
    personalTask = new PersonalTask
    {
        Id = Guid.NewGuid().ToString(),
        Name = "yolo",
        UserId = // get userid from HttpRequest
    };

    return new OkObjectResult(personalTask.Id);
}
```

### Reality:

* You can authenticate on a service level (Azure takes care of OpenID connect and validates the access token before the function is executed) BUT this only works when the function is deployed. Testing locally becomes difficult as the local runtime does not come with this authentication layer.

* The Azure Function docs do not show how to overcome this problem. I ended up creating a [Github issue](https://github.com/Azure/azure-functions-host/issues/8536) to understand if I'm the only guy with this problem or if it's just not well supported. Turns out the latter one is true😢

* There are [some libraries](https://github.com/fmichellonet/AzureFunctions.Extensions.OpenIDConnect) that workaround this problem BUT they are not well maintained and potentially [use preview code](https://github.com/Azure/azure-functions-host/issues/8536#issuecomment-1205682012) that might never make it to the new Out Of Process runtime.

* You can write the validation logic yourself and call custom code at the beginning of your function BUT who wants to maintain that?

```csharp
[FunctionName("CreatePersonalTask")]
public static IActionResult Run(
    [HttpTrigger(AuthorizationLevel.Anonymous, "post")]
    HttpRequest req,
    [CosmosDB(
        "personal_tasks",
        "personal_tasks",
        Connection = "CosmosDBConnection")]
    out PersonalTask personalTask,
    ILogger log)
{
    // validate the token in every function. This is messy if you have many functions

    log.LogInformation("Create Personal Task");
    personalTask = new PersonalTask
    {
        Id = Guid.NewGuid().ToString(),
        Name = "yolo",
        UserId = // get userid from HttpRequest
    };

    return new OkObjectResult(personalTask.Id);
}
```

Its a real bummer that authentication with JWT tokens does not work out of the box. This is a dealbreaker to me💁🏼‍♂️

## 2. CI/CD

I work as a DevOps guy so I strive to automate as much as I can to avoid errors and free up my time for development. The Github Action was working before I realized the authentication debacle. With the CD pipeline I quickly realized one flaw: whenever a new function version is deployed a [zip file is uploaded](https://docs.microsoft.com/en-us/azure/azure-functions/functions-how-to-github-actions) to the mandatory Storage Account on Azure. Soon I had a few dozens of zip files in the storage account and had no overview of what's deployed and what is not deployed. That's messy if you need to debug or roll back a version.

This is not a major problem but worth keeping in mind when using dotnet and Azure Functions.

## 3. In-process or Isolated process

If all of that was not enough Azure Functions can be written in two flavours: [in-Process](https://docs.microsoft.com/en-us/azure/azure-functions/functions-dotnet-class-library) or [isolated process](https://docs.microsoft.com/en-us/azure/azure-functions/dotnet-isolated-process-guide). Basically, this is how functions are hosted. More info on that can be found [here](https://docs.microsoft.com/en-us/azure/azure-functions/dotnet-isolated-process-guide#benefits-of-running-out-of-process). The in-process way has better binding support and a faster startup time. Isolated process hosting is newer and allows you to target a different dotnet version than the function runtime itself. It also has less dependency [collisions](https://bryanknox.github.io/2022/07/15/functionsskipcleanoutput-and-functionspreserveddependencies.html) as your app is separated from the function runtime. I decided to roll with in-process for my PoC because of the [awesome binding support](https://docs.microsoft.com/en-us/azure/azure-functions/functions-triggers-bindings?tabs=csharp). I wanted to use dotnet 7 when released but I feared that might only work when using isolated process Azure Functions (Unless Microsoft offers the in-process runtime with dotnet 7 too). Unfortunately, some code is different between in-process and out-of-process so one may not easily switch between the two hosting options.

## Conclusion:

Azure Functions are great if you have a small project that does not need authentication. Make sure to carefully decide between in-process and isolated process hosting. If you have a larger project you can check out [Azure Container Apps](https://azure.microsoft.com/en-us/services/container-apps/) as an alternative. That's what I'm using right now and I'm very impressed with it so far. I hope to share some details on how I'm doing that soon in another post.
All in all I can say that I learned a lot when working with Azure Functions and I'd love to use them in the future again. But only when I find a great use case without authentication ;)


## cl3rk

[cl3rk](https://cl3rk.io) is a new, innovative and easy-to-use document management app. We all know document management is a pain. Have you tried finding the documents you need for tax declaration? I struggle with that every year. cl3rk's goal is to take this pain away from every user with AI. Keeping the documents secure cl3rk aims to provide reasonable reminders on chores like renewing car insurance each user has to stay on top of. This way nothing will get forgotten.


Let me know what you think of Azure Functions and cl3rk. If you want you can signup the email list (no spam - I promise) or reach out at klaus@cl3rk.io