public async Task <WebStatus> RegisterAsync(RegisterInputModel model) { var genericSuccessMessage = _localizer["Please check your email to complete the sign up process."]; _logger.LogDebug("Begin registration for {0}", model.Email); if (!ApplicationIdIsNullOrValid(model.ApplicationId)) { return(WebStatus.Error(_localizer["Invalid application id."], HttpStatusCode.BadRequest)); } if (!await _userStore.UsernameIsAvailable(model.Email)) { _logger.LogDebug("Existing user found."); var sendStatus = await _messageService.SendAccountAlreadyExistsMessageAsync(model.ApplicationId, model.Email); // Return a generic success message to prevent account discovery. Only the owner of // the email address will get a customized message. return(sendStatus.IsOk ? WebStatus.Success(genericSuccessMessage) : new WebStatus(sendStatus)); } if (await _oneTimeCodeService.UnexpiredOneTimeCodeExistsAsync(model.Email)) { // Although the username is available, there is a valid one time code // that can be used to cancel an email address change, so we can't // reuse the address quite yet return(WebStatus.Error(_localizer["Email address is temporarily reserved."], HttpStatusCode.Conflict)); } _logger.LogDebug("Email address not used by an existing user. Creating a new user."); // consider: in some cases may want to restricting claims to a list predefined by the system administrator var status = new WebStatus(); if (model.Claims == null) { model.Claims = new Dictionary <string, string>(); } var internalClaims = new KeyValuePair <string, string>[] { new KeyValuePair <string, string>( PasswordlessLoginConstants.Security.EmailNotConfirmedClaimType, "!") }; var newUser = new User() { Email = model.Email, Claims = model.Claims .Where(x => !PasswordlessLoginConstants.Security.ForbiddenClaims.Contains(x.Key) && !PasswordlessLoginConstants.Security.ProtectedClaims.Contains(x.Key)) .Union(internalClaims) .Select(x => new UserClaim() { Type = x.Key, Value = x.Value }) }; var newUserResponse = await _userStore.AddUserAsync(newUser); if (newUserResponse.HasError) { return(new WebStatus(newUserResponse.Status)); } newUser = newUserResponse.Result; await _eventNotificationService.NotifyEventAsync(newUser.Email, EventType.Register); if (!string.IsNullOrEmpty(model.Password)) { var setPasswordStatus = await _passwordService.SetPasswordAsync(newUser.SubjectId, model.Password); if (setPasswordStatus.IsOk) { await _eventNotificationService.NotifyEventAsync(newUser.Email, EventType.SetPassword); } else { status.AddWarning(_localizer["Password was not set."]); } } status.AddSuccess(genericSuccessMessage); var nextUrl = !string.IsNullOrEmpty(model.NextUrl) ? model.NextUrl : _urlService.GetDefaultRedirectUrl(); if (model.SetPassword) { _logger.LogTrace("The user will be asked to set their password after confirming the account."); nextUrl = SendToSetPasswordFirst(nextUrl); } var oneTimeCodeResponse = await _oneTimeCodeService.GetOneTimeCodeAsync(model.Email, TimeSpan.FromMinutes(_options.ConfirmAccountLinkValidityMinutes), nextUrl); switch (oneTimeCodeResponse.Status.StatusCode) { case GetOneTimeCodeStatusCode.Success: var result = await _messageService.SendWelcomeMessageAsync(model.ApplicationId, model.Email, oneTimeCodeResponse.Result.ShortCode, oneTimeCodeResponse.Result.LongCode, model.Claims); SetNonce(oneTimeCodeResponse.Result.ClientNonce); return(new WebStatus(status)); case GetOneTimeCodeStatusCode.TooManyRequests: return(WebStatus.Error(_localizer["Please wait a few minutes and try again."], HttpStatusCode.TooManyRequests)); case GetOneTimeCodeStatusCode.ServiceFailure: default: return(ServerError(_localizer["Hmm. Something went wrong. Please try again."])); } }