Question: I have an App Engine project.

I also have a Google Cloud Function.

And I want to call that Google Cloud Function from the App Engine project. I just can't seem to get that to work.

Yes, if I make the function full public (i.e. set the Cloud Function to 'allow all traffic' *and* create a rule for 'allUsers' to allow calling the function) it works. But if I limit either of the two settings, it stops working immediately and I get 403's.

The App and Function are in the same project, so I would at least assume that setting the Function to 'allow internal traffic only' should work just fine, provided that I have a rule for 'allUsers' to allow calling the function.

How does that work? How does one generally call a (non-public) Google Cloud Function from Google App Engine?

Answer: 
You need an auth header for the ping to the function url. It should look like:

```
headers = {
    ....
    'Authorization': 'Bearer some-long-hash-token'
}

```

Here is how to get the token:

```
import requests
token_response = requests.get(
    'http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/identity?audience=' +
    'https://[your zone]-[your app name].cloudfunctions.net/[your function name]', 
    headers={'Metadata-Flavor': 'Google'})

return token_response.content.decode("utf-8")

```

'Allow internal traffic only' does not work as expected. My App Engine app is in the same project as the Functions, and it does not work. I had to turn on 'Allow all traffic', and use the header method.

Example:

```
def get_access_token():
    import requests
    token_response = requests.get(
        'http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/identity?audience=' +
        'https://us-central1-my_app.cloudfunctions.net/my_function', 
        headers={'Metadata-Flavor': 'Google'})

    return token_response.content.decode("utf-8")

def test():
    url_string = f"https://us-central1-my_app.cloudfunctions.net/my_function?message=it%20worked"

    access_token = get_access_token()

    print(
        requests.get(url_string, headers={'Authorization': f"Bearer {access_token}"}
    )

```
@GAEfan is correct.

As an addition: I used the official Google Auth library to give me the necessary headers.

```js
const {GoogleAuth} = require('google-auth-library');
// Instead of specifying the type of client you'd like to use (JWT, OAuth2, etc)
// this library will automatically choose the right client based on the environment.
const googleCloudFunctionURL = 'https://europe-west1-project.cloudfunctions.net/function';
(async function() {
  const auth = new GoogleAuth();
  let googleCloudFunctionClient = await auth.getIdTokenClient(googleCloudFunctionURL);
  console.log(await googleCloudFunctionClient.getRequestHeaders(googleCloudFunctionURL));
})();

```