@@ -93,21 +93,16 @@ func (h *Handlers) BeginRegistration(w http.ResponseWriter, r *http.Request) {
9393 return
9494 }
9595
96- // Create new user
96+ // Create a temporary WebAuthn user for registration without saving to DB yet
9797 isAdmin := h .config .IsAdmin (req .Email )
98- user , err := h .db .CreateUserWithApproval (req .Email , req .DisplayName , isAdmin )
99- if err != nil {
100- logrus .Errorf ("Failed to create user: %v" , err )
101- h .writeError (w , "Failed to create user" , http .StatusInternalServerError )
102- return
103- }
104-
105- if isAdmin {
106- logrus .Infof ("Admin user auto-approved: %s" , req .Email )
98+ tempUser := & database.User {
99+ Email : req .Email ,
100+ DisplayName : req .DisplayName ,
101+ Approved : isAdmin , // Auto-approve admins
107102 }
108103
109104 webAuthnUser := & auth.WebAuthnUser {}
110- webAuthnUser .SetUser (user )
105+ webAuthnUser .SetUser (tempUser )
111106
112107 options , sessionData , err := h .webAuthn .BeginRegistration (webAuthnUser )
113108 if err != nil {
@@ -116,10 +111,12 @@ func (h *Handlers) BeginRegistration(w http.ResponseWriter, r *http.Request) {
116111 return
117112 }
118113
119- // Store session data
114+ // Store session data with user details for later creation
120115 session , _ := h .store .Get (r , "webauthn-session" )
121116 session .Values ["challenge" ] = sessionData .Challenge
122- session .Values ["user_id" ] = user .ID
117+ session .Values ["pending_email" ] = req .Email
118+ session .Values ["pending_display_name" ] = req .DisplayName
119+ session .Values ["pending_is_admin" ] = isAdmin
123120 if err := session .Save (r , w ); err != nil {
124121 h .writeError (w , "Failed to save session" , http .StatusInternalServerError )
125122 return
@@ -139,15 +136,28 @@ func (h *Handlers) BeginRegistration(w http.ResponseWriter, r *http.Request) {
139136func (h * Handlers ) FinishRegistration (w http.ResponseWriter , r * http.Request ) {
140137 session , _ := h .store .Get (r , "webauthn-session" )
141138
142- userID , ok := session .Values ["user_id" ].(int )
139+ // Get pending user data from session instead of user_id
140+ pendingEmail , ok := session .Values ["pending_email" ].(string )
143141 if ! ok {
144- h .writeError (w , "Invalid session" , http .StatusBadRequest )
142+ h .writeError (w , "Invalid session - no pending registration" , http .StatusBadRequest )
143+ return
144+ }
145+
146+ pendingDisplayName , ok := session .Values ["pending_display_name" ].(string )
147+ if ! ok {
148+ h .writeError (w , "Invalid session - missing display name" , http .StatusBadRequest )
149+ return
150+ }
151+
152+ pendingIsAdmin , ok := session .Values ["pending_is_admin" ].(bool )
153+ if ! ok {
154+ h .writeError (w , "Invalid session - missing admin flag" , http .StatusBadRequest )
145155 return
146156 }
147157
148158 challenge , ok := session .Values ["challenge" ].(string )
149159 if ! ok {
150- h .writeError (w , "Invalid session" , http .StatusBadRequest )
160+ h .writeError (w , "Invalid session - missing challenge " , http .StatusBadRequest )
151161 return
152162 }
153163
@@ -162,22 +172,23 @@ func (h *Handlers) FinishRegistration(w http.ResponseWriter, r *http.Request) {
162172 // Create a new reader from the body for the WebAuthn library
163173 r .Body = io .NopCloser (strings .NewReader (string (body )))
164174
165- user , err := h .db .GetUser (userID )
166- if err != nil {
167- h .writeError (w , "User not found" , http .StatusNotFound )
168- return
175+ // Create temporary user for WebAuthn verification
176+ tempUser := & database.User {
177+ Email : pendingEmail ,
178+ DisplayName : pendingDisplayName ,
179+ Approved : pendingIsAdmin ,
169180 }
170181
171182 webAuthnUser := & auth.WebAuthnUser {}
172- webAuthnUser .SetUser (user )
183+ webAuthnUser .SetUser (tempUser )
173184
174185 sessionData := webauthn.SessionData {
175186 Challenge : challenge ,
176187 UserID : webAuthnUser .WebAuthnID (),
177188 }
178189
179190 // Log the request details for debugging
180- logrus .Debugf ("Finishing registration for user: %s" , user . Email )
191+ logrus .Debugf ("Finishing registration for user: %s" , pendingEmail )
181192 logrus .Debugf ("Session challenge: %s" , challenge )
182193 logrus .Debugf ("Session user ID: %v" , webAuthnUser .WebAuthnID ())
183194
@@ -188,9 +199,29 @@ func (h *Handlers) FinishRegistration(w http.ResponseWriter, r *http.Request) {
188199 return
189200 }
190201
202+ // Only NOW create the user in the database after successful passkey registration
203+ user , err := h .db .CreateUserWithApproval (pendingEmail , pendingDisplayName , pendingIsAdmin )
204+ if err != nil {
205+ if strings .Contains (err .Error (), "UNIQUE constraint failed" ) {
206+ h .writeError (w , "User already exists" , http .StatusConflict )
207+ return
208+ }
209+ logrus .Errorf ("Failed to create user: %v" , err )
210+ h .writeError (w , "Failed to create user" , http .StatusInternalServerError )
211+ return
212+ }
213+
214+ if pendingIsAdmin {
215+ logrus .Infof ("Admin user auto-approved: %s" , pendingEmail )
216+ }
217+
191218 // Save credential to database
192219 if err := h .webAuthn .SaveCredential (user .ID , credential ); err != nil {
193220 logrus .Errorf ("Failed to save credential: %v" , err )
221+ // If we can't save the credential, we should remove the user we just created
222+ if deleteErr := h .db .DeleteUser (user .ID ); deleteErr != nil {
223+ logrus .Errorf ("Failed to cleanup user after credential save failure: %v" , deleteErr )
224+ }
194225 h .writeError (w , "Failed to save credential" , http .StatusInternalServerError )
195226 return
196227 }
@@ -207,7 +238,9 @@ func (h *Handlers) FinishRegistration(w http.ResponseWriter, r *http.Request) {
207238
208239 // Clear webauthn session
209240 session .Values ["challenge" ] = nil
210- session .Values ["user_id" ] = nil
241+ session .Values ["pending_email" ] = nil
242+ session .Values ["pending_display_name" ] = nil
243+ session .Values ["pending_is_admin" ] = nil
211244 if err := session .Save (r , w ); err != nil {
212245 log .Printf ("Failed to save session: %v" , err )
213246 // Don't return error here as the main operation succeeded
@@ -427,7 +460,7 @@ func (h *Handlers) ListUsers(w http.ResponseWriter, r *http.Request) {
427460 if ! h .requireAdmin (w , r ) {
428461 return
429462 }
430-
463+
431464 users , err := h .db .ListUsers ()
432465 if err != nil {
433466 logrus .Errorf ("Failed to list users: %v" , err )
@@ -443,7 +476,7 @@ func (h *Handlers) CreateUser(w http.ResponseWriter, r *http.Request) {
443476 if ! h .requireAdmin (w , r ) {
444477 return
445478 }
446-
479+
447480 var req struct {
448481 Email string `json:"email"`
449482 DisplayName string `json:"display_name"`
@@ -480,7 +513,7 @@ func (h *Handlers) UpdateUser(w http.ResponseWriter, r *http.Request) {
480513 if ! h .requireAdmin (w , r ) {
481514 return
482515 }
483-
516+
484517 vars := mux .Vars (r )
485518 idStr , ok := vars ["id" ]
486519 if ! ok {
@@ -529,7 +562,7 @@ func (h *Handlers) DeleteUser(w http.ResponseWriter, r *http.Request) {
529562 if ! h .requireAdmin (w , r ) {
530563 return
531564 }
532-
565+
533566 vars := mux .Vars (r )
534567 idStr , ok := vars ["id" ]
535568 if ! ok {
0 commit comments