@@ -477,6 +477,10 @@ type OIDCConfig struct {
477
477
// UsernameField selects the claim field to be used as the created user's
478
478
// username.
479
479
UsernameField string
480
+ // GroupField selects the claim field to be used as the created user's
481
+ // groups. If the group field is the empty string, then no group updates
482
+ // will ever come from the OIDC provider.
483
+ GroupField string
480
484
// SignInText is the text to display on the OIDC login button
481
485
SignInText string
482
486
// IconURL points to the URL of an icon to display on the OIDC login button
@@ -609,21 +613,27 @@ func (api *API) userOIDC(rw http.ResponseWriter, r *http.Request) {
609
613
}
610
614
}
611
615
616
+ var usingGroups bool
612
617
var groups []string
613
- groupsRaw , ok := claims ["groups" ]
614
- if ok {
615
- // Convert the []interface{} we get to a []string.
616
- groupsInterface , ok := groupsRaw .([]interface {})
617
- if ok {
618
- for _ , groupInterface := range groupsInterface {
619
- group , ok := groupInterface .(string )
620
- if ! ok {
621
- httpapi .Write (ctx , rw , http .StatusBadRequest , codersdk.Response {
622
- Message : fmt .Sprintf ("Invalid group type. Expected string, got: %t" , emailRaw ),
623
- })
624
- return
618
+ // If the GroupField is the empty string, then groups from OIDC are not used.
619
+ // This is so we can support manual group assignment.
620
+ if api .OIDCConfig .GroupField != "" {
621
+ usingGroups = true
622
+ groupsRaw , ok := claims [api .OIDCConfig .GroupField ]
623
+ if ok && api .OIDCConfig .GroupField != "" {
624
+ // Convert the []interface{} we get to a []string.
625
+ groupsInterface , ok := groupsRaw .([]interface {})
626
+ if ok {
627
+ for _ , groupInterface := range groupsInterface {
628
+ group , ok := groupInterface .(string )
629
+ if ! ok {
630
+ httpapi .Write (ctx , rw , http .StatusBadRequest , codersdk.Response {
631
+ Message : fmt .Sprintf ("Invalid group type. Expected string, got: %t" , emailRaw ),
632
+ })
633
+ return
634
+ }
635
+ groups = append (groups , group )
625
636
}
626
- groups = append (groups , group )
627
637
}
628
638
}
629
639
}
@@ -684,6 +694,7 @@ func (api *API) userOIDC(rw http.ResponseWriter, r *http.Request) {
684
694
Email : email ,
685
695
Username : username ,
686
696
AvatarURL : picture ,
697
+ UsingGroups : usingGroups ,
687
698
Groups : groups ,
688
699
})
689
700
var httpErr httpError
@@ -725,7 +736,10 @@ type oauthLoginParams struct {
725
736
Email string
726
737
Username string
727
738
AvatarURL string
728
- Groups []string
739
+ // Is UsingGroups is true, then the user will be assigned
740
+ // to the Groups provided.
741
+ UsingGroups bool
742
+ Groups []string
729
743
}
730
744
731
745
type httpError struct {
@@ -865,7 +879,7 @@ func (api *API) oauthLogin(r *http.Request, params oauthLoginParams) (*http.Cook
865
879
}
866
880
867
881
// Ensure groups are correct.
868
- if len ( params .Groups ) > 0 {
882
+ if params .UsingGroups {
869
883
//nolint:gocritic
870
884
err := api .Options .SetUserGroups (dbauthz .AsSystemRestricted (ctx ), tx , user .ID , params .Groups )
871
885
if err != nil {
0 commit comments