2

I'm using a mobile app and am receiving an Unauthorized response when attempting to post to an Azure Function and providing a function key.

Error:

StatusCode: 401, ReasonPhrase: 'Unauthorized'

Code:

let postToAsync (baseAddress:string) (resource:string) (payload:Object) =

async {

    let tokenSource = new CancellationTokenSource(TimeSpan(0,0,30));
    let token = tokenSource.Token;
    
    try
        let tokens      = resource.Split("?code=")
        let functionKey = tokens.[1]

        use client = httpClient baseAddress
        client.DefaultRequestHeaders.Add("x-functions-key", functionKey)
        client.DefaultRequestHeaders.Accept.Add(MediaTypeWithQualityHeaderValue("application/json"))

        let  json     = JsonConvert.SerializeObject(payload)
        let  content  = new StringContent(json, Encoding.UTF8, "application/json")
        let! response = client.PostAsync(resource.Replace($"?code={functionKey}",""), content, token) |> Async.AwaitTask

        Debug.WriteLine $"\n\n{baseAddress}{resource}\nSuccess: {response.IsSuccessStatusCode}\n\n" 

        return response

    with ex -> ...
} |> Async.StartAsTask

Note:

My Azure Function's AuthorizationLevel is set to Function.

I can call the function successfully when I publish it manually from Visual Studio. However, when I deploy the function using Pulumi, I receive an Unauthorized response. I believe this is because Pulumi constrains me to add access policies for each Function App.

Versioning:

<TargetFramework>net6.0</TargetFramework>
<AzureFunctionsVersion>v4</AzureFunctionsVersion>

enter image description here

oauth2/v2.0:

I think the following link provides a clue to why I'm observing the issue. However, I still don't know how to resolve it.

Connectivity

I launched Log Stream and observed that the URL is correct:

enter image description here

Access Control:

Please note that the difference between the Function App that I created without using Pulumi, which lets me post successfully, versus the Function App that was generated using Pulumi, is an Access Policy per Function App with Pulumi.

public static class AccessPolicies
{
    public static void Build(string policyName, string functionName, Dictionary<string, CustomResource> registry)
    {
        var resourceGroup = registry[nameof(ResourceGroup)] as ResourceGroup;
        var keyVault      = registry[nameof(KeyVault)]      as KeyVault;
        var functionApp   = registry[functionName]   as FunctionApp;

        var result = new AccessPolicy(policyName, new AccessPolicyArgs {

            KeyVaultId = keyVault.Id,
            TenantId   = TenantId.Value,
            ObjectId   = functionApp.Identity.Apply(v => v.PrincipalId ?? "11111111-1111-1111-1111-111111111111"),
            KeyPermissions    = new[] { "Get", },
            SecretPermissions = new[] { "Get", }, 
        });

        registry.Add($"{policyName}-{functionName}", result);
    }
}

}

enter image description here

Scott Nimrod
  • 11,206
  • 11
  • 54
  • 118
  • Could you include how you generated the **bearer** token with what scope? Have you added any **[identity provider](https://i.imgur.com/J19dqb8.png)** to your function app? – Sridevi Jan 24 '23 at 09:16
  • @Sridevi - I updated my post to include the bearer token implementation. Please note that this is the same implementation that I use for requests to Azure to update Azure Function keys. I don't think I added an Identity Provider to my function app. – Scott Nimrod Jan 24 '23 at 09:51
  • I think you are using `https://management.azure.com/.default` as scope. Am I right? – Sridevi Jan 24 '23 at 09:55
  • Yes for the bearer token. – Scott Nimrod Jan 24 '23 at 10:13
  • @Sridevi - I updated my post with Log Stream that shows confirmation on confirmed routing to function. – Scott Nimrod Jan 27 '23 at 14:28
  • Setting the function's AuthorizationLevel to anonymous is a workaround. – Scott Nimrod Jan 27 '23 at 15:18
  • Do you have a storage account attached to your function app? Also, do you see keys in the portal blade or when trying to run from the portal? – PramodValavala Apr 10 '23 at 20:09

1 Answers1

2

I tried to reproduce the same in my environment via Postman and got below results:

I have one function app with http function named srifunction like below:

enter image description here

I generated one bearer token with same scope as you like below:

POST https://login.microsoftonline.com/<tenantID>/oauth2/v2.0/token
grant_type:client_credentials
client_id: <appID>
client_secret: <secret_value>
scope: https://management.azure.com/.default

Response:

enter image description here

When I used the above token to call function, I got 401 Unauthorized error same as you like below:

POST https://<funcappName>.azurewebsites.net/api/<function_name>
Authorization: Bearer <token>

enter image description here

If you pass function key in token value, you will still get 401 Unauthorized error like below:

POST https://<funcappName>.azurewebsites.net/api/<function_name>
Authorization: Bearer <function key>

enter image description here

To call function using function key, you need to include key value in x-functions-key header instead of Bearer token.

When I included the above header, I am able to call the function successfully like below:

POST https://<funcappName>.azurewebsites.net/api/<function_name>
x-functions-key: <function key>

enter image description here

Sridevi
  • 10,599
  • 1
  • 4
  • 17
  • I'm getting a 404 'Not found'. I verified that the URL in Azure poral is identical to URL in my program. Here's the example URL: https://myFunctionApp.azurewebsites.net/api/ServiceKeysFn?code=some_key – Scott Nimrod Jan 24 '23 at 14:44
  • Don't include **code** in the URL. Your URL should be like this `https://myfunctionapp.azurewebsites.net/api/ServiceKeysFn` – Sridevi Jan 24 '23 at 14:49
  • I removed the function key suffix from the URL but still receive the same error. I removed the key via the following: client.PostAsync(resource.Replace($"?code={functionKey}","") Please note that Pulumi requires me to create Access Policies for each Function App. I updated my post to reflect the Access Control page for the Function App. – Scott Nimrod Jan 24 '23 at 15:01
  • Instead of adding **x-functions-key** header in Authorization, can you try like this `client.defaultrequestheaders.Add("x-functions-key", "functionkeyvalue")` – Sridevi Jan 24 '23 at 15:06
  • I updated my post to reflect the example provided. Unfortunately, I get the same 'Not found' error. The URL still matches the 'Get Url' value in Azure. Would access policies that I depicted in my post impact this? – Scott Nimrod Jan 24 '23 at 15:18
  • 1
    Not sure what might be the problem but ideally including `x-functions-key` header should give you results while calling a function with the function key. Maybe there are additional changes required on the Pulumi side as access policies are added. – Sridevi Jan 24 '23 at 15:27
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/251366/discussion-between-sridevi-and-scott-nimrod). – Sridevi Jan 24 '23 at 15:36