0

I created an Azure Function app. Within it, I have an HTTPTrigger function "Sync" that works very well and can be called successfully locally by (HTTP://localhost/api/sync) or Azure by using its Azure Url (https://xxx.azurewebsites.net/api/sync).

I wanted to be able to continue calling that function via http, but I also wanted to trigger it to run once an hour, so I created a TimerTrigger function "ScheduledSync" with the sole purpose of calling the "Sync" function via HTTPRequestMessage.

ScheduledSync works great locally calling and running the HTTP triggered function successfully, but once it's published in Azure, the HTTP request to https://xxx.azurewebsites.net/api/sync fails.

Nothing I have tried has worked, receiving an unauthorized 403 error in the ScheduledSync function logs. I was passing the Function's key, but later removed authentication altogether, but its like Azure doesn't let a function call itself using the full Azure URL, but localhost doesn't work in Azure either. I can call the same Azure Sync URL from PostMan remotely that the ScheduledSync is calling, with no authentication or key, and it runs successfully.

Tried refactoring based on this q&a, but it didn't seem to make a difference.

[Function("Sync")]
public async Task<HttpResponseData> Run(
    [HttpTrigger(AuthorizationLevel.Function, "post")] HttpRequestData req,
    FunctionContext _,
    CancellationToken cancellationToken)
{
... //sync code
[Function("ScheduledSync")]
public async Task RunAsync([TimerTrigger("0 0 * * * *")] TimerInfo timerInfo, CancellationToken cancellationToken)
{

...

try
{
    using var request = new HttpRequestMessage(HttpMethod.Post, uri);

    var response = await _httpClient.SendAsync(request, cancellationToken);

    ... // logging and error handling code

Function Log:

2025-04-28T22:46:00Z   [Information]   Executing 'Functions.ScheduledSync' (Reason='Timer fired at 2025-04-28T22:46:00.0027402+00:00', Id=895d3ab8-b00e-40b0-837d-a77892b125c6)
2025-04-28T22:46:00Z   [Information]   Trigger Details: ScheduleStatus: {"Last":"2025-04-28T22:45:00+00:00","Next":"2025-04-28T22:46:00+00:00","LastUpdated":"2025-04-28T22:45:00+00:00"}
2025-04-28T22:46:00Z   [Information]   Start processing HTTP request POST https://xxx.azurewebsites.net/api/Sync
2025-04-28T22:46:00Z   [Information]   Sending HTTP request POST https://xxx.azurewebsites.net/api/Sync
2025-04-28T22:46:00Z   [Information]   Received HTTP response headers after 46.0215ms - 403
2025-04-28T22:46:00Z   [Information]   End processing HTTP request after 46.2548ms - 403
2025-04-28T22:46:00Z   [Error] Scheduled Sync call failed with status Forbidden: <!DOCTYPE HTML>
<HTML>
  ....
  <h1 id="unavailable">Error 403 - Forbidden</h1>
  <p id="tryAgain">The web app you have attempted to reach has blocked your access 
  </p>
  ...
</HTML>

Thanks in advance for any help you provide.

2
  • 2
    just a general suggestion, if you use a time (cron) trigger why not extract the logic of the http trigger function into a separate function and call it directly? imo your approach has no benefit. other than that haney has made a good suggestion Commented Apr 29 at 7:08
  • 1
    Agreed, pull out the logic in the HTTP trigger and put it in its own class/method and make it reusable so you’re not making a HTTP call back to itself. Commented Apr 29 at 10:12

1 Answer 1

2

Azure has a lot of "footgun" preventing defaults. One of them is what's called Access Restrictions. These usually default to "No Access" or similar. You'll need to create a rule to allow your function to access the desired other function. You could do this a few ways including by IP.

See here for more: https://learn.microsoft.com/en-us/azure/app-service/app-service-ip-restrictions?tabs=azurecli

Sign up to request clarification or add additional context in comments.

1 Comment

Removing access restrictions completely showed that your answer is correct, a narrower allow should do the trick. However, the comments above are correct. I should take the sync logic out of the HTTP trigger and put it into a shared internal method to be called by logicless HTTP and TIMER triggers as needed. Thank you all so much!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.