Azure Function works with Entra ID custom authentication extension when created manually in portal, but not after deploying via Visual Studio

Zeeshan Ahmad 0 Reputation points
2025-07-01T11:16:20.65+00:00

I have already asked this on Stackoverflow you can see imanges as well on stackoverflow
https://stackoverflow.com/questions/79683577/azure-function-works-with-entra-id-custom-authentication-extension-when-created

Case 1

Here is public endpoint which is working fine with entra
https://azuretestfunction20250627020054.azurewebsites.net/api/OnTokenIssuanceStart_CustomClaimsExtension?code=nfe8tDdGaSvhfPMn7G8TAyVXcMLLuoBYn7Th-1sF9dZQAzFu76q5PQ==

I'm using a custom authentication extension with Microsoft Entra ID for my Azure Function app. When I manually create the function using the Azure Portal and configure the Entra ID authentication extension, everything works as expected — the function URL returns the JSON response and the extension returns the expected claims (like user info) inside the request.

Here is the code which I added when created function from Azure Functions app portal, which I get from here

https://learn.microsoft.com/en-us/entra/identity-platform/custom-extension-tokenissuancestart-setup?tabs=visual-studio%2Cazure-portal&pivots=azure-portal#edit-the-function

`#r "Newtonsoft.Json"`
    using System.Net;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.Extensions.Primitives;
    using Newtonsoft.Json;
    public static async Task<IActionResult> Run(HttpRequest req, ILogger log)
    {
        log.LogInformation("C# HTTP trigger function processed a request.");
        string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
        dynamic data = JsonConvert.DeserializeObject(requestBody);
  
       // Read the correlation ID from the Microsoft Entra request   
        string correlationId = data?.data.authenticationContext.correlationId;
  
        // Claims to return to Microsoft Entra
        ResponseContent r = new ResponseContent();
        r.data.actions[0].claims.CorrelationId = correlationId;
        r.data.actions[0].claims.ApiVersion = "1.0.0";
        r.data.actions[0].claims.DateOfBirth = "01/01/2000";
        r.data.actions[0].claims.CustomRoles.Add("Writer");
        r.data.actions[0].claims.CustomRoles.Add("Editor");
        return new OkObjectResult(r);
    }
    public class ResponseContent
    {
        [JsonProperty("data")]
        public Data data { get; set; }
        public ResponseContent()
        {
            data = new Data();
        }
    }
    public class Data
    {
        [JsonProperty("@odata.type")]
        public string odatatype { get; set; }
        public List<Action> actions { get; set; }
        public Data()
        {
            odatatype = "microsoft.graph.onTokenIssuanceStartResponseData";
            actions = new List<Action>();
            actions.Add(new Action());
        }
    }
    public class Action
    {
        [JsonProperty("@odata.type")]
        public string odatatype { get; set; }
        public Claims claims { get; set; }
        public Action()
        {
            odatatype = "microsoft.graph.tokenIssuanceStart.provideClaimsForToken";
            claims = new Claims();
        }
    }
    public class Claims
    {
        [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
        public string CorrelationId { get; set; }
        [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
        public string DateOfBirth { get; set; }
        public string ApiVersion { get; set; }
        public List<string> CustomRoles { get; set; }
        public Claims()
        {
            CustomRoles = new List<string>();
        }
    }

Case 2

Here is public endpoint which is not working with entra even azure funciton retuning same json
https://customextensionfunctionapp.azurewebsites.net/api/OnTokenIssuranceStartFun?code=6qL_PiZglc12fMkUWlCwXt5BcW-cN7NyvC_Bntp4jJU5AzFuyhAIZw==

However, when I deploy the same function from Visual Studio (using the publish profile), the function still runs fine — the function URL returns same JSON in the browser — but the custom authentication extension doesn't return any claims and getting error. The only difference I could see here when deploy using Visual Studio function get deploy in the form of package and in other case we direct upload code.

Here is my Visual Studio code of the function:

using System;
    using System.IO;
    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;
    using Microsoft.Data.SqlClient;
    using System.Collections.Generic;
  
    namespace AzureTestFunction
    {
        public static class Function1
        {
            [FunctionName("Function1")]
            public static async Task<IActionResult> Run(
                [HttpTrigger(AuthorizationLevel.Function, "get", Route = null)] HttpRequest req,
                ILogger log)
            {
                log.LogInformation("C# HTTP trigger function processed a request.");
                string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
                dynamic data = JsonConvert.DeserializeObject(requestBody);
  
               // Read the correlation ID from the Microsoft Entra request   
                string correlationId = data?.data.authenticationContext.correlationId;
              
                // Claims to return to Microsoft Entra
                ResponseContent r = new ResponseContent();
                r.data.actions[0].claims.CorrelationId = correlationId;
                r.data.actions[0].claims.ApiVersion = "1.0.0";
                r.data.actions[0].claims.DateOfBirth = "01/01/2000";
                r.data.actions[0].claims.CustomRoles.Add("Writer");
                r.data.actions[0].claims.CustomRoles.Add("Editor");
              
                // Get database values
              
                string connectionString = Environment.GetEnvironmentVariable("SqlServerConnection");
                var resultList = new List<string>();
  
                using (SqlConnection conn = new SqlConnection(connectionString))
                {
                    await conn.OpenAsync();
                    var query = "SELECT Name from auth.Permissions"; // Adjust your table/query
                    using (SqlCommand cmd = new SqlCommand(query, conn))
                    using (SqlDataReader reader = await cmd.ExecuteReaderAsync())
                    {
                        while (await reader.ReadAsync())
                        {
                            resultList.Add(reader.GetString(0)); // assuming Name is the first column
                        }
                    }
                }
                // append claims which are coming from database
                foreach (var result in resultList)
                {
                    r.data.actions[0].claims.Permissions.Add(result);
                }
  
                return new OkObjectResult(r);
            }
        }
        public class ResponseContent
        {
            [JsonProperty("data")]
            public Data data { get; set; }
            public ResponseContent()
            {
                data = new Data();
            }
        }
        public class Data
        {
            [JsonProperty("@odata.type")]
            public string odatatype { get; set; }
            public List<Action> actions { get; set; }
            public Data()
            {
                odatatype = "microsoft.graph.onTokenIssuanceStartResponseData";
                actions = new List<Action>();
                actions.Add(new Action());
            }
        }
        public class Action
        {
            [JsonProperty("@odata.type")]
            public string odatatype { get; set; }
            public Claims claims { get; set; }
            public Action()
            {
                odatatype = "microsoft.graph.tokenIssuanceStart.provideClaimsForToken";
                claims = new Claims();
            }
        }
        public class Claims
        {
            [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
            public string CorrelationId { get; set; }
            [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
            public string DateOfBirth { get; set; }
            public string ApiVersion { get; set; }
            public List<string> CustomRoles { get; set; }
            public List<string> Permissions { get; set; }
  
            public Claims()
            {
                CustomRoles = new List<string>();
                Permissions = new List<string>();
            }
        }
    }

Here is the error which i am getting.
AADSTS1100001: Non-retryable error has occurred. Underlying error code: 1003002. Trace ID: 3ef48eac-d5a2-4e08-ab94-b1e998e20100 Correlation ID: db0c6f94-445d-4222-92bb-6d3215f6ea9f If anyone could help me - how can I debug this? It would be great. Thank you

Microsoft Security | Microsoft Entra | Microsoft Entra External ID

Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.