diff --git a/.changelog/8402.txt b/.changelog/8402.txt new file mode 100644 index 0000000000..86de61340f --- /dev/null +++ b/.changelog/8402.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +identityplayform: added support for `blocking_functions` `quota` and `authorized_domains` in `google_identity_platform_config` +``` diff --git a/google-beta/resource_identity_platform_config_generated_test.go b/google-beta/resource_identity_platform_config_generated_test.go index 85a01ceeec..6212aec985 100644 --- a/google-beta/resource_identity_platform_config_generated_test.go +++ b/google-beta/resource_identity_platform_config_generated_test.go @@ -19,6 +19,7 @@ package google import ( "testing" + "time" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -31,9 +32,10 @@ func TestAccIdentityPlatformConfig_identityPlatformConfigBasicExample(t *testing t.Parallel() context := map[string]interface{}{ - "org_id": envvar.GetTestOrgFromEnv(t), - "billing_acct": envvar.GetTestBillingAccountFromEnv(t), - "random_suffix": acctest.RandString(t, 10), + "org_id": envvar.GetTestOrgFromEnv(t), + "billing_acct": envvar.GetTestBillingAccountFromEnv(t), + "quota_start_time": time.Now().AddDate(0, 0, 1).Format(time.RFC3339), + "random_suffix": acctest.RandString(t, 10), } acctest.VcrTest(t, resource.TestCase{ @@ -73,6 +75,29 @@ resource "google_project_service" "identitytoolkit" { resource "google_identity_platform_config" "default" { project = google_project.default.project_id autodelete_anonymous_users = true + blocking_functions { + triggers { + event_type = "beforeSignIn" + function_uri = "https://us-east1-tf-test-my-project%{random_suffix}.cloudfunctions.net/before-sign-in" + } + forward_inbound_credentials { + refresh_token = true + access_token = true + id_token = true + } + } + quota { + sign_up_quota_config { + quota = 1000 + start_time = "%{quota_start_time}" + quota_duration = "7200s" + } + } + authorized_domains = [ + "localhost", + "tf-test-my-project%{random_suffix}.firebaseapp.com", + "tf-test-my-project%{random_suffix}.web.app", + ] } `, context) } diff --git a/google-beta/services/identityplatform/resource_identity_platform_config.go b/google-beta/services/identityplatform/resource_identity_platform_config.go index 4c1792586a..7d485798df 100644 --- a/google-beta/services/identityplatform/resource_identity_platform_config.go +++ b/google-beta/services/identityplatform/resource_identity_platform_config.go @@ -48,11 +48,112 @@ func ResourceIdentityPlatformConfig() *schema.Resource { }, Schema: map[string]*schema.Schema{ + "authorized_domains": { + Type: schema.TypeList, + Optional: true, + Description: `List of domains authorized for OAuth redirects.`, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, "autodelete_anonymous_users": { Type: schema.TypeBool, Optional: true, Description: `Whether anonymous users will be auto-deleted after a period of 30 days`, }, + "blocking_functions": { + Type: schema.TypeList, + Optional: true, + Description: `Configuration related to blocking functions.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "triggers": { + Type: schema.TypeSet, + Required: true, + Description: `Map of Trigger to event type. Key should be one of the supported event types: "beforeCreate", "beforeSignIn".`, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "event_type": { + Type: schema.TypeString, + Required: true, + }, + "function_uri": { + Type: schema.TypeString, + Required: true, + Description: `HTTP URI trigger for the Cloud Function.`, + }, + "update_time": { + Type: schema.TypeString, + Computed: true, + Description: `When the trigger was changed.`, + }, + }, + }, + }, + "forward_inbound_credentials": { + Type: schema.TypeList, + Optional: true, + Description: `The user credentials to include in the JWT payload that is sent to the registered Blocking Functions.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "access_token": { + Type: schema.TypeBool, + Optional: true, + Description: `Whether to pass the user's OAuth identity provider's access token.`, + }, + "id_token": { + Type: schema.TypeBool, + Optional: true, + Description: `Whether to pass the user's OIDC identity provider's ID token.`, + }, + "refresh_token": { + Type: schema.TypeBool, + Optional: true, + Description: `Whether to pass the user's OAuth identity provider's refresh token.`, + }, + }, + }, + }, + }, + }, + }, + "quota": { + Type: schema.TypeList, + Optional: true, + Description: `Configuration related to quotas.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "sign_up_quota_config": { + Type: schema.TypeList, + Optional: true, + Description: `Quota for the Signup endpoint, if overwritten. Signup quota is measured in sign ups per project per hour per IP.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "quota": { + Type: schema.TypeInt, + Optional: true, + Description: `A sign up APIs quota that customers can override temporarily.`, + }, + "quota_duration": { + Type: schema.TypeString, + Optional: true, + Description: `How long this quota will be active for. It is measurred in seconds, e.g., Example: "9.615s".`, + }, + "start_time": { + Type: schema.TypeString, + Optional: true, + Description: `When this quota will take affect.`, + }, + }, + }, + }, + }, + }, + }, "name": { Type: schema.TypeString, Computed: true, @@ -172,6 +273,15 @@ func resourceIdentityPlatformConfigRead(d *schema.ResourceData, meta interface{} if err := d.Set("autodelete_anonymous_users", flattenIdentityPlatformConfigAutodeleteAnonymousUsers(res["autodeleteAnonymousUsers"], d, config)); err != nil { return fmt.Errorf("Error reading Config: %s", err) } + if err := d.Set("blocking_functions", flattenIdentityPlatformConfigBlockingFunctions(res["blockingFunctions"], d, config)); err != nil { + return fmt.Errorf("Error reading Config: %s", err) + } + if err := d.Set("quota", flattenIdentityPlatformConfigQuota(res["quota"], d, config)); err != nil { + return fmt.Errorf("Error reading Config: %s", err) + } + if err := d.Set("authorized_domains", flattenIdentityPlatformConfigAuthorizedDomains(res["authorizedDomains"], d, config)); err != nil { + return fmt.Errorf("Error reading Config: %s", err) + } return nil } @@ -198,6 +308,24 @@ func resourceIdentityPlatformConfigUpdate(d *schema.ResourceData, meta interface } else if v, ok := d.GetOkExists("autodelete_anonymous_users"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, autodeleteAnonymousUsersProp)) { obj["autodeleteAnonymousUsers"] = autodeleteAnonymousUsersProp } + blockingFunctionsProp, err := expandIdentityPlatformConfigBlockingFunctions(d.Get("blocking_functions"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("blocking_functions"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, blockingFunctionsProp)) { + obj["blockingFunctions"] = blockingFunctionsProp + } + quotaProp, err := expandIdentityPlatformConfigQuota(d.Get("quota"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("quota"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, quotaProp)) { + obj["quota"] = quotaProp + } + authorizedDomainsProp, err := expandIdentityPlatformConfigAuthorizedDomains(d.Get("authorized_domains"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("authorized_domains"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, authorizedDomainsProp)) { + obj["authorizedDomains"] = authorizedDomainsProp + } url, err := tpgresource.ReplaceVars(d, config, "{{IdentityPlatformBasePath}}projects/{{project}}/config") if err != nil { @@ -210,6 +338,18 @@ func resourceIdentityPlatformConfigUpdate(d *schema.ResourceData, meta interface if d.HasChange("autodelete_anonymous_users") { updateMask = append(updateMask, "autodeleteAnonymousUsers") } + + if d.HasChange("blocking_functions") { + updateMask = append(updateMask, "blockingFunctions") + } + + if d.HasChange("quota") { + updateMask = append(updateMask, "quota") + } + + if d.HasChange("authorized_domains") { + updateMask = append(updateMask, "authorizedDomains") + } // updateMask is a URL parameter but not present in the schema, so ReplaceVars // won't set it url, err = transport_tpg.AddQueryParams(url, map[string]string{"updateMask": strings.Join(updateMask, ",")}) @@ -278,6 +418,312 @@ func flattenIdentityPlatformConfigAutodeleteAnonymousUsers(v interface{}, d *sch return v } +func flattenIdentityPlatformConfigBlockingFunctions(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["triggers"] = + flattenIdentityPlatformConfigBlockingFunctionsTriggers(original["triggers"], d, config) + transformed["forward_inbound_credentials"] = + flattenIdentityPlatformConfigBlockingFunctionsForwardInboundCredentials(original["forwardInboundCredentials"], d, config) + return []interface{}{transformed} +} +func flattenIdentityPlatformConfigBlockingFunctionsTriggers(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + if v == nil { + return v + } + l := v.(map[string]interface{}) + transformed := make([]interface{}, 0, len(l)) + for k, raw := range l { + original := raw.(map[string]interface{}) + transformed = append(transformed, map[string]interface{}{ + "event_type": k, + "function_uri": flattenIdentityPlatformConfigBlockingFunctionsTriggersFunctionUri(original["functionUri"], d, config), + "update_time": flattenIdentityPlatformConfigBlockingFunctionsTriggersUpdateTime(original["updateTime"], d, config), + }) + } + return transformed +} +func flattenIdentityPlatformConfigBlockingFunctionsTriggersFunctionUri(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenIdentityPlatformConfigBlockingFunctionsTriggersUpdateTime(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenIdentityPlatformConfigBlockingFunctionsForwardInboundCredentials(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["id_token"] = + flattenIdentityPlatformConfigBlockingFunctionsForwardInboundCredentialsIdToken(original["idToken"], d, config) + transformed["access_token"] = + flattenIdentityPlatformConfigBlockingFunctionsForwardInboundCredentialsAccessToken(original["accessToken"], d, config) + transformed["refresh_token"] = + flattenIdentityPlatformConfigBlockingFunctionsForwardInboundCredentialsRefreshToken(original["refreshToken"], d, config) + return []interface{}{transformed} +} +func flattenIdentityPlatformConfigBlockingFunctionsForwardInboundCredentialsIdToken(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenIdentityPlatformConfigBlockingFunctionsForwardInboundCredentialsAccessToken(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenIdentityPlatformConfigBlockingFunctionsForwardInboundCredentialsRefreshToken(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenIdentityPlatformConfigQuota(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["sign_up_quota_config"] = + flattenIdentityPlatformConfigQuotaSignUpQuotaConfig(original["signUpQuotaConfig"], d, config) + return []interface{}{transformed} +} +func flattenIdentityPlatformConfigQuotaSignUpQuotaConfig(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["quota"] = + flattenIdentityPlatformConfigQuotaSignUpQuotaConfigQuota(original["quota"], d, config) + transformed["start_time"] = + flattenIdentityPlatformConfigQuotaSignUpQuotaConfigStartTime(original["startTime"], d, config) + transformed["quota_duration"] = + flattenIdentityPlatformConfigQuotaSignUpQuotaConfigQuotaDuration(original["quotaDuration"], d, config) + return []interface{}{transformed} +} +func flattenIdentityPlatformConfigQuotaSignUpQuotaConfigQuota(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + // Handles the string fixed64 format + if strVal, ok := v.(string); ok { + if intVal, err := tpgresource.StringToFixed64(strVal); err == nil { + return intVal + } + } + + // number values are represented as float64 + if floatVal, ok := v.(float64); ok { + intVal := int(floatVal) + return intVal + } + + return v // let terraform core handle it otherwise +} + +func flattenIdentityPlatformConfigQuotaSignUpQuotaConfigStartTime(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenIdentityPlatformConfigQuotaSignUpQuotaConfigQuotaDuration(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenIdentityPlatformConfigAuthorizedDomains(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + func expandIdentityPlatformConfigAutodeleteAnonymousUsers(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { return v, nil } + +func expandIdentityPlatformConfigBlockingFunctions(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + l := v.([]interface{}) + if len(l) == 0 || l[0] == nil { + return nil, nil + } + raw := l[0] + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedTriggers, err := expandIdentityPlatformConfigBlockingFunctionsTriggers(original["triggers"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedTriggers); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["triggers"] = transformedTriggers + } + + transformedForwardInboundCredentials, err := expandIdentityPlatformConfigBlockingFunctionsForwardInboundCredentials(original["forward_inbound_credentials"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedForwardInboundCredentials); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["forwardInboundCredentials"] = transformedForwardInboundCredentials + } + + return transformed, nil +} + +func expandIdentityPlatformConfigBlockingFunctionsTriggers(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (map[string]interface{}, error) { + if v == nil { + return map[string]interface{}{}, nil + } + m := make(map[string]interface{}) + for _, raw := range v.(*schema.Set).List() { + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedFunctionUri, err := expandIdentityPlatformConfigBlockingFunctionsTriggersFunctionUri(original["function_uri"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedFunctionUri); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["functionUri"] = transformedFunctionUri + } + + transformedUpdateTime, err := expandIdentityPlatformConfigBlockingFunctionsTriggersUpdateTime(original["update_time"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedUpdateTime); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["updateTime"] = transformedUpdateTime + } + + transformedEventType, err := tpgresource.ExpandString(original["event_type"], d, config) + if err != nil { + return nil, err + } + m[transformedEventType] = transformed + } + return m, nil +} + +func expandIdentityPlatformConfigBlockingFunctionsTriggersFunctionUri(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandIdentityPlatformConfigBlockingFunctionsTriggersUpdateTime(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandIdentityPlatformConfigBlockingFunctionsForwardInboundCredentials(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + l := v.([]interface{}) + if len(l) == 0 || l[0] == nil { + return nil, nil + } + raw := l[0] + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedIdToken, err := expandIdentityPlatformConfigBlockingFunctionsForwardInboundCredentialsIdToken(original["id_token"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedIdToken); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["idToken"] = transformedIdToken + } + + transformedAccessToken, err := expandIdentityPlatformConfigBlockingFunctionsForwardInboundCredentialsAccessToken(original["access_token"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedAccessToken); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["accessToken"] = transformedAccessToken + } + + transformedRefreshToken, err := expandIdentityPlatformConfigBlockingFunctionsForwardInboundCredentialsRefreshToken(original["refresh_token"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedRefreshToken); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["refreshToken"] = transformedRefreshToken + } + + return transformed, nil +} + +func expandIdentityPlatformConfigBlockingFunctionsForwardInboundCredentialsIdToken(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandIdentityPlatformConfigBlockingFunctionsForwardInboundCredentialsAccessToken(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandIdentityPlatformConfigBlockingFunctionsForwardInboundCredentialsRefreshToken(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandIdentityPlatformConfigQuota(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + l := v.([]interface{}) + if len(l) == 0 || l[0] == nil { + return nil, nil + } + raw := l[0] + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedSignUpQuotaConfig, err := expandIdentityPlatformConfigQuotaSignUpQuotaConfig(original["sign_up_quota_config"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedSignUpQuotaConfig); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["signUpQuotaConfig"] = transformedSignUpQuotaConfig + } + + return transformed, nil +} + +func expandIdentityPlatformConfigQuotaSignUpQuotaConfig(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + l := v.([]interface{}) + if len(l) == 0 || l[0] == nil { + return nil, nil + } + raw := l[0] + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedQuota, err := expandIdentityPlatformConfigQuotaSignUpQuotaConfigQuota(original["quota"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedQuota); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["quota"] = transformedQuota + } + + transformedStartTime, err := expandIdentityPlatformConfigQuotaSignUpQuotaConfigStartTime(original["start_time"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedStartTime); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["startTime"] = transformedStartTime + } + + transformedQuotaDuration, err := expandIdentityPlatformConfigQuotaSignUpQuotaConfigQuotaDuration(original["quota_duration"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedQuotaDuration); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["quotaDuration"] = transformedQuotaDuration + } + + return transformed, nil +} + +func expandIdentityPlatformConfigQuotaSignUpQuotaConfigQuota(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandIdentityPlatformConfigQuotaSignUpQuotaConfigStartTime(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandIdentityPlatformConfigQuotaSignUpQuotaConfigQuotaDuration(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandIdentityPlatformConfigAuthorizedDomains(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} diff --git a/website/docs/r/identity_platform_config.html.markdown b/website/docs/r/identity_platform_config.html.markdown index c40458fc9b..be08655950 100644 --- a/website/docs/r/identity_platform_config.html.markdown +++ b/website/docs/r/identity_platform_config.html.markdown @@ -57,6 +57,29 @@ resource "google_project_service" "identitytoolkit" { resource "google_identity_platform_config" "default" { project = google_project.default.project_id autodelete_anonymous_users = true + blocking_functions { + triggers { + event_type = "beforeSignIn" + function_uri = "https://us-east1-my-project.cloudfunctions.net/before-sign-in" + } + forward_inbound_credentials { + refresh_token = true + access_token = true + id_token = true + } + } + quota { + sign_up_quota_config { + quota = 1000 + start_time = "" + quota_duration = "7200s" + } + } + authorized_domains = [ + "localhost", + "my-project.firebaseapp.com", + "my-project.web.app", + ] } ``` @@ -73,10 +96,85 @@ The following arguments are supported: (Optional) Whether anonymous users will be auto-deleted after a period of 30 days +* `blocking_functions` - + (Optional) + Configuration related to blocking functions. + Structure is [documented below](#nested_blocking_functions). + +* `quota` - + (Optional) + Configuration related to quotas. + Structure is [documented below](#nested_quota). + +* `authorized_domains` - + (Optional) + List of domains authorized for OAuth redirects. + * `project` - (Optional) The ID of the project in which the resource belongs. If it is not provided, the provider project is used. +The `blocking_functions` block supports: + +* `triggers` - + (Required) + Map of Trigger to event type. Key should be one of the supported event types: "beforeCreate", "beforeSignIn". + Structure is [documented below](#nested_triggers). + +* `forward_inbound_credentials` - + (Optional) + The user credentials to include in the JWT payload that is sent to the registered Blocking Functions. + Structure is [documented below](#nested_forward_inbound_credentials). + + +The `triggers` block supports: + +* `event_type` - (Required) The identifier for this object. Format specified above. + +* `function_uri` - + (Required) + HTTP URI trigger for the Cloud Function. + +* `update_time` - + (Output) + When the trigger was changed. + +The `forward_inbound_credentials` block supports: + +* `id_token` - + (Optional) + Whether to pass the user's OIDC identity provider's ID token. + +* `access_token` - + (Optional) + Whether to pass the user's OAuth identity provider's access token. + +* `refresh_token` - + (Optional) + Whether to pass the user's OAuth identity provider's refresh token. + +The `quota` block supports: + +* `sign_up_quota_config` - + (Optional) + Quota for the Signup endpoint, if overwritten. Signup quota is measured in sign ups per project per hour per IP. + Structure is [documented below](#nested_sign_up_quota_config). + + +The `sign_up_quota_config` block supports: + +* `quota` - + (Optional) + A sign up APIs quota that customers can override temporarily. + +* `start_time` - + (Optional) + When this quota will take affect. + +* `quota_duration` - + (Optional) + How long this quota will be active for. It is measurred in seconds, e.g., Example: "9.615s". + ## Attributes Reference In addition to the arguments listed above, the following computed attributes are exported: