diff --git a/connector/oidc/oidc.go b/connector/oidc/oidc.go index 675e4b95..4c3dc6ce 100644 --- a/connector/oidc/oidc.go +++ b/connector/oidc/oidc.go @@ -55,6 +55,9 @@ type Config struct { // Configurable key which contains the user name claim UserNameKey string `json:"userNameKey"` + // Configurable key which contains the username claims + PreferredUsernameKey string `json:"preferredUsernameKey"` // defaults to "username" + // PromptType will be used fot the prompt parameter (when offline_access, by default prompt=consent) PromptType string `json:"promptType"` } @@ -143,6 +146,7 @@ func (c *Config) Open(id string, logger log.Logger) (conn connector.Connector, e getUserInfo: c.GetUserInfo, userIDKey: c.UserIDKey, userNameKey: c.UserNameKey, + preferredUsernameKey: c.PreferredUsernameKey, promptType: c.PromptType, }, nil } @@ -165,6 +169,7 @@ type oidcConnector struct { getUserInfo bool userIDKey string userNameKey string + preferredUsernameKey string promptType string } @@ -296,6 +301,11 @@ func (c *oidcConnector) createIdentity(ctx context.Context, identity connector.I } hostedDomain, _ := claims["hd"].(string) + if c.preferredUsernameKey == "" { + c.preferredUsernameKey = "username" + } + username, _ := claims[c.preferredUsernameKey].(string) + if len(c.hostedDomains) > 0 { found := false for _, domain := range c.hostedDomains { @@ -320,11 +330,12 @@ func (c *oidcConnector) createIdentity(ctx context.Context, identity connector.I } identity = connector.Identity{ - UserID: idToken.Subject, - Username: name, - Email: email, - EmailVerified: emailVerified, - ConnectorData: connData, + UserID: idToken.Subject, + Username: name, + PreferredUsername: username, + Email: email, + EmailVerified: emailVerified, + ConnectorData: connData, } if c.userIDKey != "" { diff --git a/connector/oidc/oidc_test.go b/connector/oidc/oidc_test.go index 52afa158..b4d939e1 100644 --- a/connector/oidc/oidc_test.go +++ b/connector/oidc/oidc_test.go @@ -49,10 +49,12 @@ func TestHandleCallback(t *testing.T) { name string userIDKey string userNameKey string + preferredUsernameKey string insecureSkipEmailVerified bool scopes []string expectUserID string expectUserName string + expectPreferredUsername string expectedEmailField string token map[string]interface{} }{ @@ -108,6 +110,21 @@ func TestHandleCallback(t *testing.T) { "email_verified": true, }, }, + { + name: "withPreferredUsernameKey", + preferredUsernameKey: "preferred_username", + expectUserID: "subvalue", + expectUserName: "namevalue", + expectPreferredUsername: "usernamevalue", + expectedEmailField: "emailvalue", + token: map[string]interface{}{ + "sub": "subvalue", + "name": "namevalue", + "preferred_username": "usernamevalue", + "email": "emailvalue", + "email_verified": true, + }, + }, { name: "emptyEmailScope", expectUserID: "subvalue", @@ -161,6 +178,7 @@ func TestHandleCallback(t *testing.T) { RedirectURI: fmt.Sprintf("%s/callback", serverURL), UserIDKey: tc.userIDKey, UserNameKey: tc.userNameKey, + PreferredUsernameKey: tc.preferredUsernameKey, InsecureSkipEmailVerified: tc.insecureSkipEmailVerified, BasicAuthUnsupported: &basicAuth, } @@ -182,6 +200,7 @@ func TestHandleCallback(t *testing.T) { expectEquals(t, identity.UserID, tc.expectUserID) expectEquals(t, identity.Username, tc.expectUserName) + expectEquals(t, identity.PreferredUsername, tc.expectPreferredUsername) expectEquals(t, identity.Email, tc.expectedEmailField) expectEquals(t, identity.EmailVerified, true) })