Authenticating Developers, Functions, and End-users

By default, only project owners and editors can create, update or delete functions. To grant other users or groups the ability to perform these actions, you can use Cloud Identity and Access Management (IAM) to grant roles to different members.

Similarly, you can grant or restrict the ability to invoke a function. This behavior differs for HTTP functions and background functions:

  • By default, any user or service can invoke an HTTP function. You can configure IAM on HTTP functions to restrict this behavior so that your HTTP function can only be invoked by providing authentication credentials in the request.
  • Background functions can only be invoked by the event source to which they are subscribed.

Three common use cases for authentication include:

  • Securing developer access so that only specific users can invoke the function during testing.

  • Securing function-to-function access so that only authorized functions can invoke your function.

  • Securing end-user access to an application from mobile or web clients.

Developers

In addition to administrative actions such as creating, updating, and deleting functions, developers often want to test functions privately before releasing them publicly.

When using curl or similar tools, you must treat these as end-user requests and provide a Google OAuth token in the request's Authorization header. For example, you can get a token via gcloud as follows:

curl https://REGION-PROJECT_ID.cloudfunctions.net/FUNCTION_NAME \
  -H "Authorization: bearer $(gcloud auth print-identity-token)"

In order for this request to work, the role assigned to the developer must contain the cloudfunctions.functions.invoke permission. By default, the Cloud Functions Admin and Cloud Functions Developer roles have this permission. See Cloud Functions IAM Roles for the full list of roles and their associated permissions.

Finally, we recommend that you allocate the minimum set of permissions required to develop and use your functions. Make sure that IAM policies on your functions are locked down to the minimum number of users and service accounts.

Function-to-function

When building services that connect multiple functions, it's a good idea to ensure that each function is only able to make requests to certain functions. For instance, if you have a login function, it should be able to access the user profiles function, but it probably shouldn't be able to access the search function.

First, you'll need to configure the receiving function to accept requests from the calling function:

  1. Grant the Cloud Functions Invoker (roles/cloudfunctions.invoker) role to the calling function identity on the receiving function. By default, this identity is PROJECT_ID@appspot.gserviceaccount.com.

Console

  1. Go to the Google Cloud Platform Console:

    Go to Google Cloud Platform Console

  2. Click the checkbox next to the function whose permissions you want to modify.

  3. Click Show Info Panel in the top right corner to show the Permissions tab, which displays the roles assigned to the function.

  4. In the Add members field, enter the runtime identity of the calling function. This should be a service account email.

  5. Select the Cloud Functions Invoker role from the Select a role drop-down menu.

  6. Click Add.

GCloud

Use the gcloud beta functions add-iam-policy-binding command:

gcloud beta functions add-iam-policy-binding RECEIVING_FUNCTION \
  --member='serviceAccount:CALLING_FUNCTION_IDENTITY' \
  --role='roles/cloudfunctions.invoker'

where RECEIVING_FUNCTION is the receiving function, and CALLING_FUNCTION_IDENTITY is the calling function identity.

In the calling function, you'll need to:

  1. Create a Google-signed OAuth ID token with the audience (aud) set to the URL of the receiving function.

  2. Include the ID token in an Authorization: Bearer ID_TOKEN header in the request to the function.

Nodejs
// Make sure to `npm install --save request-promise` or add the dependency to your package.json
const request = require('request-promise');

exports.callingFunction = (req, res) => {
  // Make sure to replace variables with appropriate values
  const receivingFunctionURL = 'https://REGION-PROJECT.cloudfunctions.net/RECEIVING_FUNCTION';

  // Set up metadata server request
  // See https://cloud.google.com/compute/docs/instances/verifying-instance-identity#request_signature
  const metadataServerTokenURL = 'http://metadata/computeMetadata/v1/instance/service-accounts/default/identity?audience=';
  const tokenRequestOptions = {
      uri: metadataServerTokenURL + receivingFunctionURL,
      headers: {
          'Metadata-Flavor': 'Google'
      }
  };

  // Fetch the token, then provide the token in the request to the receiving function
  request(tokenRequestOptions)
    .then((token) => {
      return request(receivingFunctionURL).auth(null, null, true, token)
    })
    .then((response) => {
      res.status(200).send(response);
    })
    .catch((error) => {
      res.status(400).send(error);
    });
};
    
Python
# Requests is already installed, no need to add it to requirements.txt
import requests

def calling_function(request):
  # Make sure to replace variables with appropriate values
  receiving_function_url = 'https://REGION-PROJECT.cloudfunctions.net/RECEIVING_FUNCTION'

  # Set up metadata server request
  # See https://cloud.google.com/compute/docs/instances/verifying-instance-identity#request_signature
  metadata_server_token_url = 'http://metadata/computeMetadata/v1/instance/service-accounts/default/identity?audience='

  token_request_url = metadata_server_token_url + receiving_function_url
  token_request_headers = {'Metadata-Flavor': 'Google'}

  # Fetch the token
  token_response = requests.get(token_request_url, headers=token_request_headers)
  jwt = token_response.content.decode("utf-8")

  # Provide the token in the request to the receiving function
  receiving_function_headers = {'Authorization': f'bearer {jwt}'}
  function_response = requests.get(receiving_function_url, headers=receiving_function_headers)

  return function_response.content
    

Service-to-function

If you're invoking a function from a compute instance that doesn't have access to compute metadata (e.g. your own server), you'll have to manually generate the proper token:

  1. Self-sign a service account JWT with the target_audience claim set to the URL of the receiving function.

  2. Exchange the self-signed JWT for a Google-signed ID token, which should have the aud claim set to the above URL.

  3. Include the ID token in an Authorization: Bearer ID_TOKEN header in the request to the function.

The Cloud IAP docs have sample code to demonstrate this functionality.

End-users

Most applications handle requests from end-users, and it's a best practice to restrict access to only allowed end users. In order to accomplish this, you can integrate Google Sign-In and grant users the roles/cloudfunctions.invoker IAM role, or implement Firebase Authentication and manually validate their credentials.

Google Sign-In

First, you'll need to enable Google Sign-In in your project:

  1. Create an OAuth 2.0 client ID for your app in the same project as the function you want to secure:
    1. Go to the Credentials page.

      Go to the Credentials page

    2. Select the project with the function you want to secure.
    3. Click Create credentials, then select OAuth Client ID.
      1. You may be required to configure your OAuth consent screen before creating a client ID. If necessary, do so in order to continue.
    4. Select the Application type for which you want to create credentials.
    5. Add a Name and Restrictions if appropriate, then click Create.
  2. Re-deploy the function you want to secure. This will ensure that the correct client ID is set on the function.

If you have multiple OAuth client IDs (for example, one each for Android, iOS, and web), you must re-deploy your function(s) after adding each one to ensure the function picks up the change. Similarly, if you delete a client ID, you must re-deploy your function(s) to remove that client ID and deny requests. All client IDs within a project will be accepted.

In your web or mobile app, you'll need to:

  1. Get an ID token for the OAuth client ID:
  2. Include the ID token in an Authorization: Bearer ID_TOKEN header in the request to the function.

Cloud Functions will validate the auth token and allow the request, or reject the request before the function starts up. If a request is rejected, you won't be billed for that request.

Getting user profile information

If you want to access user profile information, you can pull the token out of the Authorization header, decode the JSON Web Token, and extract the body.

The body of the ID token should contain the following information:

{
 // These six fields are included in all Google ID Tokens.
 "iss": "https://accounts.google.com",
 "sub": "110169484474386276334",
 "azp": "1008719970978-hb24n2dstb40o45d4feuo2ukqmcc6381.apps.googleusercontent.com",
 "aud": "1008719970978-hb24n2dstb40o45d4feuo2ukqmcc6381.apps.googleusercontent.com",
 "iat": "1433978353",
 "exp": "1433981953",

 // These seven fields are only included when the user has granted the "profile"
 // and "email" OAuth scopes to the application.
 "email": "testuser@gmail.com",
 "email_verified": "true",
 "name" : "Test User",
 "picture": "https://lh4.googleusercontent.com/-kYgzyAWpZzJ/ABCDEFGHI/AAAJKLMNOP/tIXL9Ir44LE/s99-c/photo.jpg",
 "given_name": "Test",
 "family_name": "User",
 "locale": "en"
}

There is no need to validate the token, as the token has already been validated by Cloud IAM.

Troubleshooting

If user requests are being rejected and you believe they should be allowed, ensure that users have been granted the roles/cloudfunctions.invoker role, or have the cloudfunctions.functions.invoke permission. Learn more about these in the Cloud Functions IAM reference.

Web apps, authentication, and CORS

If you want to build a web app that is secured with Google Sign-in and Cloud Functions IAM, you'll likely have to deal with Cross-Origin Resource Sharing (CORS). CORS preflight requests are sent without an Authorization header, so they will be rejected on all non-public HTTP Functions. Because the preflight requests fail, the main request will also fail.

To work around this, you can host your web app and function(s) on the same domain to avoid CORS preflight requests. Otherwise, you should make your functions public and handle CORS and authentication in the function code.

Alternatively, you can deploy a Cloud Endpoints proxy and enable CORS. If you want authentication capabilities, you can also enable Google ID token validation, which will validate these same authentication tokens.

Firebase Authentication

If you want to authenticate users using email/password, phone number, social providers like Facebook or GitHub, or a custom authentication mechanism, you can use Firebase Authentication.

First you'll need to set up Firebase Authentication in your project and function:

  1. Set up Firebase Authentication in the Firebase Console.

    Go to the Firebase Console

  2. Import the appropriate Firebase Admin SDK and configure it properly.

  3. Add middleware to your code to verify Firebase ID tokens.

  4. Deploy your function publicly.

In your web or mobile app, you need to:

  1. Use the appropriate Firebase Auth client library to get an ID token:
  2. Include the ID token in an Authorization: Bearer ID_TOKEN header in the request to the function.

Alternatively, you can deploy a Cloud Endpoints proxy and enable Firebase ID token validation, which will validate these same authentication tokens.

Getting user profile information

If you want to access user profile information, you can use the Firebase Admin SDK to retrieve user data.

API Keys

API keys identify the client application and GCP project calling your API, allowing you to perform simple authorization as well as quota checks and rate limiting.

API keys aren't as secure as the other authentication methods listed here for the following reasons:

  1. API keys are long lived. This means that if one leaks, it can be used indefinitely (or at least until keys are rotated, which requires all clients updating the key).
  2. API keys are often stored client side, making them vulnerable to being re-used by malicious parties.

If you choose to use API keys for quota and rate limiting, we recommend using them together with authentication tokens.

To configure API key access, deploy a Cloud Endpoints proxy and enable configure your securityDefinitions to enable API key validation.

Next steps

Learn how to manage access to the functions you're authenticating to.

Cette page vous a-t-elle été utile ? Évaluez-la :

Envoyer des commentaires concernant…

Cloud Functions Documentation