diff --git a/ovh/data_me_api_oauth2_client.go b/ovh/data_me_api_oauth2_client.go new file mode 100644 index 000000000..ecc02a31d --- /dev/null +++ b/ovh/data_me_api_oauth2_client.go @@ -0,0 +1,77 @@ +package ovh + +import ( + "context" + "fmt" + "log" + "net/url" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/ovh/terraform-provider-ovh/ovh/helpers" +) + +func dataSourceMeApiOauth2Client() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceMeApiOauth2ClientRead, + Schema: map[string]*schema.Schema{ + "callback_urls": { + Type: schema.TypeList, + Description: "Callback URLs of the applications using this oauth2 client. Required if using the AUTHORIZATION_CODE flow.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Computed: true, + }, + "client_id": { + Type: schema.TypeString, + Description: "Client ID for the oauth2 client, generated during the resource creation.", + Required: true, + }, + "description": { + Type: schema.TypeString, + Description: "A description of your oauth2 client.", + Computed: true, + }, + "identity": { + Type: schema.TypeString, + Description: "URN that will allow you to associate this oauth2 client with an access policy.", + Computed: true, + }, + "flow": { + Type: schema.TypeString, + Description: "OAuth2 flow type implemented for this oauth2 client. Can be either AUTHORIZATION_CODE or CLIENT_CREDENTIALS", + Computed: true, + }, + "name": { + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func dataSourceMeApiOauth2ClientRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + config := meta.(*Config) + + serviceAccount := &ApiOauth2ClientReadResponse{} + + // Query the oauth2 client using its client ID + endpoint := fmt.Sprintf("/me/api/oauth2/client/%s", url.PathEscape(d.Get("client_id").(string))) + if err := config.OVHClient.GetWithContext(ctx, endpoint, serviceAccount); err != nil { + return diag.FromErr(helpers.CheckDeleted(d, err, endpoint)) + } + + log.Printf("[DEBUG] Read oauth2 client: %s", endpoint) + + // Populate the state with the response body parameters + d.SetId(serviceAccount.ClientId) + d.Set("callback_urls", serviceAccount.CallbackUrls) + d.Set("client_id", serviceAccount.ClientId) + d.Set("description", serviceAccount.Description) + d.Set("flow", serviceAccount.Flow) + d.Set("identity", serviceAccount.Identity) + d.Set("name", serviceAccount.Name) + + return nil +} diff --git a/ovh/data_me_api_oauth2_client_test.go b/ovh/data_me_api_oauth2_client_test.go new file mode 100644 index 000000000..a88c29a30 --- /dev/null +++ b/ovh/data_me_api_oauth2_client_test.go @@ -0,0 +1,45 @@ +package ovh + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +// Tests valid configurations to create oauth2 clients +func TestAccMeApiOauth2Client_data(t *testing.T) { + const resourceName = "ovh_me_api_oauth2_client.service_account_1" + + // Successful test with app required parameters, + // that validates the use of the data instruction + const okConfigClientCredentials = ` + resource "ovh_me_api_oauth2_client" "service_account_1" { + description = "tf acc test client credentials" + name = "tf acc test client credentials" + flow = "CLIENT_CREDENTIALS" + } + data "ovh_me_api_oauth2_client" "service_account_1" { + client_id = ovh_me_api_oauth2_client.service_account_1.client_id + depends_on = [ovh_me_api_oauth2_client.service_account_1] + } + output "oauth2_client_name" { + value = data.ovh_me_api_oauth2_client.service_account_1.name + }` + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheckCredentials(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + // Create the object, check that the client secret is not empty after creation + { + Config: okConfigClientCredentials, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrWith(resourceName, "client_id", apiOauth2ClientStringNotEmpty), + resource.TestCheckResourceAttrWith(resourceName, "client_secret", apiOauth2ClientStringNotEmpty), + resource.TestCheckOutput( + "oauth2_client_name", "tf acc test client credentials", + ), + ), + }, + }, + }) +} diff --git a/ovh/data_me_api_oauth2_clients.go b/ovh/data_me_api_oauth2_clients.go new file mode 100644 index 000000000..d1c378ccd --- /dev/null +++ b/ovh/data_me_api_oauth2_clients.go @@ -0,0 +1,39 @@ +package ovh + +import ( + "context" + "sort" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/ovh/terraform-provider-ovh/ovh/helpers/hashcode" +) + +func dataSourceMeApiOauth2Clients() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceMeApiOauth2ClientsRead, + Schema: map[string]*schema.Schema{ + "client_ids": { + Type: schema.TypeSet, + Elem: &schema.Schema{Type: schema.TypeString}, + Computed: true, + }, + }, + } +} + +func dataSourceMeApiOauth2ClientsRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + config := meta.(*Config) + + var oAuth2ClientsIds []string + err := config.OVHClient.GetWithContext(ctx, "/me/api/oauth2/client", &oAuth2ClientsIds) + if err != nil { + return diag.FromErr(err) + } + + d.Set("client_ids", oAuth2ClientsIds) + + sort.Strings(oAuth2ClientsIds) + d.SetId(hashcode.Strings(oAuth2ClientsIds)) + return nil +} diff --git a/ovh/data_me_api_oauth2_clients_test.go b/ovh/data_me_api_oauth2_clients_test.go new file mode 100644 index 000000000..218c95eea --- /dev/null +++ b/ovh/data_me_api_oauth2_clients_test.go @@ -0,0 +1,44 @@ +package ovh + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +// Tests valid configurations to read all oauth2 clients +func TestAccMeApiOauth2Clients_data(t *testing.T) { + // Successful test with app required parameters, + // that validates the use of the data instruction + // We create a resource beforehand, to make sure that at least one service account exists + const okConfigClientCredentials = ` + resource "ovh_me_api_oauth2_client" "service_account_1" { + description = "tf acc test client credentials" + name = "tf acc test client credentials" + flow = "CLIENT_CREDENTIALS" + } + # A data source listing all the client ids in the account + data "ovh_me_api_oauth2_clients" "all_clients_ref" { + depends_on = [ovh_me_api_oauth2_client.service_account_1] + } + + output "is_array_length_gt_0" { + value = length(data.ovh_me_api_oauth2_clients.all_clients_ref.client_ids) > 0 + } + ` + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheckCredentials(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + // Create the object, check that the client secret is not empty after creation + { + Config: okConfigClientCredentials, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckOutput( + "is_array_length_gt_0", "true", + ), + ), + }, + }, + }) +} diff --git a/ovh/provider.go b/ovh/provider.go index 6579553a5..d1ee77e5b 100644 --- a/ovh/provider.go +++ b/ovh/provider.go @@ -118,6 +118,8 @@ func Provider() *schema.Provider { "ovh_iploadbalancing_vrack_network": dataSourceIpLoadbalancingVrackNetwork(), "ovh_iploadbalancing_vrack_networks": dataSourceIpLoadbalancingVrackNetworks(), "ovh_me": dataSourceMe(), + "ovh_me_api_oauth2_client": dataSourceMeApiOauth2Client(), + "ovh_me_api_oauth2_clients": dataSourceMeApiOauth2Clients(), "ovh_me_identity_group": dataSourceMeIdentityGroup(), "ovh_me_identity_groups": dataSourceMeIdentityGroups(), "ovh_me_identity_user": dataSourceMeIdentityUser(), @@ -208,6 +210,7 @@ func Provider() *schema.Provider { "ovh_iploadbalancing_tcp_route_rule": resourceIPLoadbalancingTcpRouteRule(), "ovh_iploadbalancing_vrack_network": resourceIPLoadbalancingVrackNetwork(), "ovh_me_identity_group": resourceMeIdentityGroup(), + "ovh_me_api_oauth2_client": resourceApiOauth2Client(), "ovh_me_identity_user": resourceMeIdentityUser(), "ovh_me_installation_template": resourceMeInstallationTemplate(), "ovh_me_installation_template_partition_scheme": resourceMeInstallationTemplatePartitionScheme(), diff --git a/ovh/resource_me_api_oauth2_client.go b/ovh/resource_me_api_oauth2_client.go new file mode 100644 index 000000000..f0653a0a8 --- /dev/null +++ b/ovh/resource_me_api_oauth2_client.go @@ -0,0 +1,196 @@ +package ovh + +import ( + "context" + "fmt" + "log" + "net/url" + "strings" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/ovh/terraform-provider-ovh/ovh/helpers" +) + +func resourceApiOauth2Client() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceApiOauth2ClientCreate, + ReadContext: resourceApiOauth2ClientRead, + UpdateContext: resourceApiOauth2ClientUpdate, + DeleteContext: resourceApiOauth2ClientDelete, + Importer: &schema.ResourceImporter{ + StateContext: func(ctx context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + + // Get the resource id from the terraform import command. + // If it contains a pipe character, try to parse it as client_id|client_secret + client_config_string := d.Id() + if strings.Contains(client_config_string, "|") { + + log.Printf("[INFO] Importing oauth2 client formatted as 'client_id|client_secret'") + + client_config_params := strings.Split(client_config_string, "|") + if len(client_config_params) != 2 { + return nil, fmt.Errorf("Error importing api oauth2 client: Resource IDs with the pipe character should be formatted as 'client_id|client_secret': %s", d.Id()) + } + d.SetId(client_config_params[0]) + d.Set("client_secret", client_config_params[1]) + } + + // Use the provided resource id as the client_id + d.Set("client_id", d.Id()) + + return []*schema.ResourceData{d}, nil + }, + }, + Schema: map[string]*schema.Schema{ + "callback_urls": { + Type: schema.TypeList, + Description: "Callback URLs of the applications using this oauth2 client. Required if using the AUTHORIZATION_CODE flow.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Optional: true, + }, + "client_id": { + Type: schema.TypeString, + Description: "Client ID for the oauth2 client, generated during the resource creation.", + Computed: true, + }, + "client_secret": { + Type: schema.TypeString, + Description: "Secret for the oauth2 client, generated during the oauth2 client creation.", + Computed: true, + Sensitive: true, + }, + "description": { + Type: schema.TypeString, + Description: "A description of your oauth2 client.", + Required: true, + }, + "identity": { + Type: schema.TypeString, + Description: "URN that will allow you to associate this oauth2 client with an access policy", + Computed: true, + }, + "flow": { + Type: schema.TypeString, + ValidateFunc: helpers.ValidateEnum([]string{"AUTHORIZATION_CODE", "CLIENT_CREDENTIALS"}), + Description: "OAuth2 flow type implemented for this oauth2 client. Can be either AUTHORIZATION_CODE or CLIENT_CREDENTIALS", + ForceNew: true, + Required: true, + }, + "name": { + Type: schema.TypeString, + Required: true, + }, + }, + } +} + +// Common function with the datasource +func resourceApiOauth2ClientRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + config := meta.(*Config) + + serviceAccount := &ApiOauth2ClientReadResponse{} + + // Query the oauth2 client using its client ID + endpoint := fmt.Sprintf("/me/api/oauth2/client/%s", url.PathEscape(d.Get("client_id").(string))) + if err := config.OVHClient.GetWithContext(ctx, endpoint, serviceAccount); err != nil { + return diag.FromErr(helpers.CheckDeleted(d, err, endpoint)) + } + + // Populate the state with the response body parameters + d.Set("callback_urls", serviceAccount.CallbackUrls) + d.Set("client_id", serviceAccount.ClientId) + d.Set("description", serviceAccount.Description) + d.Set("flow", serviceAccount.Flow) + d.Set("identity", serviceAccount.Identity) + d.Set("name", serviceAccount.Name) + + return nil +} + +func resourceApiOauth2ClientCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + config := meta.(*Config) + + // Declare an empty array if no callback url is provided + callbackUrls := []string{} + if d.Get("callback_urls") != nil { + itemsRaw := d.Get("callback_urls").([]interface{}) + for _, raw := range itemsRaw { + callbackUrls = append(callbackUrls, raw.(string)) + } + } + + params := &ApiOauth2ClientCreateOpts{ + CallbackUrls: callbackUrls, + Description: d.Get("description").(string), + Flow: d.Get("flow").(string), + Name: d.Get("name").(string), + } + + log.Printf("[DEBUG] Will create api oauth2 client: %s", params.Name) + + // Create the oauth2 client using the provided parameters + var response ApiOauth2ClientCreateResponse + err := config.OVHClient.PostWithContext(ctx, "/me/api/oauth2/client", params, &response) + if err != nil { + return diag.Errorf("Error creating api oauth2 client %s:\n\t %q", params.Name, err) + } + + // Use the client id as the resource id in the state + d.SetId(response.ClientId) + + // Populate the state with the response body parameters + d.Set("client_id", response.ClientId) + d.Set("client_secret", response.ClientSecret) + + return resourceApiOauth2ClientRead(ctx, d, meta) +} + +func resourceApiOauth2ClientUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + config := meta.(*Config) + + // Declare an empty array if no callback url is provided + callbackUrls := []string{} + if d.Get("callback_urls") != nil { + itemsRaw := d.Get("callback_urls").([]interface{}) + for _, raw := range itemsRaw { + callbackUrls = append(callbackUrls, raw.(string)) + } + } + + params := &ApiOauth2ClientUpdateOpts{ + CallbackUrls: callbackUrls, + Description: d.Get("description").(string), + Name: d.Get("name").(string), + } + + err := config.OVHClient.PutWithContext(ctx, + fmt.Sprintf("/me/api/oauth2/client/%s", url.PathEscape(d.Id())), + params, + nil, + ) + if err != nil { + return diag.Errorf("Unable to update api oauth2 client %s:\n\t %q", url.PathEscape(d.Id()), err) + } + + log.Printf("[DEBUG] Updated api oauth2 client %s", d.Id()) + return resourceApiOauth2ClientRead(ctx, d, meta) +} + +func resourceApiOauth2ClientDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + config := meta.(*Config) + + err := config.OVHClient.DeleteWithContext(ctx, + fmt.Sprintf("/me/api/oauth2/client/%s", url.PathEscape(d.Id())), + nil, + ) + if err != nil { + return diag.Errorf("Unable to delete api oauth2 client %s:\n\t %q", d.Id(), err) + } + + log.Printf("[DEBUG] Deleted api oauth2 client %s", d.Id()) + d.SetId("") + return nil +} diff --git a/ovh/resource_me_api_oauth2_client_test.go b/ovh/resource_me_api_oauth2_client_test.go new file mode 100644 index 000000000..37966f547 --- /dev/null +++ b/ovh/resource_me_api_oauth2_client_test.go @@ -0,0 +1,155 @@ +package ovh + +import ( + "fmt" + "regexp" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +// Returns an error if a string is empty, +// Used in the calls to resource.TestCheckResourceAttrWith() below +func apiOauth2ClientStringNotEmpty(s string) error { + if len(s) > 0 { + return nil + } + return fmt.Errorf("Value is empty") +} + +// Tests valid configurations to create oauth2 clients +func TestAccMeApiOauth2Client_basic(t *testing.T) { + const resourceName1 = "ovh_me_api_oauth2_client.service_account_1" + const resourceName2 = "ovh_me_api_oauth2_client.service_account_2" + + // Successful test with app required parameters + const okConfigClientCredentials = ` + resource "ovh_me_api_oauth2_client" "service_account_1" { + description = "tf acc test client credentials" + name = "tf acc test client credentials" + flow = "CLIENT_CREDENTIALS" + }` + const okConfigAuthorizationCode = ` + resource "ovh_me_api_oauth2_client" "service_account_2" { + description = "tf acc test authorization code" + name = "tf acc test authorization code" + flow = "AUTHORIZATION_CODE" + callback_urls = ["https://localhost:8080"] + }` + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheckCredentials(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + // Create the object, check that the client secret is not empty after creation + { + Config: okConfigClientCredentials, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrWith(resourceName1, "client_id", apiOauth2ClientStringNotEmpty), + resource.TestCheckResourceAttrWith(resourceName1, "client_secret", apiOauth2ClientStringNotEmpty), + ), + }, + // Verify that the state matches the resource imported with its client_id + { + ResourceName: resourceName1, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"client_secret"}, // Client secrets cannot be imported using client id only + }, + // Update the object with the second configuration, check that the client secret is not empty after creation + { + Config: okConfigAuthorizationCode, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrWith(resourceName2, "client_id", apiOauth2ClientStringNotEmpty), + resource.TestCheckResourceAttrWith(resourceName2, "client_secret", apiOauth2ClientStringNotEmpty), + ), + }, + // Verify that state matches the imported resource + { + ResourceName: resourceName2, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"client_secret"}, // Client secrets cannot be imported using client id only + }, + }, + }) +} + +// Test invalid oauth2 clients configurations +func TestAccMeApiOauth2Client_configMissingArguments(t *testing.T) { + const configMissingName = ` + resource "ovh_me_api_oauth2_client" "service_account_1" { + description = "tf acc import test" + flow = "AUTHORIZATION_CODE" + }` + const configMissingDescription = ` + resource "ovh_me_api_oauth2_client" "service_account_1" { + name = "tf acc test authorization code" + flow = "AUTHORIZATION_CODE" + }` + const configMissingFlow = ` + resource "ovh_me_api_oauth2_client" "service_account_1" { + name = "tf acc test authorization code" + description = "tf acc import test" + }` + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheckCredentials(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + // Check that we cannot create a resource with a missing name + { + Config: configMissingName, + ExpectError: regexp.MustCompile("Missing required argument"), + }, + // Check that we cannot create a resource with a missing description + { + Config: configMissingDescription, + ExpectError: regexp.MustCompile("Missing required argument"), + }, + // Check that we cannot create a resource with a missing flow + { + Config: configMissingFlow, + ExpectError: regexp.MustCompile("Missing required argument"), + }, + }, + }) +} + +// Test invalid oauth2 clients import IDs +func TestAccMeApiOauth2Client_importBasic(t *testing.T) { + const resourceName = "ovh_me_api_oauth2_client.service_account_1" + const okConfigClientCredentials = ` + resource "ovh_me_api_oauth2_client" "service_account_1" { + description = "tf acc test client credentials" + name = "tf acc test client credentials" + flow = "CLIENT_CREDENTIALS" + }` + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheckCredentials(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: okConfigClientCredentials, + }, + // Verify that the state matches the resource imported with its client_id and client_secret separated by a pipe + { + ResourceName: resourceName, + ImportStateIdFunc: func(state *terraform.State) (string, error) { + resource_id := state.RootModule().Resources[resourceName].Primary.Attributes["id"] + resource_secret := state.RootModule().Resources[resourceName].Primary.Attributes["client_secret"] + return resource_id + "|" + resource_secret, nil + }, + ImportState: true, + ImportStateVerify: true, + }, + // Check that importing a resource fails when its client_id contains a pipe but is not formatted properly + { + ImportState: true, + ImportStateVerify: true, + ResourceName: resourceName, + ImportStateId: "fake_client|fake_secret|extra_data", + ExpectError: regexp.MustCompile("Resource IDs with the pipe character should be formatted as"), + }, + }, + }) +} diff --git a/ovh/types_me_api_oauth2_client.go b/ovh/types_me_api_oauth2_client.go new file mode 100644 index 000000000..52051181c --- /dev/null +++ b/ovh/types_me_api_oauth2_client.go @@ -0,0 +1,32 @@ +package ovh + +// Request body parameters for a oauth2 client POST request +type ApiOauth2ClientCreateOpts struct { + CallbackUrls []string `json:"callbackUrls"` + Description string `json:"description"` + Flow string `json:"flow"` + Name string `json:"name"` +} + +// Response body parameters from a successful oauth2 client POST request +type ApiOauth2ClientCreateResponse struct { + ClientId string `json:"clientId"` + ClientSecret string `json:"clientSecret"` +} + +// Response body parameters from a successful oauth2 client GET request +type ApiOauth2ClientReadResponse struct { + CallbackUrls []string `json:"callbackUrls"` + ClientId string `json:"clientId"` + Description string `json:"description"` + Flow string `json:"flow"` + Name string `json:"name"` + Identity string `json:"identity"` +} + +// Request body parameters for a oauth2 client PUT request +type ApiOauth2ClientUpdateOpts struct { + CallbackUrls []string `json:"callbackUrls"` + Description string `json:"description"` + Name string `json:"name"` +} diff --git a/website/docs/d/me_api_oauth2_client.markdown b/website/docs/d/me_api_oauth2_client.markdown new file mode 100644 index 000000000..9cf500197 --- /dev/null +++ b/website/docs/d/me_api_oauth2_client.markdown @@ -0,0 +1,29 @@ +--- +subcategory : "Account Management" +--- + +# ovh_me_api_oauth2_client (Data Source) + +Use this data source to retrieve information about an existing OAuth2 service account. + +## Example Usage + +```hcl +data "ovh_me_api_oauth2_client" "my_oauth2_client" { + client_id = "5f8969a993ec8b4b" +} +``` + +## Argument Reference + +* `client_id` - Client ID of an existing OAuth2 service account. + +## Attributes Reference + +* `client_id` - Client ID of the created service account. +* `name` - OAuth2 client name. +* `description` - OAuth2 client description. +* `flow` - The OAuth2 flow to use. `AUTHORIZATION_CODE` or `CLIENT_CREDENTIALS` are supported at the moment. +* `callback_urls` - List of callback urls when configuring the `AUTHORIZATION_CODE` flow. + +The `client_secret` attribute is not supported in the Data Source. If you need this attribute to be in the state, see how to import a `ovh_me_api_oauth2_client` resource instead. \ No newline at end of file diff --git a/website/docs/d/me_api_oauth2_clients.markdown b/website/docs/d/me_api_oauth2_clients.markdown new file mode 100644 index 000000000..1d9014a29 --- /dev/null +++ b/website/docs/d/me_api_oauth2_clients.markdown @@ -0,0 +1,22 @@ +--- +subcategory : "Account Management" +--- + +# ovh_me_api_oauth2_client (Data Source) + +Use this data source to retrieve information the list of existing OAuth2 service account IDs. + +## Example Usage + +```hcl +data "ovh_me_api_oauth2_client" "my_oauth2_clients" { +} +``` + +## Argument Reference + +This datasource takes no arguments. + +## Attributes Reference + +* `client_ids` - The list of all the existing client IDs. diff --git a/website/docs/r/me_api_oauth2_client.html.markdown b/website/docs/r/me_api_oauth2_client.html.markdown new file mode 100644 index 000000000..aaa0df99b --- /dev/null +++ b/website/docs/r/me_api_oauth2_client.html.markdown @@ -0,0 +1,61 @@ +--- +subcategory : "Account Management" +--- + +# ovh_me_api_oauth2_client + +Creates an OAuth2 service account. + +## Example Usage + +An OAuth2 client for an app hosted at `my-app.com`, that uses the authorization code flow to authenticate. + +```hcl +resource "ovh_me_api_oauth2_client" "my_oauth2_client_auth_code" { + name = "OAuth2 authorization code service account" + flow = "AUTHORIZATION_CODE" + description = "An OAuth2 client using the authorization code flow for my-app.com" + callback_urls = ["https://my-app.com/callback"] +} +``` + +An OAuth2 client for an app hosted at `my-app.com`, that uses the client credentials flow to authenticate. + +```hcl +resource "ovh_me_api_oauth2_client" "my_oauth2_client_client_creds" { + name = "client credentials service account" + description = "An OAuth2 client using the client credentials flow for my app" + flow = "CLIENT_CREDENTIALS" +} +``` + +## Argument Reference + +* `name` - OAuth2 client name. +* `description` - OAuth2 client description. +* `flow` - The OAuth2 flow to use. `AUTHORIZATION_CODE` or `CLIENT_CREDENTIALS` are supported at the moment. +* `callback_urls` - List of callback urls when configuring the `AUTHORIZATION_CODE` flow. + +## Attributes Reference + +* `client_id` - Client ID of the created service account. +* `client_secret` - Client secret of the created service account. +* `name` - OAuth2 client name. +* `description` - OAuth2 client description. +* `flow` - The OAuth2 flow to use. `AUTHORIZATION_CODE` or `CLIENT_CREDENTIALS` are supported at the moment. +* `callback_urls` - List of callback urls when configuring the `AUTHORIZATION_CODE` flow. + + +## Import + +OAuth2 clients can be imported using their `client_id`: + +```bash +$ terraform import ovh_me_api_oauth2_client.my_oauth2_client client_id +``` + +Because the client_secret is only available for resources created using terraform, OAuth2 clients can also be imported using a `client_id` and a `client_secret` with a pipe separator: + +```bash +$ terraform import ovh_me_api_oauth2_client.my_oauth2_client 'client_id|client_secret' +```