diff --git a/src/Api/Auth/Controllers/AccountsController.cs b/src/Api/Auth/Controllers/AccountsController.cs
index 8acdbb7e87..f1b1cf6299 100644
--- a/src/Api/Auth/Controllers/AccountsController.cs
+++ b/src/Api/Auth/Controllers/AccountsController.cs
@@ -2,6 +2,7 @@
 using Bit.Api.AdminConsole.Models.Response;
 using Bit.Api.Auth.Models.Request;
 using Bit.Api.Auth.Models.Request.Accounts;
+using Bit.Api.Auth.Models.Request.WebAuthn;
 using Bit.Api.Auth.Validators;
 using Bit.Api.Models.Request;
 using Bit.Api.Models.Request.Accounts;
@@ -81,6 +82,8 @@ public class AccountsController : Controller
     private readonly IRotationValidator<IEnumerable<ResetPasswordWithOrgIdRequestModel>,
             IReadOnlyList<OrganizationUser>>
         _organizationUserValidator;
+    private readonly IRotationValidator<IEnumerable<WebAuthnLoginRotateKeyRequestModel>, IEnumerable<WebAuthnLoginRotateKeyData>>
+        _webauthnKeyValidator;
 
 
     public AccountsController(
@@ -109,7 +112,8 @@ public class AccountsController : Controller
         IRotationValidator<IEnumerable<EmergencyAccessWithIdRequestModel>, IEnumerable<EmergencyAccess>>
             emergencyAccessValidator,
         IRotationValidator<IEnumerable<ResetPasswordWithOrgIdRequestModel>, IReadOnlyList<OrganizationUser>>
-            organizationUserValidator
+            organizationUserValidator,
+        IRotationValidator<IEnumerable<WebAuthnLoginRotateKeyRequestModel>, IEnumerable<WebAuthnLoginRotateKeyData>> webAuthnKeyValidator
         )
     {
         _cipherRepository = cipherRepository;
@@ -136,6 +140,7 @@ public class AccountsController : Controller
         _sendValidator = sendValidator;
         _emergencyAccessValidator = emergencyAccessValidator;
         _organizationUserValidator = organizationUserValidator;
+        _webauthnKeyValidator = webAuthnKeyValidator;
     }
 
     #region DEPRECATED (Moved to Identity Service)
@@ -442,7 +447,8 @@ public class AccountsController : Controller
             Folders = await _folderValidator.ValidateAsync(user, model.Folders),
             Sends = await _sendValidator.ValidateAsync(user, model.Sends),
             EmergencyAccesses = await _emergencyAccessValidator.ValidateAsync(user, model.EmergencyAccessKeys),
-            OrganizationUsers = await _organizationUserValidator.ValidateAsync(user, model.ResetPasswordKeys)
+            OrganizationUsers = await _organizationUserValidator.ValidateAsync(user, model.ResetPasswordKeys),
+            WebAuthnKeys = await _webauthnKeyValidator.ValidateAsync(user, model.WebAuthnKeys)
         };
 
         var result = await _rotateUserKeyCommand.RotateUserKeyAsync(user, dataModel);
diff --git a/src/Api/Auth/Controllers/WebAuthnController.cs b/src/Api/Auth/Controllers/WebAuthnController.cs
index 437c1ba20d..a66055b97a 100644
--- a/src/Api/Auth/Controllers/WebAuthnController.cs
+++ b/src/Api/Auth/Controllers/WebAuthnController.cs
@@ -1,5 +1,5 @@
 using Bit.Api.Auth.Models.Request.Accounts;
-using Bit.Api.Auth.Models.Request.Webauthn;
+using Bit.Api.Auth.Models.Request.WebAuthn;
 using Bit.Api.Auth.Models.Response.WebAuthn;
 using Bit.Api.Models.Response;
 using Bit.Core;
diff --git a/src/Api/Auth/Models/Request/Accounts/UpdateKeyRequestModel.cs b/src/Api/Auth/Models/Request/Accounts/UpdateKeyRequestModel.cs
index cfeaec3248..d3cb5c2442 100644
--- a/src/Api/Auth/Models/Request/Accounts/UpdateKeyRequestModel.cs
+++ b/src/Api/Auth/Models/Request/Accounts/UpdateKeyRequestModel.cs
@@ -1,5 +1,6 @@
 using System.ComponentModel.DataAnnotations;
 using Bit.Api.AdminConsole.Models.Request.Organizations;
+using Bit.Api.Auth.Models.Request.WebAuthn;
 using Bit.Api.Tools.Models.Request;
 using Bit.Api.Vault.Models.Request;
 
@@ -19,5 +20,6 @@ public class UpdateKeyRequestModel
     public IEnumerable<SendWithIdRequestModel> Sends { get; set; }
     public IEnumerable<EmergencyAccessWithIdRequestModel> EmergencyAccessKeys { get; set; }
     public IEnumerable<ResetPasswordWithOrgIdRequestModel> ResetPasswordKeys { get; set; }
+    public IEnumerable<WebAuthnLoginRotateKeyRequestModel> WebAuthnKeys { get; set; }
 
 }
diff --git a/src/Api/Auth/Models/Request/WebAuthn/WebAuthnLoginCredentialCreatelRequestModel.cs b/src/Api/Auth/Models/Request/WebAuthn/WebAuthnLoginCredentialCreatelRequestModel.cs
index 2a3aa1dde9..8c6acbc8d4 100644
--- a/src/Api/Auth/Models/Request/WebAuthn/WebAuthnLoginCredentialCreatelRequestModel.cs
+++ b/src/Api/Auth/Models/Request/WebAuthn/WebAuthnLoginCredentialCreatelRequestModel.cs
@@ -2,7 +2,7 @@
 using Bit.Core.Utilities;
 using Fido2NetLib;
 
-namespace Bit.Api.Auth.Models.Request.Webauthn;
+namespace Bit.Api.Auth.Models.Request.WebAuthn;
 
 public class WebAuthnLoginCredentialCreateRequestModel
 {
diff --git a/src/Api/Auth/Models/Request/WebAuthn/WebAuthnLoginCredentialUpdateRequestModel.cs b/src/Api/Auth/Models/Request/WebAuthn/WebAuthnLoginCredentialUpdateRequestModel.cs
index 1d2e0813ef..54244c2dbd 100644
--- a/src/Api/Auth/Models/Request/WebAuthn/WebAuthnLoginCredentialUpdateRequestModel.cs
+++ b/src/Api/Auth/Models/Request/WebAuthn/WebAuthnLoginCredentialUpdateRequestModel.cs
@@ -2,7 +2,7 @@
 using Bit.Core.Utilities;
 using Fido2NetLib;
 
-namespace Bit.Api.Auth.Models.Request.Webauthn;
+namespace Bit.Api.Auth.Models.Request.WebAuthn;
 
 public class WebAuthnLoginCredentialUpdateRequestModel
 {
diff --git a/src/Api/Auth/Models/Request/WebAuthn/WebAuthnLoginRotateKeyRequestModel.cs b/src/Api/Auth/Models/Request/WebAuthn/WebAuthnLoginRotateKeyRequestModel.cs
new file mode 100644
index 0000000000..7e161cfbea
--- /dev/null
+++ b/src/Api/Auth/Models/Request/WebAuthn/WebAuthnLoginRotateKeyRequestModel.cs
@@ -0,0 +1,32 @@
+using System.ComponentModel.DataAnnotations;
+using Bit.Core.Auth.Models.Data;
+using Bit.Core.Utilities;
+
+namespace Bit.Api.Auth.Models.Request.WebAuthn;
+
+public class WebAuthnLoginRotateKeyRequestModel
+{
+    [Required]
+    public Guid Id { get; set; }
+
+    [Required]
+    [EncryptedString]
+    [EncryptedStringLength(2000)]
+    public string EncryptedUserKey { get; set; }
+
+    [Required]
+    [EncryptedString]
+    [EncryptedStringLength(2000)]
+    public string EncryptedPublicKey { get; set; }
+
+    public WebAuthnLoginRotateKeyData ToWebAuthnRotateKeyData()
+    {
+        return new WebAuthnLoginRotateKeyData
+        {
+            Id = Id,
+            EncryptedUserKey = EncryptedUserKey,
+            EncryptedPublicKey = EncryptedPublicKey
+        };
+    }
+
+}
diff --git a/src/Api/Auth/Models/Response/WebAuthn/WebAuthnCredentialResponseModel.cs b/src/Api/Auth/Models/Response/WebAuthn/WebAuthnCredentialResponseModel.cs
index 01cf2559a6..3199dccd02 100644
--- a/src/Api/Auth/Models/Response/WebAuthn/WebAuthnCredentialResponseModel.cs
+++ b/src/Api/Auth/Models/Response/WebAuthn/WebAuthnCredentialResponseModel.cs
@@ -1,6 +1,7 @@
 using Bit.Core.Auth.Entities;
 using Bit.Core.Auth.Enums;
 using Bit.Core.Models.Api;
+using Bit.Core.Utilities;
 
 namespace Bit.Api.Auth.Models.Response.WebAuthn;
 
@@ -13,9 +14,17 @@ public class WebAuthnCredentialResponseModel : ResponseModel
         Id = credential.Id.ToString();
         Name = credential.Name;
         PrfStatus = credential.GetPrfStatus();
+        EncryptedUserKey = credential.EncryptedUserKey;
+        EncryptedPublicKey = credential.EncryptedPublicKey;
     }
 
     public string Id { get; set; }
     public string Name { get; set; }
     public WebAuthnPrfStatus PrfStatus { get; set; }
+    [EncryptedString]
+    [EncryptedStringLength(2000)]
+    public string EncryptedUserKey { get; set; }
+    [EncryptedString]
+    [EncryptedStringLength(2000)]
+    public string EncryptedPublicKey { get; set; }
 }
diff --git a/src/Api/Auth/Validators/WebAuthnLoginKeyRotationValidator.cs b/src/Api/Auth/Validators/WebAuthnLoginKeyRotationValidator.cs
new file mode 100644
index 0000000000..5c4d0ef302
--- /dev/null
+++ b/src/Api/Auth/Validators/WebAuthnLoginKeyRotationValidator.cs
@@ -0,0 +1,55 @@
+using Bit.Api.Auth.Models.Request.WebAuthn;
+using Bit.Core.Auth.Models.Data;
+using Bit.Core.Auth.Repositories;
+using Bit.Core.Entities;
+using Bit.Core.Exceptions;
+
+namespace Bit.Api.Auth.Validators;
+
+public class WebAuthnLoginKeyRotationValidator : IRotationValidator<IEnumerable<WebAuthnLoginRotateKeyRequestModel>, IEnumerable<WebAuthnLoginRotateKeyData>>
+{
+    private readonly IWebAuthnCredentialRepository _webAuthnCredentialRepository;
+
+    public WebAuthnLoginKeyRotationValidator(IWebAuthnCredentialRepository webAuthnCredentialRepository)
+    {
+        _webAuthnCredentialRepository = webAuthnCredentialRepository;
+    }
+
+    public async Task<IEnumerable<WebAuthnLoginRotateKeyData>> ValidateAsync(User user, IEnumerable<WebAuthnLoginRotateKeyRequestModel> keysToRotate)
+    {
+        // 2024-06: Remove after 3 releases, for backward compatibility
+        if (keysToRotate == null)
+        {
+            return new List<WebAuthnLoginRotateKeyData>();
+        }
+
+        var result = new List<WebAuthnLoginRotateKeyData>();
+        var existing = await _webAuthnCredentialRepository.GetManyByUserIdAsync(user.Id);
+        if (existing == null || !existing.Any())
+        {
+            return result;
+        }
+
+        foreach (var ea in existing)
+        {
+            var keyToRotate = keysToRotate.FirstOrDefault(c => c.Id == ea.Id);
+            if (keyToRotate == null)
+            {
+                throw new BadRequestException("All existing webauthn prf keys must be included in the rotation.");
+            }
+
+            if (keyToRotate.EncryptedUserKey == null)
+            {
+                throw new BadRequestException("WebAuthn prf keys must have user-key during rotation.");
+            }
+            if (keyToRotate.EncryptedPublicKey == null)
+            {
+                throw new BadRequestException("WebAuthn prf keys must have public-key during rotation.");
+            }
+
+            result.Add(keyToRotate.ToWebAuthnRotateKeyData());
+        }
+
+        return result;
+    }
+}
diff --git a/src/Api/Startup.cs b/src/Api/Startup.cs
index 63b1a3c3cd..fd2a4dbe6f 100644
--- a/src/Api/Startup.cs
+++ b/src/Api/Startup.cs
@@ -30,6 +30,8 @@ using Bit.Core.Billing.Extensions;
 using Bit.Core.OrganizationFeatures.OrganizationSubscriptions;
 using Bit.Core.Tools.Entities;
 using Bit.Core.Vault.Entities;
+using Bit.Api.Auth.Models.Request.WebAuthn;
+using Bit.Core.Auth.Models.Data;
 
 #if !OSS
 using Bit.Commercial.Core.SecretsManager;
@@ -163,7 +165,9 @@ public class Startup
             .AddScoped<IRotationValidator<IEnumerable<ResetPasswordWithOrgIdRequestModel>,
                     IReadOnlyList<OrganizationUser>>
                 , OrganizationUserRotationValidator>();
-
+        services
+            .AddScoped<IRotationValidator<IEnumerable<WebAuthnLoginRotateKeyRequestModel>, IEnumerable<WebAuthnLoginRotateKeyData>>,
+                WebAuthnLoginKeyRotationValidator>();
 
         // Services
         services.AddBaseServices(globalSettings);
diff --git a/src/Core/Auth/Models/Data/RotateUserKeyData.cs b/src/Core/Auth/Models/Data/RotateUserKeyData.cs
index 52c6514770..f361c2a2cc 100644
--- a/src/Core/Auth/Models/Data/RotateUserKeyData.cs
+++ b/src/Core/Auth/Models/Data/RotateUserKeyData.cs
@@ -15,4 +15,5 @@ public class RotateUserKeyData
     public IReadOnlyList<Send> Sends { get; set; }
     public IEnumerable<EmergencyAccess> EmergencyAccesses { get; set; }
     public IReadOnlyList<OrganizationUser> OrganizationUsers { get; set; }
+    public IEnumerable<WebAuthnLoginRotateKeyData> WebAuthnKeys { get; set; }
 }
diff --git a/src/Core/Auth/Models/Data/WebAuthnLoginRotateKeyData.cs b/src/Core/Auth/Models/Data/WebAuthnLoginRotateKeyData.cs
new file mode 100644
index 0000000000..40a096c474
--- /dev/null
+++ b/src/Core/Auth/Models/Data/WebAuthnLoginRotateKeyData.cs
@@ -0,0 +1,21 @@
+using System.ComponentModel.DataAnnotations;
+using Bit.Core.Utilities;
+
+namespace Bit.Core.Auth.Models.Data;
+
+public class WebAuthnLoginRotateKeyData
+{
+    [Required]
+    public Guid Id { get; set; }
+
+    [Required]
+    [EncryptedString]
+    [EncryptedStringLength(2000)]
+    public string EncryptedUserKey { get; set; }
+
+    [Required]
+    [EncryptedString]
+    [EncryptedStringLength(2000)]
+    public string EncryptedPublicKey { get; set; }
+
+}
diff --git a/src/Core/Auth/Repositories/IWebAuthnCredentialRepository.cs b/src/Core/Auth/Repositories/IWebAuthnCredentialRepository.cs
index 50f03744c5..1fab56d07a 100644
--- a/src/Core/Auth/Repositories/IWebAuthnCredentialRepository.cs
+++ b/src/Core/Auth/Repositories/IWebAuthnCredentialRepository.cs
@@ -1,4 +1,6 @@
 using Bit.Core.Auth.Entities;
+using Bit.Core.Auth.Models.Data;
+using Bit.Core.Auth.UserFeatures.UserKey;
 using Bit.Core.Repositories;
 
 namespace Bit.Core.Auth.Repositories;
@@ -8,4 +10,5 @@ public interface IWebAuthnCredentialRepository : IRepository<WebAuthnCredential,
     Task<WebAuthnCredential> GetByIdAsync(Guid id, Guid userId);
     Task<ICollection<WebAuthnCredential>> GetManyByUserIdAsync(Guid userId);
     Task<bool> UpdateAsync(WebAuthnCredential credential);
+    UpdateEncryptedDataForKeyRotation UpdateKeysForRotationAsync(Guid userId, IEnumerable<WebAuthnLoginRotateKeyData> credentials);
 }
diff --git a/src/Core/Auth/UserFeatures/UserKey/Implementations/RotateUserKeyCommand.cs b/src/Core/Auth/UserFeatures/UserKey/Implementations/RotateUserKeyCommand.cs
index a580629864..4c7ca20737 100644
--- a/src/Core/Auth/UserFeatures/UserKey/Implementations/RotateUserKeyCommand.cs
+++ b/src/Core/Auth/UserFeatures/UserKey/Implementations/RotateUserKeyCommand.cs
@@ -1,4 +1,5 @@
 using Bit.Core.Auth.Models.Data;
+using Bit.Core.Auth.Repositories;
 using Bit.Core.Entities;
 using Bit.Core.Repositories;
 using Bit.Core.Services;
@@ -20,6 +21,7 @@ public class RotateUserKeyCommand : IRotateUserKeyCommand
     private readonly IOrganizationUserRepository _organizationUserRepository;
     private readonly IPushNotificationService _pushService;
     private readonly IdentityErrorDescriber _identityErrorDescriber;
+    private readonly IWebAuthnCredentialRepository _credentialRepository;
 
     /// <summary>
     /// Instantiates a new <see cref="RotateUserKeyCommand"/>
@@ -35,7 +37,7 @@ public class RotateUserKeyCommand : IRotateUserKeyCommand
     public RotateUserKeyCommand(IUserService userService, IUserRepository userRepository,
         ICipherRepository cipherRepository, IFolderRepository folderRepository, ISendRepository sendRepository,
         IEmergencyAccessRepository emergencyAccessRepository, IOrganizationUserRepository organizationUserRepository,
-        IPushNotificationService pushService, IdentityErrorDescriber errors)
+        IPushNotificationService pushService, IdentityErrorDescriber errors, IWebAuthnCredentialRepository credentialRepository)
     {
         _userService = userService;
         _userRepository = userRepository;
@@ -46,6 +48,7 @@ public class RotateUserKeyCommand : IRotateUserKeyCommand
         _organizationUserRepository = organizationUserRepository;
         _pushService = pushService;
         _identityErrorDescriber = errors;
+        _credentialRepository = credentialRepository;
     }
 
     /// <inheritdoc />
@@ -68,7 +71,7 @@ public class RotateUserKeyCommand : IRotateUserKeyCommand
         user.Key = model.Key;
         user.PrivateKey = model.PrivateKey;
         if (model.Ciphers.Any() || model.Folders.Any() || model.Sends.Any() || model.EmergencyAccesses.Any() ||
-            model.OrganizationUsers.Any())
+            model.OrganizationUsers.Any() || model.WebAuthnKeys.Any())
         {
             List<UpdateEncryptedDataForKeyRotation> saveEncryptedDataActions = new();
 
@@ -99,6 +102,11 @@ public class RotateUserKeyCommand : IRotateUserKeyCommand
                     _organizationUserRepository.UpdateForKeyRotation(user.Id, model.OrganizationUsers));
             }
 
+            if (model.WebAuthnKeys.Any())
+            {
+                saveEncryptedDataActions.Add(_credentialRepository.UpdateKeysForRotationAsync(user.Id, model.WebAuthnKeys));
+            }
+
             await _userRepository.UpdateUserKeyAndEncryptedDataAsync(user, saveEncryptedDataActions);
         }
         else
diff --git a/src/Infrastructure.Dapper/Auth/Repositories/WebAuthnCredentialRepository.cs b/src/Infrastructure.Dapper/Auth/Repositories/WebAuthnCredentialRepository.cs
index d159157c0e..85a7cc64ef 100644
--- a/src/Infrastructure.Dapper/Auth/Repositories/WebAuthnCredentialRepository.cs
+++ b/src/Infrastructure.Dapper/Auth/Repositories/WebAuthnCredentialRepository.cs
@@ -1,7 +1,10 @@
 using System.Data;
 using Bit.Core.Auth.Entities;
+using Bit.Core.Auth.Models.Data;
 using Bit.Core.Auth.Repositories;
+using Bit.Core.Auth.UserFeatures.UserKey;
 using Bit.Core.Settings;
+using Bit.Core.Utilities;
 using Bit.Infrastructure.Dapper.Repositories;
 using Dapper;
 using Microsoft.Data.SqlClient;
@@ -55,4 +58,37 @@ public class WebAuthnCredentialRepository : Repository<WebAuthnCredential, Guid>
 
         return affectedRows > 0;
     }
+
+    public UpdateEncryptedDataForKeyRotation UpdateKeysForRotationAsync(Guid userId, IEnumerable<WebAuthnLoginRotateKeyData> credentials)
+    {
+        return async (SqlConnection connection, SqlTransaction transaction) =>
+        {
+            const string sql = @"
+                UPDATE WC
+                SET
+                    WC.[EncryptedPublicKey] = UW.[encryptedPublicKey],
+                    WC.[EncryptedUserKey] = UW.[encryptedUserKey]
+                FROM
+                    [dbo].[WebAuthnCredential] WC
+                INNER JOIN
+                    OPENJSON(@JsonCredentials)
+                    WITH (
+                        id UNIQUEIDENTIFIER,
+                        encryptedPublicKey NVARCHAR(MAX),
+                        encryptedUserKey NVARCHAR(MAX)
+                    ) UW
+                    ON UW.id = WC.Id
+                WHERE
+                    WC.[UserId] = @UserId";
+
+            var jsonCredentials = CoreHelpers.ClassToJsonData(credentials);
+
+            await connection.ExecuteAsync(
+                sql,
+                new { UserId = userId, JsonCredentials = jsonCredentials },
+                transaction: transaction,
+                commandType: CommandType.Text);
+        };
+    }
+
 }
diff --git a/src/Infrastructure.EntityFramework/Auth/Repositories/WebAuthnCredentialRepository.cs b/src/Infrastructure.EntityFramework/Auth/Repositories/WebAuthnCredentialRepository.cs
index cd3751a6d0..1499811880 100644
--- a/src/Infrastructure.EntityFramework/Auth/Repositories/WebAuthnCredentialRepository.cs
+++ b/src/Infrastructure.EntityFramework/Auth/Repositories/WebAuthnCredentialRepository.cs
@@ -1,5 +1,7 @@
 using AutoMapper;
+using Bit.Core.Auth.Models.Data;
 using Bit.Core.Auth.Repositories;
+using Bit.Core.Auth.UserFeatures.UserKey;
 using Bit.Infrastructure.EntityFramework.Auth.Models;
 using Bit.Infrastructure.EntityFramework.Repositories;
 using Microsoft.EntityFrameworkCore;
@@ -56,4 +58,30 @@ public class WebAuthnCredentialRepository : Repository<Core.Auth.Entities.WebAut
             return true;
         }
     }
+
+    public UpdateEncryptedDataForKeyRotation UpdateKeysForRotationAsync(Guid userId, IEnumerable<WebAuthnLoginRotateKeyData> credentials)
+    {
+        return async (_, _) =>
+        {
+            var newCreds = credentials.ToList();
+            using var scope = ServiceScopeFactory.CreateScope();
+            var dbContext = GetDatabaseContext(scope);
+            var userWebauthnCredentials = await GetDbSet(dbContext)
+                .Where(wc => wc.Id == wc.Id)
+                .ToListAsync();
+            var validUserWebauthnCredentials = userWebauthnCredentials
+                .Where(wc => newCreds.Any(nwc => nwc.Id == wc.Id))
+                .Where(wc => wc.UserId == userId);
+
+            foreach (var wc in validUserWebauthnCredentials)
+            {
+                var nwc = newCreds.First(eak => eak.Id == wc.Id);
+                wc.EncryptedPublicKey = nwc.EncryptedPublicKey;
+                wc.EncryptedUserKey = nwc.EncryptedUserKey;
+            }
+
+            await dbContext.SaveChangesAsync();
+        };
+    }
+
 }
diff --git a/test/Api.Test/Auth/Controllers/AccountsControllerTests.cs b/test/Api.Test/Auth/Controllers/AccountsControllerTests.cs
index 9b6566bf64..1dd8fe064d 100644
--- a/test/Api.Test/Auth/Controllers/AccountsControllerTests.cs
+++ b/test/Api.Test/Auth/Controllers/AccountsControllerTests.cs
@@ -3,6 +3,7 @@ using Bit.Api.AdminConsole.Models.Request.Organizations;
 using Bit.Api.Auth.Controllers;
 using Bit.Api.Auth.Models.Request;
 using Bit.Api.Auth.Models.Request.Accounts;
+using Bit.Api.Auth.Models.Request.WebAuthn;
 using Bit.Api.Auth.Validators;
 using Bit.Api.Tools.Models.Request;
 using Bit.Api.Vault.Models.Request;
@@ -11,6 +12,7 @@ using Bit.Core.AdminConsole.Repositories;
 using Bit.Core.AdminConsole.Services;
 using Bit.Core.Auth.Entities;
 using Bit.Core.Auth.Models.Api.Request.Accounts;
+using Bit.Core.Auth.Models.Data;
 using Bit.Core.Auth.Services;
 using Bit.Core.Auth.UserFeatures.UserKey;
 using Bit.Core.Auth.UserFeatures.UserMasterPassword.Interfaces;
@@ -67,6 +69,8 @@ public class AccountsControllerTests : IDisposable
     private readonly IRotationValidator<IEnumerable<ResetPasswordWithOrgIdRequestModel>,
             IReadOnlyList<OrganizationUser>>
         _resetPasswordValidator;
+    private readonly IRotationValidator<IEnumerable<WebAuthnLoginRotateKeyRequestModel>, IEnumerable<WebAuthnLoginRotateKeyData>>
+        _webauthnKeyRotationValidator;
 
 
     public AccountsControllerTests()
@@ -97,6 +101,7 @@ public class AccountsControllerTests : IDisposable
         _sendValidator = Substitute.For<IRotationValidator<IEnumerable<SendWithIdRequestModel>, IReadOnlyList<Send>>>();
         _emergencyAccessValidator = Substitute.For<IRotationValidator<IEnumerable<EmergencyAccessWithIdRequestModel>,
             IEnumerable<EmergencyAccess>>>();
+        _webauthnKeyRotationValidator = Substitute.For<IRotationValidator<IEnumerable<WebAuthnLoginRotateKeyRequestModel>, IEnumerable<WebAuthnLoginRotateKeyData>>>();
         _resetPasswordValidator = Substitute
             .For<IRotationValidator<IEnumerable<ResetPasswordWithOrgIdRequestModel>,
                 IReadOnlyList<OrganizationUser>>>();
@@ -125,7 +130,8 @@ public class AccountsControllerTests : IDisposable
             _folderValidator,
             _sendValidator,
             _emergencyAccessValidator,
-            _resetPasswordValidator
+            _resetPasswordValidator,
+            _webauthnKeyRotationValidator
         );
     }
 
diff --git a/test/Api.Test/Auth/Controllers/WebAuthnControllerTests.cs b/test/Api.Test/Auth/Controllers/WebAuthnControllerTests.cs
index 85b0b9cab7..702fc7764a 100644
--- a/test/Api.Test/Auth/Controllers/WebAuthnControllerTests.cs
+++ b/test/Api.Test/Auth/Controllers/WebAuthnControllerTests.cs
@@ -1,6 +1,6 @@
 using Bit.Api.Auth.Controllers;
 using Bit.Api.Auth.Models.Request.Accounts;
-using Bit.Api.Auth.Models.Request.Webauthn;
+using Bit.Api.Auth.Models.Request.WebAuthn;
 using Bit.Core.AdminConsole.Enums;
 using Bit.Core.AdminConsole.Services;
 using Bit.Core.Auth.Entities;
diff --git a/test/Api.Test/Auth/Validators/WebauthnLoginKeyRotationValidatorTests.cs b/test/Api.Test/Auth/Validators/WebauthnLoginKeyRotationValidatorTests.cs
new file mode 100644
index 0000000000..97eadcbdc3
--- /dev/null
+++ b/test/Api.Test/Auth/Validators/WebauthnLoginKeyRotationValidatorTests.cs
@@ -0,0 +1,93 @@
+using Bit.Api.Auth.Models.Request.WebAuthn;
+using Bit.Api.Auth.Validators;
+using Bit.Core.Auth.Entities;
+using Bit.Core.Auth.Repositories;
+using Bit.Core.Entities;
+using Bit.Core.Exceptions;
+using Bit.Test.Common.AutoFixture;
+using Bit.Test.Common.AutoFixture.Attributes;
+using NSubstitute;
+using Xunit;
+
+namespace Bit.Api.Test.Auth.Validators;
+
+[SutProviderCustomize]
+public class WebAuthnLoginKeyRotationValidatorTests
+{
+    [Theory]
+    [BitAutoData]
+    public async Task ValidateAsync_WrongWebAuthnKeys_Throws(
+        SutProvider<WebAuthnLoginKeyRotationValidator> sutProvider, User user,
+        IEnumerable<WebAuthnLoginRotateKeyRequestModel> webauthnRotateCredentialData)
+    {
+        var webauthnKeysToRotate = webauthnRotateCredentialData.Select(e => new WebAuthnLoginRotateKeyRequestModel
+        {
+            Id = Guid.Parse("00000000-0000-0000-0000-000000000001"),
+            EncryptedPublicKey = e.EncryptedPublicKey,
+            EncryptedUserKey = e.EncryptedUserKey
+        }).ToList();
+
+        var data = new WebAuthnCredential
+        {
+            Id = Guid.Parse("00000000-0000-0000-0000-000000000002"),
+            EncryptedPublicKey = "TestKey",
+            EncryptedUserKey = "Test"
+        };
+        sutProvider.GetDependency<IWebAuthnCredentialRepository>().GetManyByUserIdAsync(user.Id).Returns(new List<WebAuthnCredential> { data });
+
+        await Assert.ThrowsAsync<BadRequestException>(async () =>
+            await sutProvider.Sut.ValidateAsync(user, webauthnKeysToRotate));
+    }
+
+    [Theory]
+    [BitAutoData]
+    public async Task ValidateAsync_NullUserKey_Throws(
+        SutProvider<WebAuthnLoginKeyRotationValidator> sutProvider, User user,
+        IEnumerable<WebAuthnLoginRotateKeyRequestModel> webauthnRotateCredentialData)
+    {
+        var guid = Guid.NewGuid();
+        var webauthnKeysToRotate = webauthnRotateCredentialData.Select(e => new WebAuthnLoginRotateKeyRequestModel
+        {
+            Id = guid,
+            EncryptedPublicKey = e.EncryptedPublicKey,
+        }).ToList();
+
+        var data = new WebAuthnCredential
+        {
+            Id = guid,
+            EncryptedPublicKey = "TestKey",
+            EncryptedUserKey = "Test"
+        };
+        sutProvider.GetDependency<IWebAuthnCredentialRepository>().GetManyByUserIdAsync(user.Id).Returns(new List<WebAuthnCredential> { data });
+
+        await Assert.ThrowsAsync<BadRequestException>(async () =>
+            await sutProvider.Sut.ValidateAsync(user, webauthnKeysToRotate));
+    }
+
+
+    [Theory]
+    [BitAutoData]
+    public async Task ValidateAsync_NullPublicKey_Throws(
+        SutProvider<WebAuthnLoginKeyRotationValidator> sutProvider, User user,
+        IEnumerable<WebAuthnLoginRotateKeyRequestModel> webauthnRotateCredentialData)
+    {
+        var guid = Guid.NewGuid();
+        var webauthnKeysToRotate = webauthnRotateCredentialData.Select(e => new WebAuthnLoginRotateKeyRequestModel
+        {
+            Id = guid,
+            EncryptedUserKey = e.EncryptedUserKey,
+        }).ToList();
+
+        var data = new WebAuthnCredential
+        {
+            Id = guid,
+            EncryptedPublicKey = "TestKey",
+            EncryptedUserKey = "Test"
+        };
+        sutProvider.GetDependency<IWebAuthnCredentialRepository>().GetManyByUserIdAsync(user.Id).Returns(new List<WebAuthnCredential> { data });
+
+        await Assert.ThrowsAsync<BadRequestException>(async () =>
+            await sutProvider.Sut.ValidateAsync(user, webauthnKeysToRotate));
+    }
+
+}
diff --git a/test/Core.Test/Auth/UserFeatures/UserKey/RotateUserKeyCommandTests.cs b/test/Core.Test/Auth/UserFeatures/UserKey/RotateUserKeyCommandTests.cs
index f97e55a674..41c78f4272 100644
--- a/test/Core.Test/Auth/UserFeatures/UserKey/RotateUserKeyCommandTests.cs
+++ b/test/Core.Test/Auth/UserFeatures/UserKey/RotateUserKeyCommandTests.cs
@@ -1,4 +1,6 @@
-using Bit.Core.Auth.Models.Data;
+using Bit.Core.Auth.Entities;
+using Bit.Core.Auth.Models.Data;
+using Bit.Core.Auth.Repositories;
 using Bit.Core.Auth.UserFeatures.UserKey.Implementations;
 using Bit.Core.Entities;
 using Bit.Core.Services;
@@ -19,6 +21,16 @@ public class RotateUserKeyCommandTests
     {
         sutProvider.GetDependency<IUserService>().CheckPasswordAsync(user, model.MasterPasswordHash)
             .Returns(true);
+        foreach (var webauthnCred in model.WebAuthnKeys)
+        {
+            var dbWebauthnCred = new WebAuthnCredential
+            {
+                EncryptedPublicKey = "encryptedPublicKey",
+                EncryptedUserKey = "encryptedUserKey"
+            };
+            sutProvider.GetDependency<IWebAuthnCredentialRepository>().GetByIdAsync(webauthnCred.Id, user.Id)
+                .Returns(dbWebauthnCred);
+        }
 
         var result = await sutProvider.Sut.RotateUserKeyAsync(user, model);
 
@@ -31,6 +43,16 @@ public class RotateUserKeyCommandTests
     {
         sutProvider.GetDependency<IUserService>().CheckPasswordAsync(user, model.MasterPasswordHash)
             .Returns(false);
+        foreach (var webauthnCred in model.WebAuthnKeys)
+        {
+            var dbWebauthnCred = new WebAuthnCredential
+            {
+                EncryptedPublicKey = "encryptedPublicKey",
+                EncryptedUserKey = "encryptedUserKey"
+            };
+            sutProvider.GetDependency<IWebAuthnCredentialRepository>().GetByIdAsync(webauthnCred.Id, user.Id)
+                .Returns(dbWebauthnCred);
+        }
 
         var result = await sutProvider.Sut.RotateUserKeyAsync(user, model);
 
@@ -43,6 +65,16 @@ public class RotateUserKeyCommandTests
     {
         sutProvider.GetDependency<IUserService>().CheckPasswordAsync(user, model.MasterPasswordHash)
             .Returns(true);
+        foreach (var webauthnCred in model.WebAuthnKeys)
+        {
+            var dbWebauthnCred = new WebAuthnCredential
+            {
+                EncryptedPublicKey = "encryptedPublicKey",
+                EncryptedUserKey = "encryptedUserKey"
+            };
+            sutProvider.GetDependency<IWebAuthnCredentialRepository>().GetByIdAsync(webauthnCred.Id, user.Id)
+                .Returns(dbWebauthnCred);
+        }
 
         await sutProvider.Sut.RotateUserKeyAsync(user, model);