Browse Source

oidc: allow to configure oauth2 scopes

Signed-off-by: Nicola Murino <[email protected]>
Nicola Murino 3 years ago
parent
commit
6b995db864
9 changed files with 49 additions and 10 deletions
  1. 7 0
      config/config.go
  2. 6 0
      config/config_test.go
  3. 1 0
      docs/full-configuration.md
  4. 10 3
      docs/oidc.md
  5. 2 2
      go.mod
  6. 4 4
      go.sum
  7. 8 1
      httpd/oidc.go
  8. 6 0
      httpd/oidc_test.go
  9. 5 0
      sftpgo.json

+ 7 - 0
config/config.go

@@ -105,6 +105,7 @@ var (
 			UsernameField:   "",
 			UsernameField:   "",
 			RoleField:       "",
 			RoleField:       "",
 			ImplicitRoles:   false,
 			ImplicitRoles:   false,
+			Scopes:          []string{"openid", "profile", "email"},
 			CustomFields:    []string{},
 			CustomFields:    []string{},
 		},
 		},
 		Security: httpd.SecurityConf{
 		Security: httpd.SecurityConf{
@@ -1408,6 +1409,12 @@ func getHTTPDOIDCFromEnv(idx int) (httpd.OIDC, bool) {
 		isSet = true
 		isSet = true
 	}
 	}
 
 
+	scopes, ok := lookupStringListFromEnv(fmt.Sprintf("SFTPGO_HTTPD__BINDINGS__%v__OIDC__SCOPES", idx))
+	if ok {
+		result.Scopes = scopes
+		isSet = true
+	}
+
 	roleField, ok := os.LookupEnv(fmt.Sprintf("SFTPGO_HTTPD__BINDINGS__%v__OIDC__ROLE_FIELD", idx))
 	roleField, ok := os.LookupEnv(fmt.Sprintf("SFTPGO_HTTPD__BINDINGS__%v__OIDC__ROLE_FIELD", idx))
 	if ok {
 	if ok {
 		result.RoleField = roleField
 		result.RoleField = roleField

+ 6 - 0
config/config_test.go

@@ -1060,6 +1060,7 @@ func TestHTTPDBindingsFromEnv(t *testing.T) {
 	os.Setenv("SFTPGO_HTTPD__BINDINGS__2__OIDC__REDIRECT_BASE_URL", "redirect base url")
 	os.Setenv("SFTPGO_HTTPD__BINDINGS__2__OIDC__REDIRECT_BASE_URL", "redirect base url")
 	os.Setenv("SFTPGO_HTTPD__BINDINGS__2__OIDC__USERNAME_FIELD", "preferred_username")
 	os.Setenv("SFTPGO_HTTPD__BINDINGS__2__OIDC__USERNAME_FIELD", "preferred_username")
 	os.Setenv("SFTPGO_HTTPD__BINDINGS__2__OIDC__ROLE_FIELD", "sftpgo_role")
 	os.Setenv("SFTPGO_HTTPD__BINDINGS__2__OIDC__ROLE_FIELD", "sftpgo_role")
+	os.Setenv("SFTPGO_HTTPD__BINDINGS__2__OIDC__SCOPES", "openid")
 	os.Setenv("SFTPGO_HTTPD__BINDINGS__2__OIDC__IMPLICIT_ROLES", "1")
 	os.Setenv("SFTPGO_HTTPD__BINDINGS__2__OIDC__IMPLICIT_ROLES", "1")
 	os.Setenv("SFTPGO_HTTPD__BINDINGS__2__OIDC__CUSTOM_FIELDS", "field1,field2")
 	os.Setenv("SFTPGO_HTTPD__BINDINGS__2__OIDC__CUSTOM_FIELDS", "field1,field2")
 	os.Setenv("SFTPGO_HTTPD__BINDINGS__2__SECURITY__ENABLED", "true")
 	os.Setenv("SFTPGO_HTTPD__BINDINGS__2__SECURITY__ENABLED", "true")
@@ -1124,6 +1125,7 @@ func TestHTTPDBindingsFromEnv(t *testing.T) {
 		os.Unsetenv("SFTPGO_HTTPD__BINDINGS__2__OIDC__REDIRECT_BASE_URL")
 		os.Unsetenv("SFTPGO_HTTPD__BINDINGS__2__OIDC__REDIRECT_BASE_URL")
 		os.Unsetenv("SFTPGO_HTTPD__BINDINGS__2__OIDC__USERNAME_FIELD")
 		os.Unsetenv("SFTPGO_HTTPD__BINDINGS__2__OIDC__USERNAME_FIELD")
 		os.Unsetenv("SFTPGO_HTTPD__BINDINGS__2__OIDC__ROLE_FIELD")
 		os.Unsetenv("SFTPGO_HTTPD__BINDINGS__2__OIDC__ROLE_FIELD")
+		os.Unsetenv("SFTPGO_HTTPD__BINDINGS__2__OIDC__SCOPES")
 		os.Unsetenv("SFTPGO_HTTPD__BINDINGS__2__OIDC__IMPLICIT_ROLES")
 		os.Unsetenv("SFTPGO_HTTPD__BINDINGS__2__OIDC__IMPLICIT_ROLES")
 		os.Unsetenv("SFTPGO_HTTPD__BINDINGS__2__OIDC__CUSTOM_FIELDS")
 		os.Unsetenv("SFTPGO_HTTPD__BINDINGS__2__OIDC__CUSTOM_FIELDS")
 		os.Unsetenv("SFTPGO_HTTPD__BINDINGS__2__SECURITY__ENABLED")
 		os.Unsetenv("SFTPGO_HTTPD__BINDINGS__2__SECURITY__ENABLED")
@@ -1173,6 +1175,7 @@ func TestHTTPDBindingsFromEnv(t *testing.T) {
 	require.Equal(t, 0, bindings[0].HideLoginURL)
 	require.Equal(t, 0, bindings[0].HideLoginURL)
 	require.False(t, bindings[0].Security.Enabled)
 	require.False(t, bindings[0].Security.Enabled)
 	require.Equal(t, 0, bindings[0].ClientIPHeaderDepth)
 	require.Equal(t, 0, bindings[0].ClientIPHeaderDepth)
+	require.Len(t, bindings[0].OIDC.Scopes, 3)
 	require.Equal(t, 8000, bindings[1].Port)
 	require.Equal(t, 8000, bindings[1].Port)
 	require.Equal(t, "127.0.0.1", bindings[1].Address)
 	require.Equal(t, "127.0.0.1", bindings[1].Address)
 	require.False(t, bindings[1].EnableHTTPS)
 	require.False(t, bindings[1].EnableHTTPS)
@@ -1183,6 +1186,7 @@ func TestHTTPDBindingsFromEnv(t *testing.T) {
 	require.Nil(t, bindings[1].TLSCipherSuites)
 	require.Nil(t, bindings[1].TLSCipherSuites)
 	require.Equal(t, 1, bindings[1].HideLoginURL)
 	require.Equal(t, 1, bindings[1].HideLoginURL)
 	require.Empty(t, bindings[1].OIDC.ClientID)
 	require.Empty(t, bindings[1].OIDC.ClientID)
+	require.Len(t, bindings[1].OIDC.Scopes, 3)
 	require.False(t, bindings[1].Security.Enabled)
 	require.False(t, bindings[1].Security.Enabled)
 	require.Equal(t, "Web Admin", bindings[1].Branding.WebAdmin.Name)
 	require.Equal(t, "Web Admin", bindings[1].Branding.WebAdmin.Name)
 	require.Equal(t, "WebClient", bindings[1].Branding.WebClient.ShortName)
 	require.Equal(t, "WebClient", bindings[1].Branding.WebClient.ShortName)
@@ -1213,6 +1217,8 @@ func TestHTTPDBindingsFromEnv(t *testing.T) {
 	require.Equal(t, "redirect base url", bindings[2].OIDC.RedirectBaseURL)
 	require.Equal(t, "redirect base url", bindings[2].OIDC.RedirectBaseURL)
 	require.Equal(t, "preferred_username", bindings[2].OIDC.UsernameField)
 	require.Equal(t, "preferred_username", bindings[2].OIDC.UsernameField)
 	require.Equal(t, "sftpgo_role", bindings[2].OIDC.RoleField)
 	require.Equal(t, "sftpgo_role", bindings[2].OIDC.RoleField)
+	require.Len(t, bindings[2].OIDC.Scopes, 1)
+	require.Equal(t, "openid", bindings[2].OIDC.Scopes[0])
 	require.True(t, bindings[2].OIDC.ImplicitRoles)
 	require.True(t, bindings[2].OIDC.ImplicitRoles)
 	require.Len(t, bindings[2].OIDC.CustomFields, 2)
 	require.Len(t, bindings[2].OIDC.CustomFields, 2)
 	require.Equal(t, "field1", bindings[2].OIDC.CustomFields[0])
 	require.Equal(t, "field1", bindings[2].OIDC.CustomFields[0])

+ 1 - 0
docs/full-configuration.md

@@ -279,6 +279,7 @@ The configuration file contains the following sections:
       - `client_secret`, string. Defines the application's secret. Default: blank.
       - `client_secret`, string. Defines the application's secret. Default: blank.
       - `redirect_base_url`, string. Defines the base URL to redirect to after OpenID authentication. The suffix `/web/oidc/redirect` will be added to this base URL, adding also the `web_root` if configured. Default: blank.
       - `redirect_base_url`, string. Defines the base URL to redirect to after OpenID authentication. The suffix `/web/oidc/redirect` will be added to this base URL, adding also the `web_root` if configured. Default: blank.
       - `username_field`, string. Defines the ID token claims field to map to the SFTPGo username. Default: blank.
       - `username_field`, string. Defines the ID token claims field to map to the SFTPGo username. Default: blank.
+      - `scopes`, list of strings. Request the OAuth provider to provide the scope information from an authenticated users. The `openid` scope is mandatory. Default: `"openid", "profile", "email"`.
       - `role_field`, string. Defines the optional ID token claims field to map to a SFTPGo role. If the defined ID token claims field is set to `admin` the authenticated user is mapped to an SFTPGo admin. You don't need to specify this field if you want to use OpenID only for the Web Client UI. Default: blank.
       - `role_field`, string. Defines the optional ID token claims field to map to a SFTPGo role. If the defined ID token claims field is set to `admin` the authenticated user is mapped to an SFTPGo admin. You don't need to specify this field if you want to use OpenID only for the Web Client UI. Default: blank.
       - `implicit_roles`, boolean. If set, the `role_field` is ignored and the SFTPGo role is assumed based on the login link used. Default: `false`.
       - `implicit_roles`, boolean. If set, the `role_field` is ignored and the SFTPGo role is assumed based on the login link used. Default: `false`.
       - `custom_fields`, list of strings. Custom token claims fields to pass to the pre-login hook. Default: empty.
       - `custom_fields`, list of strings. Custom token claims fields to pass to the pre-login hook. Default: empty.

+ 10 - 3
docs/oidc.md

@@ -1,6 +1,7 @@
 # OpenID Connect
 # OpenID Connect
 
 
-OpenID Connect integration allows you to map your identity provider users to SFTPGo admins/users and so you can login to SFTPGo Web Client and Web Admin user interfaces using your identity provider.
+OpenID Connect integration allows you to map your identity provider users to SFTPGo admins/users,
+so you can login to SFTPGo Web Client and Web Admin user interfaces, using your own identity provider.
 
 
 SFTPGo allows to configure per-binding OpenID Connect configurations. The supported configuration parameters are documented within the `oidc` section [here](./full-configuration.md).
 SFTPGo allows to configure per-binding OpenID Connect configurations. The supported configuration parameters are documented within the `oidc` section [here](./full-configuration.md).
 
 
@@ -42,6 +43,7 @@ Add the following configuration parameters to the SFTPGo configuration file (or
       "config_url": "http://192.168.1.12:8086/auth/realms/sftpgo",
       "config_url": "http://192.168.1.12:8086/auth/realms/sftpgo",
       "redirect_base_url": "http://192.168.1.50:8080",
       "redirect_base_url": "http://192.168.1.50:8080",
       "username_field": "preferred_username",
       "username_field": "preferred_username",
+      "scopes": [ "openid", "profile", "email" ],
       "role_field": "sftpgo_role",
       "role_field": "sftpgo_role",
       "implicit_roles": false,
       "implicit_roles": false,
       "custom_fields": []
       "custom_fields": []
@@ -104,8 +106,12 @@ And the following is an example ID token which allows the SFTPGo user `user1` to
 ```
 ```
 
 
 SFTPGo users (not admins) can be created/updated after successful OpenID authentication by defining a [pre-login hook](./dynamic-user-mod.md).
 SFTPGo users (not admins) can be created/updated after successful OpenID authentication by defining a [pre-login hook](./dynamic-user-mod.md).
-You can use the `custom_fields` configuration parameter to define the token claims field names to pass to the pre-login hook, these fields are useful for implementing custom logic when creating/updating the SFTPGo user within the hook.
-For example you can set the field `sftpgo_home_dir` in your identity provider and add it to the `custom_fields` in the SFTPGo configuration like this:
+You can use `scopes` configuration to request additional information (claims) about authenticated users (See your provider's own documentation for more information).
+By default the scopes `"openid", "profile", "email"` are retrieved.
+The `custom_fields` configuration parameter can be used to define claim field names to pass to the pre-login hook,
+these fields can be used e.g. for implementing custom logic when creating/updating the SFTPGo user within the hook.
+For example, if you have created a scope with name `sftpgo` in your identity provider to provide a claim for `sftpgo_home_dir` ,
+then you can add it to the `custom_fields` in the SFTPGo configuration like this:
 
 
 ```json
 ```json
 ...
 ...
@@ -115,6 +121,7 @@ For example you can set the field `sftpgo_home_dir` in your identity provider an
       "config_url": "http://192.168.1.12:8086/auth/realms/sftpgo",
       "config_url": "http://192.168.1.12:8086/auth/realms/sftpgo",
       "redirect_base_url": "http://192.168.1.50:8080",
       "redirect_base_url": "http://192.168.1.50:8080",
       "username_field": "preferred_username",
       "username_field": "preferred_username",
+      "scopes": [ "openid", "profile", "email", "sftpgo" ],
       "role_field": "sftpgo_role",
       "role_field": "sftpgo_role",
       "custom_fields": ["sftpgo_home_dir"]
       "custom_fields": ["sftpgo_home_dir"]
     }
     }

+ 2 - 2
go.mod

@@ -58,7 +58,7 @@ require (
 	github.com/spf13/viper v1.12.0
 	github.com/spf13/viper v1.12.0
 	github.com/stretchr/testify v1.8.0
 	github.com/stretchr/testify v1.8.0
 	github.com/studio-b12/gowebdav v0.0.0-20220128162035-c7b1ff8a5e62
 	github.com/studio-b12/gowebdav v0.0.0-20220128162035-c7b1ff8a5e62
-	github.com/unrolled/secure v1.11.0
+	github.com/unrolled/secure v1.12.0
 	github.com/wagslane/go-password-validator v0.3.0
 	github.com/wagslane/go-password-validator v0.3.0
 	github.com/xhit/go-simple-mail/v2 v2.11.0
 	github.com/xhit/go-simple-mail/v2 v2.11.0
 	github.com/yl2chen/cidranger v1.0.3-0.20210928021809-d1cb2c52f37a
 	github.com/yl2chen/cidranger v1.0.3-0.20210928021809-d1cb2c52f37a
@@ -155,7 +155,7 @@ require (
 	golang.org/x/tools v0.1.11 // indirect
 	golang.org/x/tools v0.1.11 // indirect
 	golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f // indirect
 	golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f // indirect
 	google.golang.org/appengine v1.6.7 // indirect
 	google.golang.org/appengine v1.6.7 // indirect
-	google.golang.org/genproto v0.0.0-20220714211235-042d03aeabc9 // indirect
+	google.golang.org/genproto v0.0.0-20220715211116-798f69b842b9 // indirect
 	google.golang.org/grpc v1.48.0 // indirect
 	google.golang.org/grpc v1.48.0 // indirect
 	google.golang.org/protobuf v1.28.0 // indirect
 	google.golang.org/protobuf v1.28.0 // indirect
 	gopkg.in/ini.v1 v1.66.6 // indirect
 	gopkg.in/ini.v1 v1.66.6 // indirect

+ 4 - 4
go.sum

@@ -760,8 +760,8 @@ github.com/toorop/go-dkim v0.0.0-20201103131630-e1cd1a0a5208 h1:PM5hJF7HVfNWmCjM
 github.com/toorop/go-dkim v0.0.0-20201103131630-e1cd1a0a5208/go.mod h1:BzWtXXrXzZUvMacR0oF/fbDDgUPO8L36tDMmRAf14ns=
 github.com/toorop/go-dkim v0.0.0-20201103131630-e1cd1a0a5208/go.mod h1:BzWtXXrXzZUvMacR0oF/fbDDgUPO8L36tDMmRAf14ns=
 github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
 github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
 github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
 github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
-github.com/unrolled/secure v1.11.0 h1:fjkKhD/MsQnlmz/au+MmFptCFNhvf5iv04ALkdCXRCI=
-github.com/unrolled/secure v1.11.0/go.mod h1:BmF5hyM6tXczk3MpQkFf1hpKSRqCyhqcbiQtiAF7+40=
+github.com/unrolled/secure v1.12.0 h1:7k3jcgLwfjiKkhQde6VbQ3D4KDLtDBqDd/hs3PPANDY=
+github.com/unrolled/secure v1.12.0/go.mod h1:BmF5hyM6tXczk3MpQkFf1hpKSRqCyhqcbiQtiAF7+40=
 github.com/wagslane/go-password-validator v0.3.0 h1:vfxOPzGHkz5S146HDpavl0cw1DSVP061Ry2PX0/ON6I=
 github.com/wagslane/go-password-validator v0.3.0 h1:vfxOPzGHkz5S146HDpavl0cw1DSVP061Ry2PX0/ON6I=
 github.com/wagslane/go-password-validator v0.3.0/go.mod h1:TI1XJ6T5fRdRnHqHt14pvy1tNVnrwe7m3/f1f2fDphQ=
 github.com/wagslane/go-password-validator v0.3.0/go.mod h1:TI1XJ6T5fRdRnHqHt14pvy1tNVnrwe7m3/f1f2fDphQ=
 github.com/xhit/go-simple-mail/v2 v2.11.0 h1:o/056V50zfkO3Mm5tVdo9rG3ryg4ZmJ2XW5GMinHfVs=
 github.com/xhit/go-simple-mail/v2 v2.11.0 h1:o/056V50zfkO3Mm5tVdo9rG3ryg4ZmJ2XW5GMinHfVs=
@@ -1224,8 +1224,8 @@ google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljW
 google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
 google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
 google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
 google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
 google.golang.org/genproto v0.0.0-20220628213854-d9e0b6570c03/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
 google.golang.org/genproto v0.0.0-20220628213854-d9e0b6570c03/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
-google.golang.org/genproto v0.0.0-20220714211235-042d03aeabc9 h1:zfXhTgBfGlIh3jMXN06W8qbhFGsh6MJNJiYEuhTddOI=
-google.golang.org/genproto v0.0.0-20220714211235-042d03aeabc9/go.mod h1:GkXuJDJ6aQ7lnJcRF+SJVgFdQhypqgl3LB1C9vabdRE=
+google.golang.org/genproto v0.0.0-20220715211116-798f69b842b9 h1:1aEQRgZ4Gks2SRAkLzIPpIszRazwVfjSFe1cKc+e0Jg=
+google.golang.org/genproto v0.0.0-20220715211116-798f69b842b9/go.mod h1:GkXuJDJ6aQ7lnJcRF+SJVgFdQhypqgl3LB1C9vabdRE=
 google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
 google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
 google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
 google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
 google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
 google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=

+ 8 - 1
httpd/oidc.go

@@ -70,6 +70,10 @@ type OIDC struct {
 	// If set, the `RoleField` is ignored and the SFTPGo role is assumed based on
 	// If set, the `RoleField` is ignored and the SFTPGo role is assumed based on
 	// the login link used
 	// the login link used
 	ImplicitRoles bool `json:"implicit_roles" mapstructure:"implicit_roles"`
 	ImplicitRoles bool `json:"implicit_roles" mapstructure:"implicit_roles"`
+	// Scopes required by the OAuth provider to retrieve information about the authenticated user.
+	// The "openid" scope is required.
+	// Refer to your OAuth provider documentation for more information about this
+	Scopes []string `json:"scopes" mapstructure:"scopes"`
 	// Custom token claims fields to pass to the pre-login hook
 	// Custom token claims fields to pass to the pre-login hook
 	CustomFields      []string `json:"custom_fields" mapstructure:"custom_fields"`
 	CustomFields      []string `json:"custom_fields" mapstructure:"custom_fields"`
 	provider          *oidc.Provider
 	provider          *oidc.Provider
@@ -116,6 +120,9 @@ func (o *OIDC) initialize() error {
 	if o.RedirectBaseURL == "" {
 	if o.RedirectBaseURL == "" {
 		return errors.New("oidc: redirect base URL cannot be empty")
 		return errors.New("oidc: redirect base URL cannot be empty")
 	}
 	}
+	if !util.Contains(o.Scopes, oidc.ScopeOpenID) {
+		return fmt.Errorf("oidc: required scope %q is not set", oidc.ScopeOpenID)
+	}
 	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
 	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
 	defer cancel()
 	defer cancel()
 
 
@@ -143,7 +150,7 @@ func (o *OIDC) initialize() error {
 		ClientSecret: o.ClientSecret,
 		ClientSecret: o.ClientSecret,
 		Endpoint:     o.provider.Endpoint(),
 		Endpoint:     o.provider.Endpoint(),
 		RedirectURL:  o.getRedirectURL(),
 		RedirectURL:  o.getRedirectURL(),
-		Scopes:       []string{oidc.ScopeOpenID, "profile", "email"},
+		Scopes:       o.Scopes,
 	}
 	}
 
 
 	return nil
 	return nil

+ 6 - 0
httpd/oidc_test.go

@@ -93,6 +93,11 @@ func TestOIDCInitialization(t *testing.T) {
 		RoleField:       "sftpgo_role",
 		RoleField:       "sftpgo_role",
 	}
 	}
 	err = config.initialize()
 	err = config.initialize()
+	if assert.Error(t, err) {
+		assert.Contains(t, err.Error(), "oidc: required scope \"openid\" is not set")
+	}
+	config.Scopes = []string{oidc.ScopeOpenID}
+	err = config.initialize()
 	if assert.Error(t, err) {
 	if assert.Error(t, err) {
 		assert.Contains(t, err.Error(), "oidc: unable to initialize provider")
 		assert.Contains(t, err.Error(), "oidc: unable to initialize provider")
 	}
 	}
@@ -1263,6 +1268,7 @@ func getTestOIDCServer() *httpdServer {
 				UsernameField:   "preferred_username",
 				UsernameField:   "preferred_username",
 				RoleField:       "sftpgo_role",
 				RoleField:       "sftpgo_role",
 				ImplicitRoles:   false,
 				ImplicitRoles:   false,
+				Scopes:          []string{oidc.ScopeOpenID, "profile", "email"},
 				CustomFields:    nil,
 				CustomFields:    nil,
 			},
 			},
 		},
 		},

+ 5 - 0
sftpgo.json

@@ -263,6 +263,11 @@
           "client_secret": "",
           "client_secret": "",
           "config_url": "",
           "config_url": "",
           "redirect_base_url": "",
           "redirect_base_url": "",
+          "scopes": [
+            "openid",
+            "profile",
+            "email"
+          ],
           "username_field": "",
           "username_field": "",
           "role_field": "",
           "role_field": "",
           "implicit_roles": false,
           "implicit_roles": false,