Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/data-sources/client.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ data "auth0_client" "some-client-by-id" {
- `oidc_backchannel_logout_urls` (Set of String) Set of URLs that are valid to call back from Auth0 for OIDC backchannel logout. Currently only one URL is allowed.
- `oidc_conformant` (Boolean) Indicates whether this client will conform to strict OIDC specifications.
- `oidc_logout` (List of Object) Configure OIDC logout for the Client (see [below for nested schema](#nestedatt--oidc_logout))
- `organization_discovery_methods` (List of String) Methods for discovering organizations during the pre_login_prompt. Can include `email` (allows users to find their organization by entering their email address) and/or `organization_name` (requires users to enter the organization name directly). These methods can be combined. Setting this property requires that `organization_require_behavior` is set to `pre_login_prompt`.
- `organization_require_behavior` (String) Defines how to proceed during an authentication transaction when `organization_usage = "require"`. Can be `no_prompt` (default), `pre_login_prompt` or `post_login_prompt`.
- `organization_usage` (String) Defines how to proceed during an authentication transaction with regards to an organization. Can be `deny` (default), `allow` or `require`.
- `refresh_token` (List of Object) Configuration settings for the refresh tokens issued for this client. (see [below for nested schema](#nestedatt--refresh_token))
Expand Down
1 change: 1 addition & 0 deletions docs/data-sources/clients.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ Read-Only:
- `is_token_endpoint_ip_header_trusted` (Boolean)
- `name` (String)
- `oidc_logout` (List of Object) (see [below for nested schema](#nestedobjatt--clients--oidc_logout))
- `organization_discovery_methods` (List of String)
- `resource_server_identifier` (String)
- `session_transfer` (List of Object) (see [below for nested schema](#nestedobjatt--clients--session_transfer))
- `skip_non_verifiable_callback_uri_confirmation_prompt` (String)
Expand Down
1 change: 1 addition & 0 deletions docs/resources/client.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ resource "auth0_client" "my_client" {
- `oidc_backchannel_logout_urls` (Set of String, Deprecated) Set of URLs that are valid to call back from Auth0 for OIDC backchannel logout. Currently only one URL is allowed.
- `oidc_conformant` (Boolean) Indicates whether this client will conform to strict OIDC specifications.
- `oidc_logout` (Block List, Max: 1) Configure OIDC logout for the Client (see [below for nested schema](#nestedblock--oidc_logout))
- `organization_discovery_methods` (List of String) Methods for discovering organizations during the pre_login_prompt. Can include `email` (allows users to find their organization by entering their email address) and/or `organization_name` (requires users to enter the organization name directly). These methods can be combined. Setting this property requires that `organization_require_behavior` is set to `pre_login_prompt`.
- `organization_require_behavior` (String) Defines how to proceed during an authentication transaction when `organization_usage = "require"`. Can be `no_prompt` (default), `pre_login_prompt` or `post_login_prompt`.
- `organization_usage` (String) Defines how to proceed during an authentication transaction with regards to an organization. Can be `deny` (default), `allow` or `require`.
- `refresh_token` (Block List, Max: 1) Configuration settings for the refresh tokens issued for this client. (see [below for nested schema](#nestedblock--refresh_token))
Expand Down
28 changes: 28 additions & 0 deletions docs/resources/organization_discovery_domain.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---
page_title: "Resource: auth0_organization_discovery_domain"
description: |-
Manage organization discovery domains for Home Realm Discovery. These domains help automatically route users to the correct organization based on their email domain.
---

# Resource: auth0_organization_discovery_domain

Manage organization discovery domains for Home Realm Discovery. These domains help automatically route users to the correct organization based on their email domain.



<!-- schema generated by tfplugindocs -->
## Schema

### Required

- `domain` (String) The domain name for organization discovery.
- `organization_id` (String) The ID of the organization.
- `status` (String) Verification status. Must be either 'pending' or 'verified'.

### Read-Only

- `id` (String) The ID of the discovery domain.
- `verification_host` (String) The full domain where the TXT record should be added.
- `verification_txt` (String) TXT record value for domain verification.


39 changes: 39 additions & 0 deletions docs/resources/organization_discovery_domains.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
---
page_title: "Resource: auth0_organization_discovery_domains"
description: |-
With this resource, you can manage discovery domains on an organization.
---

# Resource: auth0_organization_discovery_domains

With this resource, you can manage discovery domains on an organization.



<!-- schema generated by tfplugindocs -->
## Schema

### Required

- `discovery_domains` (Block Set, Min: 1) Discovery domains that are configured for the organization. (see [below for nested schema](#nestedblock--discovery_domains))
- `organization_id` (String) ID of the organization on which to manage the discovery domains.

### Read-Only

- `id` (String) The ID of this resource.

<a id="nestedblock--discovery_domains"></a>
### Nested Schema for `discovery_domains`

Required:

- `domain` (String) The domain name for organization discovery.
- `status` (String) Verification status. Must be either 'pending' or 'verified'.

Read-Only:

- `id` (String) The ID of the discovery domain.
- `verification_host` (String) The full domain where the TXT record should be added.
- `verification_txt` (String) TXT record value for domain verification.


2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ toolchain go1.24.7

require (
github.com/PuerkitoBio/rehttp v1.4.0
github.com/auth0/go-auth0 v1.30.0
github.com/auth0/go-auth0 v1.30.1-0.20251016080035-af408378465e
github.com/google/go-cmp v0.7.0
github.com/hashicorp/go-cty v1.5.0
github.com/hashicorp/go-multierror v1.1.1
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI=
github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/auth0/go-auth0 v1.30.0 h1:LZUWkvhyvaqzRYjP+mywc3141cP7bI6EsjaUX0t+mcw=
github.com/auth0/go-auth0 v1.30.0/go.mod h1:32sQB1uAn+99fJo6N819EniKq8h785p0ag0lMWhiTaE=
github.com/auth0/go-auth0 v1.30.1-0.20251016080035-af408378465e h1:u9DjX/L2elmJSN2+dM2jOiczUX0fxtIEpwkBgyZEoXU=
github.com/auth0/go-auth0 v1.30.1-0.20251016080035-af408378465e/go.mod h1:32sQB1uAn+99fJo6N819EniKq8h785p0ag0lMWhiTaE=
github.com/aybabtme/iocontrol v0.0.0-20150809002002-ad15bcfc95a0 h1:0NmehRCgyk5rljDQLKUO+cRJCnduDyn11+zGZIc9Z48=
github.com/aybabtme/iocontrol v0.0.0-20150809002002-ad15bcfc95a0/go.mod h1:6L7zgvqo0idzI7IO8de6ZC051AfXb5ipkIJ7bIA2tGA=
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
Expand Down
1 change: 1 addition & 0 deletions internal/auth0/client/expand.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ func expandClient(data *schema.ResourceData) (*management.Client, error) {
GrantTypes: value.Strings(config.GetAttr("grant_types")),
OrganizationUsage: value.String(config.GetAttr("organization_usage")),
OrganizationRequireBehavior: value.String(config.GetAttr("organization_require_behavior")),
OrganizationDiscoveryMethods: value.Strings(config.GetAttr("organization_discovery_methods")),
WebOrigins: value.Strings(config.GetAttr("web_origins")),
RequirePushedAuthorizationRequests: value.Bool(config.GetAttr("require_pushed_authorization_requests")),
SSO: value.Bool(config.GetAttr("sso")),
Expand Down
1 change: 1 addition & 0 deletions internal/auth0/client/flatten.go
Original file line number Diff line number Diff line change
Expand Up @@ -617,6 +617,7 @@ func flattenClient(data *schema.ResourceData, client *management.Client) error {
data.Set("grant_types", client.GetGrantTypes()),
data.Set("organization_usage", client.GetOrganizationUsage()),
data.Set("organization_require_behavior", client.GetOrganizationRequireBehavior()),
data.Set("organization_discovery_methods", client.GetOrganizationDiscoveryMethods()),
data.Set("web_origins", client.GetWebOrigins()),
data.Set("sso", client.GetSSO()),
data.Set("sso_disabled", client.GetSSODisabled()),
Expand Down
15 changes: 15 additions & 0 deletions internal/auth0/client/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,21 @@ func NewResource() *schema.Resource {
Description: "Defines how to proceed during an authentication transaction when " +
"`organization_usage = \"require\"`. Can be `no_prompt` (default), `pre_login_prompt` or `post_login_prompt`.",
},
"organization_discovery_methods": {
Type: schema.TypeList,
Elem: &schema.Schema{
Type: schema.TypeString,
ValidateFunc: validation.StringInSlice([]string{
"email", "organization_name",
}, false),
},
Optional: true,
Description: "Methods for discovering organizations during the pre_login_prompt. " +
"Can include `email` (allows users to find their organization by entering their email address) " +
"and/or `organization_name` (requires users to enter the organization name directly). " +
"These methods can be combined. Setting this property requires that " +
"`organization_require_behavior` is set to `pre_login_prompt`.",
},
"allowed_origins": {
Type: schema.TypeList,
Elem: &schema.Schema{Type: schema.TypeString},
Expand Down
30 changes: 30 additions & 0 deletions internal/auth0/organization/expand.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,33 @@ func fetchNullableFields(data *schema.ResourceData) map[string]interface{} {

return nullableMap
}

func expandOrganizationDiscoveryDomain(data *schema.ResourceData) *management.OrganizationDiscoveryDomain {
cfg := data.GetRawConfig()

return &management.OrganizationDiscoveryDomain{
Domain: value.String(cfg.GetAttr("domain")),
Status: value.String(cfg.GetAttr("status")),
// Note: ID, VerificationTXT, and VerificationHost are read-only and should not be sent to the API.
}
}

func expandOrganizationDiscoveryDomainFromConfig(domainCfg cty.Value) *management.OrganizationDiscoveryDomain {
return &management.OrganizationDiscoveryDomain{
Domain: value.String(domainCfg.GetAttr("domain")),
Status: value.String(domainCfg.GetAttr("status")),
// Note: ID, VerificationTXT, and VerificationHost are read-only and should not be sent to the API.
}
}

func expandOrganizationDiscoveryDomains(cfg cty.Value) []*management.OrganizationDiscoveryDomain {
domains := make([]*management.OrganizationDiscoveryDomain, 0)

cfg.ForEachElement(func(_ cty.Value, domainCfg cty.Value) (stop bool) {
domains = append(domains, expandOrganizationDiscoveryDomainFromConfig(domainCfg))

return stop
})

return domains
}
32 changes: 32 additions & 0 deletions internal/auth0/organization/flatten.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,3 +129,35 @@ func flattenOrganizationClientGrantsSlice(clientGrants []*management.ClientGrant
}
return flattenedClientGrants
}

func flattenOrganizationDiscoveryDomain(data *schema.ResourceData, discoveryDomain *management.OrganizationDiscoveryDomain, organizationID string) error {
result := multierror.Append(
data.Set("organization_id", organizationID),
data.Set("id", discoveryDomain.GetID()),
data.Set("domain", discoveryDomain.GetDomain()),
data.Set("status", discoveryDomain.GetStatus()),
data.Set("verification_txt", discoveryDomain.GetVerificationTXT()),
data.Set("verification_host", discoveryDomain.GetVerificationHost()),
)

return result.ErrorOrNil()
}

func flattenOrganizationDiscoveryDomains(data *schema.ResourceData, domains []*management.OrganizationDiscoveryDomain) error {
if len(domains) == 0 {
return data.Set("discovery_domains", []interface{}{})
}

var enabledDomains []interface{}
for _, domain := range domains {
enabledDomains = append(enabledDomains, map[string]interface{}{
"id": domain.GetID(),
"domain": domain.GetDomain(),
"status": domain.GetStatus(),
"verification_txt": domain.GetVerificationTXT(),
"verification_host": domain.GetVerificationHost(),
})
}

return data.Set("discovery_domains", enabledDomains)
}
136 changes: 136 additions & 0 deletions internal/auth0/organization/resource_discovery_domain.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
package organization

import (
"context"
"fmt"
"strings"

"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"

"github.com/auth0/terraform-provider-auth0/internal/config"
internalError "github.com/auth0/terraform-provider-auth0/internal/error"
internalSchema "github.com/auth0/terraform-provider-auth0/internal/schema"
)

// NewDiscoveryDomainResource will return a new auth0_organization_discovery_domain resource.
func NewDiscoveryDomainResource() *schema.Resource {
return &schema.Resource{
CreateContext: createOrganizationDiscoveryDomain,
ReadContext: readOrganizationDiscoveryDomain,
UpdateContext: updateOrganizationDiscoveryDomain,
DeleteContext: deleteOrganizationDiscoveryDomain,
Importer: &schema.ResourceImporter{
StateContext: internalSchema.ImportResourceGroupID("organization_id", "id"),
},
Description: "Manage organization discovery domains for Home Realm Discovery. These domains help automatically route users to the correct organization based on their email domain.",
Schema: map[string]*schema.Schema{
"organization_id": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
Description: "The ID of the organization.",
},
"id": {
Type: schema.TypeString,
Computed: true,
Description: "The ID of the discovery domain.",
},
"domain": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
Description: "The domain name for organization discovery.",
},
"status": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.StringInSlice([]string{"pending", "verified"}, false),
Description: "Verification status. Must be either 'pending' or 'verified'.",
},
"verification_txt": {
Type: schema.TypeString,
Computed: true,
Description: "TXT record value for domain verification.",
},
"verification_host": {
Type: schema.TypeString,
Computed: true,
Description: "The full domain where the TXT record should be added.",
},
},
}
}

func createOrganizationDiscoveryDomain(ctx context.Context, data *schema.ResourceData, meta interface{}) diag.Diagnostics {
api := meta.(*config.Config).GetAPI()

organizationID := data.Get("organization_id").(string)
discoveryDomain := expandOrganizationDiscoveryDomain(data)

if err := api.Organization.CreateDiscoveryDomain(ctx, organizationID, discoveryDomain); err != nil {
return diag.FromErr(err)
}

internalSchema.SetResourceGroupID(data, organizationID, discoveryDomain.GetID())

return readOrganizationDiscoveryDomain(ctx, data, meta)
}

func readOrganizationDiscoveryDomain(ctx context.Context, data *schema.ResourceData, meta interface{}) diag.Diagnostics {
api := meta.(*config.Config).GetAPI()

organizationID, domainID, err := parseOrganizationDiscoveryDomainID(data.Id())
if err != nil {
return diag.FromErr(err)
}

discoveryDomain, err := api.Organization.DiscoveryDomain(ctx, organizationID, domainID)
if err != nil {
return diag.FromErr(internalError.HandleAPIError(data, err))
}

return diag.FromErr(flattenOrganizationDiscoveryDomain(data, discoveryDomain, organizationID))
}

func updateOrganizationDiscoveryDomain(ctx context.Context, data *schema.ResourceData, meta interface{}) diag.Diagnostics {
api := meta.(*config.Config).GetAPI()

organizationID, domainID, err := parseOrganizationDiscoveryDomainID(data.Id())
if err != nil {
return diag.FromErr(err)
}

discoveryDomain := expandOrganizationDiscoveryDomain(data)

if err := api.Organization.UpdateDiscoveryDomain(ctx, organizationID, domainID, discoveryDomain); err != nil {
return diag.FromErr(internalError.HandleAPIError(data, err))
}

return readOrganizationDiscoveryDomain(ctx, data, meta)
}

func deleteOrganizationDiscoveryDomain(ctx context.Context, data *schema.ResourceData, meta interface{}) diag.Diagnostics {
api := meta.(*config.Config).GetAPI()

organizationID, domainID, err := parseOrganizationDiscoveryDomainID(data.Id())
if err != nil {
return diag.FromErr(err)
}

if err := api.Organization.DeleteDiscoveryDomain(ctx, organizationID, domainID); err != nil {
return diag.FromErr(internalError.HandleAPIError(data, err))
}

return nil
}

// parseOrganizationDiscoveryDomainID parses the resource ID in format "organization_id::id".
func parseOrganizationDiscoveryDomainID(id string) (organizationID, domainID string, err error) {
parts := strings.Split(id, "::")
if len(parts) != 2 {
return "", "", fmt.Errorf("invalid organization discovery domain ID format: %s, expected format: organization_id::id", id)
}
return parts[0], parts[1], nil
}
Loading
Loading