@@ -66,6 +66,10 @@ func (kc *keycloakClient) CreateGroup(name string) error {
6666 defer resp .Body .Close ()
6767
6868 if resp .StatusCode != http .StatusCreated {
69+ // If the group already exists (409 Conflict), that's fine - we can reuse it
70+ if resp .StatusCode == http .StatusConflict {
71+ return nil
72+ }
6973 respBytes , _ := io .ReadAll (resp .Body )
7074 return fmt .Errorf ("failed creating group %q: %s - %s" , name , resp .Status , respBytes )
7175 }
@@ -131,6 +135,43 @@ func (kc *keycloakClient) CreateUser(username, password string, groups ...string
131135 return nil
132136}
133137
138+ func (kc * keycloakClient ) CreateUserWithEmail (username , email , password string , groups ... string ) error {
139+ userURL := kc .adminURL .JoinPath ("users" )
140+
141+ user := user {
142+ Username : username ,
143+ Email : email ,
144+ Enabled : true ,
145+ EmailVerified : true ,
146+ Groups : groups ,
147+ Credentials : []credential {
148+ {
149+ Temporary : false ,
150+ Type : credentialTypePassword ,
151+ Value : password ,
152+ },
153+ },
154+ }
155+
156+ userBytes , err := json .Marshal (user )
157+ if err != nil {
158+ return fmt .Errorf ("marshalling user configuration %v" , user )
159+ }
160+
161+ resp , err := kc .DoRequest (http .MethodPost , userURL .String (), runtime .ContentTypeJSON , true , bytes .NewBuffer (userBytes ))
162+ if err != nil {
163+ return fmt .Errorf ("sending POST request to %q to create user %v" , userURL .String (), user )
164+ }
165+ defer resp .Body .Close ()
166+
167+ if resp .StatusCode != http .StatusCreated {
168+ respBytes , _ := io .ReadAll (resp .Body )
169+ return fmt .Errorf ("failed creating user %v: %s - %s" , user , resp .Status , respBytes )
170+ }
171+
172+ return nil
173+ }
174+
134175type authenticationResponse struct {
135176 AccessToken string `json:"access_token"`
136177 IDToken string `json:"id_token"`
0 commit comments