Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Passkey Support #1099

Open
wants to merge 16 commits into
base: main
Choose a base branch
from
Open
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
37 changes: 37 additions & 0 deletions docs/data-sources/connection.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ Read-Only:
- `attribute_map` (List of Object) (see [below for nested schema](#nestedobjatt--options--attribute_map))
- `attributes` (List of Object) (see [below for nested schema](#nestedobjatt--options--attributes))
- `auth_params` (Map of String)
- `authentication_methods` (List of Object) (see [below for nested schema](#nestedobjatt--options--authentication_methods))
- `authorization_endpoint` (String)
- `brute_force_protection` (Boolean)
- `client_id` (String)
Expand Down Expand Up @@ -97,6 +98,7 @@ Read-Only:
- `mfa` (List of Object) (see [below for nested schema](#nestedobjatt--options--mfa))
- `name` (String)
- `non_persistent_attrs` (Set of String)
- `passkey_options` (List of Object) (see [below for nested schema](#nestedobjatt--options--passkey_options))
- `password_complexity_options` (List of Object) (see [below for nested schema](#nestedobjatt--options--password_complexity_options))
- `password_dictionary` (List of Object) (see [below for nested schema](#nestedobjatt--options--password_dictionary))
- `password_history` (List of Object) (see [below for nested schema](#nestedobjatt--options--password_history))
Expand Down Expand Up @@ -276,6 +278,31 @@ Read-Only:



<a id="nestedobjatt--options--authentication_methods"></a>
### Nested Schema for `options.authentication_methods`

Read-Only:

- `passkey` (List of Object) (see [below for nested schema](#nestedobjatt--options--authentication_methods--passkey))
- `password` (List of Object) (see [below for nested schema](#nestedobjatt--options--authentication_methods--password))

<a id="nestedobjatt--options--authentication_methods--passkey"></a>
### Nested Schema for `options.authentication_methods.passkey`

Read-Only:

- `enabled` (Boolean)


<a id="nestedobjatt--options--authentication_methods--password"></a>
### Nested Schema for `options.authentication_methods.password`

Read-Only:

- `enabled` (Boolean)



<a id="nestedobjatt--options--connection_settings"></a>
### Nested Schema for `options.connection_settings`

Expand Down Expand Up @@ -325,6 +352,16 @@ Read-Only:
- `return_enroll_settings` (Boolean)


<a id="nestedobjatt--options--passkey_options"></a>
### Nested Schema for `options.passkey_options`

Read-Only:

- `challenge_ui` (String)
- `local_enrollment_enabled` (Boolean)
- `progressive_enrollment_enabled` (Boolean)


<a id="nestedobjatt--options--password_complexity_options"></a>
### Nested Schema for `options.password_complexity_options`

Expand Down
51 changes: 51 additions & 0 deletions docs/resources/connection.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,20 @@ resource "auth0_connection" "my_connection" {
active = true
return_enroll_settings = true
}
authentication_methods {
passkey {
enabled = true
}
password {
enabled = true
}
}
passkey_options {
challenge_ui = "both"
local_enrollment_enabled = true
progressive_enrollment_enabled = true
}
}
}
```
Expand Down Expand Up @@ -672,6 +686,7 @@ Optional:
- `attribute_map` (Block List, Max: 1) OpenID Connect and Okta Workforce connections can automatically map claims received from the identity provider (IdP). You can configure this mapping through a library template provided by Auth0 or by entering your own template directly. Click [here](https://auth0.com/docs/authenticate/identity-providers/enterprise-identity-providers/configure-pkce-claim-mapping-for-oidc#map-claims-for-oidc-connections) for more info. (see [below for nested schema](#nestedblock--options--attribute_map))
- `attributes` (Block List) Order of attributes for precedence in identification.Valid values: email, phone_number, username. If Precedence is set, it must contain all values (email, phone_number, username) in specific order (see [below for nested schema](#nestedblock--options--attributes))
- `auth_params` (Map of String) Query string parameters to be included as part of the generated passwordless email link.
- `authentication_methods` (Block List) Specifies the authentication methods and their configuration (enabled or disabled) (see [below for nested schema](#nestedblock--options--authentication_methods))
- `authorization_endpoint` (String) Authorization endpoint.
- `brute_force_protection` (Boolean) Indicates whether to enable brute force protection, which will limit the number of signups and failed logins from a suspicious IP address.
- `client_id` (String) The strategy's client ID.
Expand Down Expand Up @@ -715,6 +730,7 @@ Optional:
- `mfa` (Block List, Max: 1) Configuration options for multifactor authentication. (see [below for nested schema](#nestedblock--options--mfa))
- `name` (String) The public name of the email or SMS Connection. In most cases this is the same name as the connection name.
- `non_persistent_attrs` (Set of String) If there are user fields that should not be stored in Auth0 databases due to privacy reasons, you can add them to the DenyList here.
- `passkey_options` (Block List, Max: 1) Defines options for the passkey authentication method (see [below for nested schema](#nestedblock--options--passkey_options))
- `password_complexity_options` (Block List, Max: 1) Configuration settings for password complexity. (see [below for nested schema](#nestedblock--options--password_complexity_options))
- `password_dictionary` (Block List, Max: 1) Configuration settings for the password dictionary check, which does not allow passwords that are part of the password dictionary. (see [below for nested schema](#nestedblock--options--password_dictionary))
- `password_history` (Block List) Configuration settings for the password history that is maintained for each user to prevent the reuse of passwords. (see [below for nested schema](#nestedblock--options--password_history))
Expand Down Expand Up @@ -897,6 +913,31 @@ Optional:



<a id="nestedblock--options--authentication_methods"></a>
### Nested Schema for `options.authentication_methods`

Optional:

- `passkey` (Block List, Max: 1) Configures passkey authentication (see [below for nested schema](#nestedblock--options--authentication_methods--passkey))
- `password` (Block List, Max: 1) Configures password authentication (see [below for nested schema](#nestedblock--options--authentication_methods--password))

<a id="nestedblock--options--authentication_methods--passkey"></a>
### Nested Schema for `options.authentication_methods.passkey`

Optional:

- `enabled` (Boolean) Enables passkey authentication


<a id="nestedblock--options--authentication_methods--password"></a>
### Nested Schema for `options.authentication_methods.password`

Optional:

- `enabled` (Boolean) Enables password authentication



<a id="nestedblock--options--connection_settings"></a>
### Nested Schema for `options.connection_settings`

Expand Down Expand Up @@ -946,6 +987,16 @@ Optional:
- `return_enroll_settings` (Boolean) Indicates whether multifactor authentication enrollment settings will be returned.


<a id="nestedblock--options--passkey_options"></a>
### Nested Schema for `options.passkey_options`

Optional:

- `challenge_ui` (String) Controls the UI used to challenge the user for their passkey
- `local_enrollment_enabled` (Boolean) Enables or disables enrollment prompt for local passkey when user authenticates using a cross-device passkey for the connection
- `progressive_enrollment_enabled` (Boolean) Enables or disables progressive enrollment of passkeys for the connection


<a id="nestedblock--options--password_complexity_options"></a>
### Nested Schema for `options.password_complexity_options`

Expand Down
14 changes: 14 additions & 0 deletions examples/resources/auth0_connection/resource.tf
Original file line number Diff line number Diff line change
Expand Up @@ -63,5 +63,19 @@ resource "auth0_connection" "my_connection" {
active = true
return_enroll_settings = true
}

authentication_methods {
passkey {
enabled = true
}
password {
enabled = true
}
}
passkey_options {
challenge_ui = "both"
local_enrollment_enabled = true
progressive_enrollment_enabled = true
}
}
}
67 changes: 67 additions & 0 deletions internal/auth0/connection/expand.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,65 @@ func expandConnectionOptionsGitHub(data *schema.ResourceData, config cty.Value)
return options, diag.FromErr(err)
}

func expandConnectionOptionsAuthenticationMethods(config cty.Value) *management.AuthenticationMethods {
var authMethods *management.AuthenticationMethods
config.ForEachElement(
func(_ cty.Value, attributes cty.Value) (stop bool) {
authMethods = &management.AuthenticationMethods{}

authMethods.Password = expandConnectionOptionsAuthenticationMethodsPassword(attributes.GetAttr("password"))
authMethods.Passkey = expandConnectionOptionsAuthenticationMethodsPasskey(attributes.GetAttr("passkey"))

return stop
})
return authMethods
}

func expandConnectionOptionsAuthenticationMethodsPassword(config cty.Value) *management.PasswordAuthenticationMethod {
var passwordAuth *management.PasswordAuthenticationMethod
config.ForEachElement(
func(_ cty.Value, attributes cty.Value) (stop bool) {
passwordAuth = &management.PasswordAuthenticationMethod{
Enabled: value.Bool(attributes.GetAttr("enabled")),
}
return stop
})
return passwordAuth
}

func expandConnectionOptionsAuthenticationMethodsPasskey(config cty.Value) *management.PasskeyAuthenticationMethod {
var passkeyAuth *management.PasskeyAuthenticationMethod
config.ForEachElement(
func(_ cty.Value, attributes cty.Value) (stop bool) {
passkeyAuth = &management.PasskeyAuthenticationMethod{
Enabled: value.Bool(attributes.GetAttr("enabled")),
}
return stop
})
return passkeyAuth
}

func expandConnectionOptionsPasskeyOptions(config cty.Value) *management.PasskeyOptions {
var passkeyOptions *management.PasskeyOptions
config.ForEachElement(
func(_ cty.Value, attributes cty.Value) (stop bool) {
passkeyOptions = &management.PasskeyOptions{}

if attributes.Type().HasAttribute("challenge_ui") {
passkeyOptions.ChallengeUI = value.String(attributes.GetAttr("challenge_ui"))
}
if attributes.Type().HasAttribute("local_enrollment_enabled") {
passkeyOptions.LocalEnrollmentEnabled = value.Bool(attributes.GetAttr("local_enrollment_enabled"))
}
if attributes.Type().HasAttribute("progressive_enrollment_enabled") {
passkeyOptions.ProgressiveEnrollmentEnabled = value.Bool(attributes.GetAttr("progressive_enrollment_enabled"))
}

return stop
})
return passkeyOptions
}

func expandConnectionOptionsAttributes(config cty.Value) *management.ConnectionOptionsAttributes {
var coa *management.ConnectionOptionsAttributes
config.ForEachElement(
Expand Down Expand Up @@ -445,6 +504,14 @@ func expandConnectionOptionsAuth0(_ *schema.ResourceData, config cty.Value) (int
},
)

if config.Type().HasAttribute("authentication_methods") && !config.GetAttr("authentication_methods").IsNull() {
options.AuthenticationMethods = expandConnectionOptionsAuthenticationMethods(config.GetAttr("authentication_methods"))
}

if config.Type().HasAttribute("passkey_options") && !config.GetAttr("passkey_options").IsNull() {
options.PasskeyOptions = expandConnectionOptionsPasskeyOptions(config.GetAttr("passkey_options"))
}

var err error
options.UpstreamParams, err = value.MapFromJSON(config.GetAttr("upstream_params"))

Expand Down
55 changes: 55 additions & 0 deletions internal/auth0/connection/flatten.go
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,53 @@ func flattenPhoneNumberAttribute(phoneNumberAttribute *management.ConnectionOpti
}
}

func flattenAuthenticationMethods(authenticationMethods *management.AuthenticationMethods) interface{} {
if authenticationMethods == nil {
return nil
}

return map[string]interface{}{
"passkey": flattenAuthenticationMethodPasskey(authenticationMethods.Passkey),
"password": flattenAuthenticationMethodPassword(authenticationMethods.Password),
}
}

func flattenPasskeyOptions(passkeyOptions *management.PasskeyOptions) interface{} {
if passkeyOptions == nil {
return nil
}

return map[string]interface{}{
"challenge_ui": passkeyOptions.GetChallengeUI(),
"local_enrollment_enabled": passkeyOptions.GetLocalEnrollmentEnabled(),
"progressive_enrollment_enabled": passkeyOptions.GetProgressiveEnrollmentEnabled(),
}
}

func flattenAuthenticationMethodPasskey(passkeyAuthenticationMethod *management.PasskeyAuthenticationMethod) interface{} {
if passkeyAuthenticationMethod == nil {
return nil
}

return []map[string]bool{
{
"enabled": *passkeyAuthenticationMethod.Enabled,
},
}
}

func flattenAuthenticationMethodPassword(passwordAuthenticationMethod *management.PasswordAuthenticationMethod) interface{} {
if passwordAuthenticationMethod == nil {
return nil
}

return []map[string]bool{
{
"enabled": *passwordAuthenticationMethod.Enabled,
},
}
}

func flattenIdentifier(identifier *management.ConnectionOptionsAttributeIdentifier) []map[string]interface{} {
if identifier == nil {
return nil
Expand Down Expand Up @@ -330,6 +377,14 @@ func flattenConnectionOptionsAuth0(
optionsMap["attributes"] = []interface{}{flattenAttributes(options.GetAttributes())}
}

if options.AuthenticationMethods != nil {
optionsMap["authentication_methods"] = []interface{}{flattenAuthenticationMethods(options.GetAuthenticationMethods())}
}

if options.PasskeyOptions != nil {
optionsMap["passkey_options"] = []interface{}{flattenPasskeyOptions(options.GetPasskeyOptions())}
}

if options.PasswordComplexityOptions != nil {
optionsMap["password_complexity_options"] = []interface{}{options.PasswordComplexityOptions}
}
Expand Down
18 changes: 18 additions & 0 deletions internal/auth0/connection/resource_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ func TestAccConnection(t *testing.T) {
resource.TestCheckResourceAttr("auth0_connection.my_connection", "options.0.non_persistent_attrs.#", "2"),
resource.TestCheckTypeSetElemAttr("auth0_connection.my_connection", "options.0.non_persistent_attrs.*", "hair_color"),
resource.TestCheckTypeSetElemAttr("auth0_connection.my_connection", "options.0.non_persistent_attrs.*", "gender"),
resource.TestCheckResourceAttr("auth0_connection.my_connection", "options.0.authentication_methods.0.password.0.enabled", "true"),
resource.TestCheckResourceAttr("auth0_connection.my_connection", "options.0.authentication_methods.0.passkey.0.enabled", "false"),
resource.TestCheckResourceAttr("auth0_connection.my_connection", "options.0.passkey_options.0.challenge_ui", "both"),
resource.TestCheckResourceAttr("auth0_connection.my_connection", "options.0.passkey_options.0.local_enrollment_enabled", "true"),
resource.TestCheckResourceAttr("auth0_connection.my_connection", "options.0.passkey_options.0.progressive_enrollment_enabled", "true"),
),
},
{
Expand Down Expand Up @@ -117,6 +122,19 @@ resource "auth0_connection" "my_connection" {
}
})
non_persistent_attrs = ["gender","hair_color"]
authentication_methods {
passkey {
enabled = false
}
password {
enabled = true
}
}
passkey_options {
challenge_ui = "both"
local_enrollment_enabled = true
progressive_enrollment_enabled = true
}
}
}
`
Expand Down
Loading