Repository: dexidp/dex
Pull request #3373 (2024-02-23 15:55:57)

OIDC connector: Allow specifying empty prompt type

<!--
Thank you for sending a pull request! Here are some tips for contributors:

1. Fill the description template below.
2. Sign a DCO (if you haven't already signed it).
3. Include appropriate tests (if necessary). Make sure that all CI checks passed.
4. If the Pull Request is a work in progress, make use of GitHub's "Draft PR" feature and mark it as such.
-->

#### Overview

Enhanced the OIDC connector to allow specifying an empty promptType parameter. Previously, the default behavior always appended 'consent' if promptType was not specified. This adjustment was necessary due to variations in default behaviors across certain Identity Providers (IDPs).

#### What this PR does / why we need it

https://cloud-native.slack.com/archives/C01HF2G1R34/p1708423095710099

#### Special notes for your reviewer



Patch:
diff --git a/connector/oidc/oidc.go b/connector/oidc/oidc.go
index e9486354..c2918006 100644
--- a/connector/oidc/oidc.go
+++ b/connector/oidc/oidc.go
@@ -76,7 +76,7 @@ type Config struct {
 	UserNameKey string `json:"userNameKey"`
 
 	// PromptType will be used fot the prompt parameter (when offline_access, by default prompt=consent)
-	PromptType string `json:"promptType"`
+	PromptType *string `json:"promptType"`
 
 	// OverrideClaimMapping will be used to override the options defined in claimMappings.
 	// i.e. if there are 'email' and `preferred_email` claims available, by default Dex will always use the `email` claim independent of the ClaimMapping.EmailKey.
@@ -242,8 +242,9 @@ func (c *Config) Open(id string, logger log.Logger) (conn connector.Connector, e
 	}
 
 	// PromptType should be "consent" by default, if not set
-	if c.PromptType == "" {
-		c.PromptType = "consent"
+	promptType := "consent"
+	if c.PromptType != nil {
+		promptType = *c.PromptType
 	}
 
 	clientID := c.ClientID
@@ -268,7 +269,7 @@ func (c *Config) Open(id string, logger log.Logger) (conn connector.Connector, e
 		allowedGroups:             c.AllowedGroups,
 		acrValues:                 c.AcrValues,
 		getUserInfo:               c.GetUserInfo,
-		promptType:                c.PromptType,
+		promptType:                promptType,
 		userIDKey:                 c.UserIDKey,
 		userNameKey:               c.UserNameKey,
 		overrideClaimMapping:      c.OverrideClaimMapping,


Test patch:
diff --git a/connector/oidc/oidc_test.go b/connector/oidc/oidc_test.go
index fef2a1a5..e621a55f 100644
--- a/connector/oidc/oidc_test.go
+++ b/connector/oidc/oidc_test.go
@@ -19,6 +19,7 @@ import (
 
 	"github.com/go-jose/go-jose/v4"
 	"github.com/sirupsen/logrus"
+	"github.com/stretchr/testify/require"
 
 	"github.com/dexidp/dex/connector"
 )
@@ -584,6 +585,40 @@ func TestTokenIdentity(t *testing.T) {
 	}
 }
 
+func TestPromptType(t *testing.T) {
+	pointer := func(s string) *string {
+		return &s
+	}
+
+	tests := []struct {
+		name       string
+		promptType *string
+		res        string
+	}{
+		{name: "none", promptType: pointer("none"), res: "none"},
+		{name: "provided empty string", promptType: pointer(""), res: ""},
+		{name: "login", promptType: pointer("login"), res: "login"},
+		{name: "consent", promptType: pointer("consent"), res: "consent"},
+		{name: "default value", promptType: nil, res: "consent"},
+	}
+
+	testServer, err := setupServer(nil, true)
+	require.NoError(t, err)
+
+	for _, tc := range tests {
+		t.Run(tc.name, func(t *testing.T) {
+			conn, err := newConnector(Config{
+				Issuer:     testServer.URL,
+				Scopes:     []string{"openid", "groups"},
+				PromptType: tc.promptType,
+			})
+			require.NoError(t, err)
+
+			require.Equal(t, tc.res, conn.promptType)
+		})
+	}
+}
+
 func TestProviderOverride(t *testing.T) {
 	testServer, err := setupServer(map[string]any{
 		"sub":  "subvalue",