Skip to content

Commit a26cbd5

Browse files
committed
fix(oauth): auto-bind verified external login to existing active user by email
When an external OAuth connector returns a verified email address that matches an existing active user account in Answer, the previous implementation immediately aborted with UserAccessDenied (50x Access denied). This required users who had previously registered with password to log in first and manually bind the provider under user settings. For open communities and seamless SSO onboarding, auto-bind the external identity to the existing active user when the email matches, update their last login timestamp, and issue an access token directly. Signed-off-by: Rénich Bon Ćirić <renich@evalinux.com>
1 parent 7f226dc commit a26cbd5

1 file changed

Lines changed: 19 additions & 12 deletions

File tree

internal/service/user_external_login/user_external_login_service.go

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -186,19 +186,31 @@ func (us *UserExternalLoginService) ExternalLogin(
186186
}, nil
187187
}
188188

189-
if _, exist, err := us.userRepo.GetByEmail(ctx, externalUserInfo.Email); err != nil {
189+
oldUserInfo, exist, err := us.userRepo.GetByEmail(ctx, externalUserInfo.Email)
190+
if err != nil {
190191
return nil, err
191-
} else if exist {
192+
}
193+
if !exist {
194+
// if user is not a member, register a new user
195+
oldUserInfo, err = us.registerNewUser(ctx, externalUserInfo)
196+
if err != nil {
197+
return nil, err
198+
}
199+
// set default user notification config for external user
200+
if err := us.userNotificationConfigService.SetDefaultUserNotificationConfig(ctx, []string{oldUserInfo.ID}); err != nil {
201+
log.Errorf("set default user notification config failed, err: %v", err)
202+
}
203+
} else if oldUserInfo.Status == entity.UserStatusDeleted {
192204
return &schema.UserExternalLoginResp{
193205
ErrTitle: translator.Tr(handler.GetLangByCtx(ctx), reason.UserAccessDenied),
194206
ErrMsg: translator.Tr(handler.GetLangByCtx(ctx), reason.UserAccessDenied),
195207
}, nil
208+
} else {
209+
if err := us.userRepo.UpdateLastLoginDate(ctx, oldUserInfo.ID); err != nil {
210+
log.Errorf("update user last login date failed: %v", err)
211+
}
196212
}
197-
// if user is not a member, register a new user
198-
oldUserInfo, err := us.registerNewUser(ctx, externalUserInfo)
199-
if err != nil {
200-
return nil, err
201-
}
213+
202214
// bind external user info to user
203215
err = us.bindOldUser(ctx, externalUserInfo, oldUserInfo)
204216
if err != nil {
@@ -211,11 +223,6 @@ func (us *UserExternalLoginService) ExternalLogin(
211223
log.Error(err)
212224
}
213225

214-
// set default user notification config for external user
215-
if err := us.userNotificationConfigService.SetDefaultUserNotificationConfig(ctx, []string{oldUserInfo.ID}); err != nil {
216-
log.Errorf("set default user notification config failed, err: %v", err)
217-
}
218-
219226
accessToken, _, err := us.userCommonService.CacheLoginUserInfo(
220227
ctx, oldUserInfo.ID, newMailStatus, oldUserInfo.Status, externalUserInfo.ExternalID)
221228
return &schema.UserExternalLoginResp{AccessToken: accessToken}, err

0 commit comments

Comments
 (0)